/* Forward function declarations. */
static arm_stack_offsets *arm_get_frame_offsets (void);
static void arm_add_gc_roots (void);
-static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
- rtx, rtx, int, int);
+static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
+ HOST_WIDE_INT, rtx, rtx, int, int);
static unsigned bit_count (unsigned long);
static int arm_address_register_rtx_p (rtx, int);
static int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int);
static rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
static rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static void emit_constant_insn (rtx cond, rtx pattern);
#ifdef OBJECT_FORMAT_ELF
static void arm_elf_asm_named_section (const char *, unsigned int);
Return value is the number of insns emitted. */
int
-arm_split_constant (enum rtx_code code, enum machine_mode mode,
+arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
{
+ rtx cond;
+
+ if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
+ cond = COND_EXEC_TEST (PATTERN (insn));
+ else
+ cond = NULL_RTX;
+
if (subtargets || code == SET
|| (GET_CODE (target) == REG && GET_CODE (source) == REG
&& REGNO (target) != REGNO (source)))
Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
*/
if (!after_arm_reorg
- && (arm_gen_constant (code, mode, val, target, source, 1, 0)
+ && !cond
+ && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
+ 1, 0)
> arm_constant_limit + (code != SET)))
{
if (code == SET)
}
}
- return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
+ return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
+ 1);
}
static int
return num_insns;
}
+/* Emit an instruction with the indicated PATTERN. If COND is
+ non-NULL, conditionalize the execution of the instruction on COND
+ being true. */
+
+static void
+emit_constant_insn (rtx cond, rtx pattern)
+{
+ if (cond)
+ pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
+ emit_insn (pattern);
+}
+
/* As above, but extra parameter GENERATE which, if clear, suppresses
RTL generation. */
static int
-arm_gen_constant (enum rtx_code code, enum machine_mode mode,
+arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
int generate)
{
if (remainder == 0xffffffff)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- GEN_INT (ARM_SIGN_EXTEND (val))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ GEN_INT (ARM_SIGN_EXTEND (val))));
return 1;
}
if (remainder == 0)
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
break;
if (remainder == 0)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, const0_rtx));
return 1;
}
if (remainder == 0xffffffff)
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
can_invert = 1;
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
if (remainder == 0xffffffff)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode, source)));
return 1;
}
if (remainder == 0)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NEG (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NEG (mode, source)));
return 1;
}
if (const_ok_for_arm (val))
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_MINUS (mode, GEN_INT (val),
- source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_MINUS (mode, GEN_INT (val),
+ source)));
return 1;
}
can_negate = 1;
|| (can_invert && const_ok_for_arm (~val)))
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- (source ? gen_rtx_fmt_ee (code, mode, source,
- GEN_INT (val))
- : GEN_INT (val))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ (source
+ ? gen_rtx_fmt_ee (code, mode, source,
+ GEN_INT (val))
+ : GEN_INT (val))));
return 1;
}
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, new_src,
- GEN_INT (temp1)));
- emit_insn (gen_ashrsi3 (target, new_src,
- GEN_INT (set_sign_bit_copies - 1)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ GEN_INT (temp1)));
+ emit_constant_insn (cond,
+ gen_ashrsi3 (target, new_src,
+ GEN_INT (set_sign_bit_copies - 1)));
}
return 2;
}
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, new_src,
- GEN_INT (temp1)));
- emit_insn (gen_ashrsi3 (target, new_src,
- GEN_INT (set_sign_bit_copies - 1)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ GEN_INT (temp1)));
+ emit_constant_insn (cond,
+ gen_ashrsi3 (target, new_src,
+ GEN_INT (set_sign_bit_copies - 1)));
}
return 2;
}
rtx new_src = (subtargets
? (generate ? gen_reg_rtx (mode) : NULL_RTX)
: target);
- insns = arm_gen_constant (code, mode, temp2, new_src,
+ insns = arm_gen_constant (code, mode, cond, temp2, new_src,
source, subtargets, generate);
source = new_src;
if (generate)
- emit_insn (gen_rtx_SET
- (VOIDmode, target,
- gen_rtx_IOR (mode,
- gen_rtx_ASHIFT (mode, source,
- GEN_INT (i)),
- source)));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET
+ (VOIDmode, target,
+ gen_rtx_IOR (mode,
+ gen_rtx_ASHIFT (mode, source,
+ GEN_INT (i)),
+ source)));
return insns + 1;
}
}
rtx new_src = (subtargets
? (generate ? gen_reg_rtx (mode) : NULL_RTX)
: target);
- insns = arm_gen_constant (code, mode, temp1, new_src,
+ insns = arm_gen_constant (code, mode, cond, temp1, new_src,
source, subtargets, generate);
source = new_src;
if (generate)
- emit_insn
- (gen_rtx_SET (VOIDmode, target,
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
gen_rtx_IOR
(mode,
gen_rtx_LSHIFTRT (mode, source,
{
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, sub, GEN_INT (val)));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_fmt_ee (code, mode, source, sub)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ GEN_INT (val)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_fmt_ee (code, mode,
+ source, sub)));
}
return 2;
}
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
rtx shift = GEN_INT (set_sign_bit_copies);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode,
- gen_rtx_ASHIFT (mode,
- source,
- shift))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode,
- gen_rtx_LSHIFTRT (mode, sub,
- shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode,
+ gen_rtx_ASHIFT (mode,
+ source,
+ shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode,
+ gen_rtx_LSHIFTRT (mode, sub,
+ shift))));
}
return 2;
}
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
rtx shift = GEN_INT (set_zero_bit_copies);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode,
- gen_rtx_LSHIFTRT (mode,
- source,
- shift))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode,
- gen_rtx_ASHIFT (mode, sub,
- shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode,
+ gen_rtx_LSHIFTRT (mode,
+ source,
+ shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode,
+ gen_rtx_ASHIFT (mode, sub,
+ shift))));
}
return 2;
}
if (generate)
{
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode, source)));
source = sub;
if (subtargets)
sub = gen_reg_rtx (mode);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_AND (mode, source,
- GEN_INT (temp1))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode, sub)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_AND (mode, source,
+ GEN_INT (temp1))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode, sub)));
}
return 3;
}
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
new_src, source, subtargets, 1);
source = new_src;
}
else
{
rtx targ = subtargets ? NULL_RTX : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
targ, source, subtargets, 0);
}
}
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
new_src, source, subtargets, 1);
source = new_src;
}
{
rtx targ = subtargets ? NULL_RTX : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
targ, source, subtargets, 0);
}
}
else
temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
- emit_insn (gen_rtx_SET (VOIDmode, new_src, temp1_rtx));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ temp1_rtx));
source = new_src;
}
"
if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
+ arm_split_constant (PLUS, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
(no_new_pseudos ? 0 : preserve_subexpressions_p ()));
DONE;
}
|| const_ok_for_arm (-INTVAL (operands[2])))"
[(clobber (const_int 0))]
"
- arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
+ arm_split_constant (PLUS, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0],
operands[1], 0);
DONE;
"
{
if (TARGET_ARM)
{
- arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
+ arm_split_constant (MINUS, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0],
operands[2],
(no_new_pseudos ? 0
: preserve_subexpressions_p ()));
&& !const_ok_for_arm (INTVAL (operands[1]))"
[(clobber (const_int 0))]
"
- arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
- operands[2], 0);
+ arm_split_constant (MINUS, SImode, curr_insn,
+ INTVAL (operands[1]), operands[0], operands[2], 0);
DONE;
"
[(set_attr "length" "4,16")
{
if (GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
+ arm_split_constant (AND, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0],
operands[1],
(no_new_pseudos
? 0 : preserve_subexpressions_p ()));
|| const_ok_for_arm (~INTVAL (operands[2])))"
[(clobber (const_int 0))]
"
- arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
- operands[1], 0);
+ arm_split_constant (AND, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0], operands[1], 0);
DONE;
"
[(set_attr "length" "4,4,16")
{
if (TARGET_ARM)
{
- arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
+ arm_split_constant (IOR, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
(no_new_pseudos
? 0 : preserve_subexpressions_p ()));
DONE;
&& !const_ok_for_arm (INTVAL (operands[2]))"
[(clobber (const_int 0))]
"
- arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
- operands[1], 0);
+ arm_split_constant (IOR, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0], operands[1], 0);
DONE;
"
[(set_attr "length" "4,16")
&& !(const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1]))))
{
- arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
- NULL_RTX,
+ arm_split_constant (SET, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0], NULL_RTX,
(no_new_pseudos ? 0
: preserve_subexpressions_p ()));
DONE;
|| const_ok_for_arm (~INTVAL (operands[1]))))"
[(clobber (const_int 0))]
"
- arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
- NULL_RTX, 0);
+ arm_split_constant (SET, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0], NULL_RTX, 0);
DONE;
"
)
const char *filename;
int lineno;
struct queue_elem *next;
+ /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT, SPLIT
+ points to the generated DEFINE_SPLIT. */
+ struct queue_elem *split;
};
static struct queue_elem *define_attr_queue;
static struct queue_elem *other_queue;
static struct queue_elem **other_tail = &other_queue;
-static void queue_pattern (rtx, struct queue_elem ***,
- const char *, int);
+static struct queue_elem *queue_pattern (rtx, struct queue_elem ***,
+ const char *, int);
/* Current maximum length of directory names in the search path
for include files. (Altered as we get more of them.) */
return rt;
}
\f
-/* Queue PATTERN on LIST_TAIL. */
+/* Queue PATTERN on LIST_TAIL. Return the address of the new queue
+ element. */
-static void
+static struct queue_elem *
queue_pattern (rtx pattern, struct queue_elem ***list_tail,
const char *filename, int lineno)
{
e->filename = filename;
e->lineno = lineno;
e->next = NULL;
+ e->split = NULL;
**list_tail = e;
*list_tail = &e->next;
+ return e;
}
/* Recursively remove constraints from an rtx. */
rtx split;
rtvec attr;
int i;
+ struct queue_elem *insn_elem;
+ struct queue_elem *split_elem;
/* Create a split with values from the insn_and_split. */
split = rtx_alloc (DEFINE_SPLIT);
XVEC (desc, 4) = attr;
/* Queue them. */
- queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno);
- queue_pattern (split, &other_tail, read_rtx_filename, lineno);
+ insn_elem
+ = queue_pattern (desc, &define_insn_tail, read_rtx_filename,
+ lineno);
+ split_elem
+ = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
+ insn_elem->split = split_elem;
break;
}
for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
{
int alternatives, max_operand;
- rtx pred, insn, pattern;
+ rtx pred, insn, pattern, split;
+ int i;
if (! is_predicable (insn_elem))
continue;
queue_pattern (insn, &other_tail, insn_elem->filename,
insn_elem->lineno);
+
+ if (!insn_elem->split)
+ continue;
+
+ /* If the original insn came from a define_insn_and_split,
+ generate a new split to handle the predicated insn. */
+ split = copy_rtx (insn_elem->split->data);
+ /* Predicate the pattern matched by the split. */
+ pattern = rtx_alloc (COND_EXEC);
+ XEXP (pattern, 0) = pred;
+ if (XVECLEN (split, 0) == 1)
+ {
+ XEXP (pattern, 1) = XVECEXP (split, 0, 0);
+ XVECEXP (split, 0, 0) = pattern;
+ PUT_NUM_ELEM (XVEC (split, 0), 1);
+ }
+ else
+ {
+ XEXP (pattern, 1) = rtx_alloc (PARALLEL);
+ XVEC (XEXP (pattern, 1), 0) = XVEC (split, 0);
+ XVEC (split, 0) = rtvec_alloc (1);
+ XVECEXP (split, 0, 0) = pattern;
+ }
+ /* Predicate all of the insns generated by the split. */
+ for (i = 0; i < XVECLEN (split, 2); i++)
+ {
+ pattern = rtx_alloc (COND_EXEC);
+ XEXP (pattern, 0) = pred;
+ XEXP (pattern, 1) = XVECEXP (split, 2, i);
+ XVECEXP (split, 2, i) = pattern;
+ }
+ /* Add the new split to the queue. */
+ queue_pattern (split, &other_tail, read_rtx_filename,
+ insn_elem->split->lineno);
}
}