+2001-01-22 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
+
+ * c4x.c (c4x_check_legit_addr): Only check CONST. Not if CONST
+ contains SYMBOL_REF, LABEL_REF and CONST_INT.
+ (c4x_U_constraint, symbolic_address_operand): Likewise.
+ (c4x_immed_float_constant): Do not check if CONST_DOUBLE is in
+ memory.
+ (c4x_r11_set_p, c4x_check_laj_p): New functions.
+ * c4x-protos.h (c4x_check_laj_p): Add prototype.
+ * c4x.md (in_annul_slot_3): Do not allow auto-increment in last
+ anulling slot because of silicon bug.
+ (laj, lajv): Call c4x_check_laj_p to check for silicon bug.
+
2001-01-22 Alan Modra <alan@linuxcare.com.au>
* cppexp.c (parse_charconst): Change `mask' type to agree
static int c4x_arn_mem_operand PARAMS ((rtx, enum machine_mode, unsigned int));
static void c4x_check_attribute PARAMS ((const char *, tree, tree, tree *));
static int c4x_parse_pragma PARAMS ((const char *, tree *, tree *));
+static int c4x_r11_set_p PARAMS ((rtx));
/* Called to register all of our global variables with the garbage
collector. */
return 1;
if (GET_CODE (op1) == CONST)
- {
- addr = XEXP (op1, 0);
-
- if (GET_CODE (addr) == PLUS
- && (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (addr, 0)) == LABEL_REF)
- && GET_CODE (XEXP (addr, 1)) == CONST_INT)
- return 1;
- }
+ return 1;
return 0;
}
break;
if (GET_CODE (op) != CONST_DOUBLE)
return 0;
- if (GET_CODE (XEXP (op, 0)) == MEM)
- return 0;
+ /* Do not check if the CONST_DOUBLE is in memory. If there is a MEM
+ present this only means that a MEM rtx has been generated. It does
+ not mean the rtx is really in memory. */
return GET_MODE (op) == QFmode || GET_MODE (op) == HFmode;
}
rtx op;
{
/* Don't allow direct addressing to an arbitrary constant. */
- if (GET_CODE (op) == CONST
- && GET_CODE (XEXP (op, 0)) == PLUS
- && (GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
- || GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF)
- && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
- return 1;
-
- return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
+ return GET_CODE (op) == CONST
+ || GET_CODE (op) == SYMBOL_REF
+ || GET_CODE (op) == LABEL_REF;
}
{
switch (GET_CODE (op))
{
+ case CONST:
case SYMBOL_REF:
case LABEL_REF:
return 1;
- case CONST:
- op = XEXP (op, 0);
- return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (op, 0)) == LABEL_REF)
- && GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
+/* Check if register r11 is used as the destination of an insn. */
+
+static int
+c4x_r11_set_p(x)
+ rtx x;
+{
+ RTX_CODE code;
+ rtx set;
+ int i, j;
+ const char *fmt;
+
+ if (x == 0)
+ return 0;
+
+ code = GET_CODE (x);
+ if (code == INSN && GET_CODE (PATTERN (x)) == SEQUENCE)
+ x = XVECEXP (PATTERN (x), 0, XVECLEN (PATTERN (x), 0) - 1);
+
+ if (code == INSN && (set = single_set (x)))
+ return c4x_r11_set_p (SET_DEST (set));
+
+ if (code == REG && REGNO (x) == R11_REGNO)
+ return 1;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (c4x_r11_set_p (XEXP (x, i)))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (c4x_r11_set_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ return 0;
+}
+
+
+/* The c4x sometimes has a problem when the insn before the laj insn
+ sets the r11 register. Check for this situation. */
+
+int
+c4x_check_laj_p (insn)
+ rtx insn;
+{
+ insn = prev_nonnote_insn (insn);
+
+ /* If this is the start of the function no nop is needed. */
+ if (insn == 0)
+ return 0;
+
+ /* If the previous insn is a code label we have to insert a nop. This
+ could be a jump or table jump. We can find the normal jumps by
+ scanning the function but this will not find table jumps. */
+ if (GET_CODE (insn) == CODE_LABEL)
+ return 1;
+
+ /* If the previous insn sets register r11 we have to insert a nop. */
+ if (c4x_r11_set_p (insn))
+ return 1;
+
+ /* No nop needed. */
+ return 0;
+}
+
+
/* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost.
A set of an address register followed by a use occurs a 2 cycle
(const_string "false")))
/* Disable ldp because the c4x contains a bug. The ldp insn modifies
- the dp register when the insn is anulled or not. */
+ the dp register when the insn is anulled or not.
+ Also disable autoincrement insns because of a silicon bug. */
(define_attr "in_annul_slot_3" "false,true"
- (if_then_else (and (eq_attr "cpu" "c4x")
- (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,push,pop,ldp,multi"))
+ (if_then_else (and (and (eq_attr "cpu" "c4x")
+ (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,push,pop,ldp,multi"))
+ (eq_attr "onlyreg_nomod" "true"))
(const_string "true")
(const_string "false")))
"! TARGET_C3X"
"*
if (final_sequence)
- return \"laj%U0\\t%C0\";
+ return c4x_check_laj_p (insn)
+ ? \"nop\\n\\tlaj%U0\\t%C0\" : \"laj%U0\\t%C0\";
else
return \"call%U0\\t%C0\";"
[(set_attr "type" "laj")])
"! TARGET_C3X"
"*
if (final_sequence)
- return \"laj%U1\\t%C1\";
+ return c4x_check_laj_p (insn)
+ ? \"nop\\n\\tlaj%U1\\t%C1\" : \"laj%U1\\t%C1\";
else
return \"call%U1\\t%C1\";"
[(set_attr "type" "laj")])