arm-modes.def (CC_Nmode): New condition code mode.

* arm-modes.def (CC_Nmode): New condition code mode.
* arm.c (thumb_condition_code): Delete.
(arm_select_cc_mode): Handle single-bit test for Thumb.
(arm_print_operand, cases 'd' and 'D'): Don't special case the
condition code logic for Thumb.
(get_arm_condition_code): Handle CC_Nmode.
(thumb_cbrch_target_operand): New function.
* arm.h (PREDICATE_CODES): Add thumb_cbrch_target_operand.
* arm-protos.h (thumb_cbrch_target_operand): Add prototype.
* arm.md: Add Thumb split patterns for zero_extract and
sign_extract.
(tbit_cbranch, andsi3_cbranch_scratch, andsi3_cbranch)
(orrsi3_cbranch_scratch, orrsi3_cbranch, xorsi3_cbranch_scratch)
(xorsi3_cbranch, addsi3_cbranch, addsi3_cbranch_scratch)
(subsi3_cbranch, subsi3_cbranch_scratch): New Thumb patterns.
(cbranchne_decr1): Re-work to use CC_Nmode.

* arm.c (thumb_expand_epilogue): Add clobbers of registers restored
by the return instruction.  Add a use of the link register if it
wasn't stored.

From-SVN: r72595
This commit is contained in:
Richard Earnshaw 2003-10-17 10:58:17 +00:00 committed by Richard Earnshaw
parent 38b2a60531
commit defc0463c4
6 changed files with 737 additions and 44 deletions

View file

@ -1,3 +1,26 @@
2003-10-17 Richard Earnshaw <rearnsha@arm.com>
* arm-modes.def (CC_Nmode): New condition code mode.
* arm.c (thumb_condition_code): Delete.
(arm_select_cc_mode): Handle single-bit test for Thumb.
(arm_print_operand, cases 'd' and 'D'): Don't special case the
condition code logic for Thumb.
(get_arm_condition_code): Handle CC_Nmode.
(thumb_cbrch_target_operand): New function.
* arm.h (PREDICATE_CODES): Add thumb_cbrch_target_operand.
* arm-protos.h (thumb_cbrch_target_operand): Add prototype.
* arm.md: Add Thumb split patterns for zero_extract and
sign_extract.
(tbit_cbranch, andsi3_cbranch_scratch, andsi3_cbranch)
(orrsi3_cbranch_scratch, orrsi3_cbranch, xorsi3_cbranch_scratch)
(xorsi3_cbranch, addsi3_cbranch, addsi3_cbranch_scratch)
(subsi3_cbranch, subsi3_cbranch_scratch): New Thumb patterns.
(cbranchne_decr1): Re-work to use CC_Nmode.
* arm.c (thumb_expand_epilogue): Add clobbers of registers restored
by the return instruction. Add a use of the link register if it
wasn't stored.
2003-10-17 Richard Earnshaw <rearnsha@arm.com>
* flow.c (init_propagate_block_info): Don't abort if a conditional

View file

@ -30,6 +30,7 @@ FLOAT_MODE (XF, 12, 0);
CCFPmode should be used with floating equalities.
CC_NOOVmode should be used with SImode integer equalities.
CC_Zmode should be used if only the Z flag is set correctly
CC_Nmode should be used if only the N (sign) flag is set correctly
CCmode should be used otherwise. */
CC_MODE (CC_NOOV);
@ -48,3 +49,4 @@ CC_MODE (CC_DLTU);
CC_MODE (CC_DGEU);
CC_MODE (CC_DGTU);
CC_MODE (CC_C);
CC_MODE (CC_N);

View file

@ -178,6 +178,7 @@ extern const char *thumb_load_double_from_address (rtx *);
extern const char *thumb_output_move_mem_multiple (int, rtx *);
extern void thumb_expand_movstrqi (rtx *);
extern int thumb_cmp_operand (rtx, enum machine_mode);
extern int thumb_cbrch_target_operand (rtx, enum machine_mode);
extern rtx *thumb_legitimize_pic_address (rtx, enum machine_mode, rtx);
extern int thumb_go_if_legitimate_address (enum machine_mode, rtx);
extern rtx arm_return_addr (int, rtx);

View file

@ -86,7 +86,6 @@ static int number_of_first_bit_set (int);
static void replace_symbols_in_block (tree, rtx, rtx);
static void thumb_exit (FILE *, int, rtx);
static void thumb_pushpop (FILE *, int, int);
static const char *thumb_condition_code (rtx, int);
static rtx is_jump_table (rtx);
static HOST_WIDE_INT get_jump_table_size (rtx);
static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
@ -5575,10 +5574,19 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
DOM_CC_X_OR_Y);
/* An operation (on Thumb) where we want to test for a single bit.
This is done by shifting that bit up into the top bit of a
scratch register; we can then branch on the sign bit. */
if (TARGET_THUMB
&& GET_MODE (x) == SImode
&& (op == EQ || op == NE)
&& (GET_CODE (x) == ZERO_EXTRACT))
return CC_Nmode;
/* An operation that sets the condition codes as a side-effect, the
V flag is not set correctly, so we can only use comparisons where
this doesn't matter. (For LT and GE we can use "mi" and "pl"
instead. */
instead.) */
if (GET_MODE (x) == SImode
&& y == const0_rtx
&& (op == EQ || op == NE || op == LT || op == GE)
@ -5588,7 +5596,8 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
|| GET_CODE (x) == NOT || GET_CODE (x) == NEG
|| GET_CODE (x) == LSHIFTRT
|| GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
|| GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT))
|| GET_CODE (x) == ROTATERT
|| (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
return CC_NOOVmode;
if (GET_MODE (x) == QImode && (op == EQ || op == NE))
@ -9557,11 +9566,8 @@ arm_print_operand (FILE *stream, rtx x, int code)
if (x == const_true_rtx)
return;
if (TARGET_ARM)
fputs (arm_condition_codes[get_arm_condition_code (x)],
stream);
else
fputs (thumb_condition_code (x, 0), stream);
fputs (arm_condition_codes[get_arm_condition_code (x)],
stream);
return;
case 'D':
@ -9570,12 +9576,9 @@ arm_print_operand (FILE *stream, rtx x, int code)
if (x == const_true_rtx)
abort ();
if (TARGET_ARM)
fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
(get_arm_condition_code (x))],
stream);
else
fputs (thumb_condition_code (x, 1), stream);
fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
(get_arm_condition_code (x))],
stream);
return;
/* Cirrus registers can be accessed in a variety of ways:
@ -9815,6 +9818,14 @@ get_arm_condition_code (rtx comparison)
default: abort ();
}
case CC_Nmode:
switch (comp_code)
{
case NE: return ARM_MI;
case EQ: return ARM_PL;
default: abort ();
}
case CCFPEmode:
case CCFPmode:
/* These encodings assume that AC=1 in the FPA system control
@ -12083,7 +12094,8 @@ thumb_expand_epilogue (void)
{
HOST_WIDE_INT amount = (thumb_get_frame_size ()
+ current_function_outgoing_args_size);
int regno;
/* Naked functions don't have prologues. */
if (IS_NAKED (arm_current_func_type ()))
return;
@ -12113,6 +12125,15 @@ thumb_expand_epilogue (void)
if (current_function_profile || TARGET_NO_SCHED_PRO)
emit_insn (gen_blockage ());
/* Emit a clobber for each insn that will be restored in the epilogue,
so that flow2 will get register lifetimes correct. */
for (regno = 0; regno < 13; regno++)
if (regs_ever_live[regno] && !call_used_regs[regno])
emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
if (! regs_ever_live[LR_REGNUM])
emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
}
static void
@ -12571,36 +12592,25 @@ thumb_cmp_operand (rtx op, enum machine_mode mode)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256)
|| register_operand (op, mode));
|| s_register_operand (op, mode));
}
static const char *
thumb_condition_code (rtx x, int invert)
/* Return TRUE if a result can be stored in OP without clobbering the
condition code register. Prior to reload we only accept a
register. After reload we have to be able to handle memory as
well, since a pseudo may not get a hard reg and reload cannot
handle output-reloads on jump insns.
We could possibly handle mem before reload as well, but that might
complicate things with the need to handle increment
side-effects. */
int
thumb_cbrch_target_operand (rtx op, enum machine_mode mode)
{
static const char * const conds[] =
{
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le"
};
int val;
switch (GET_CODE (x))
{
case EQ: val = 0; break;
case NE: val = 1; break;
case GEU: val = 2; break;
case LTU: val = 3; break;
case GTU: val = 8; break;
case LEU: val = 9; break;
case GE: val = 10; break;
case LT: val = 11; break;
case GT: val = 12; break;
case LE: val = 13; break;
default:
abort ();
}
return conds[val ^ invert];
return (s_register_operand (op, mode)
|| ((reload_in_progress || reload_completed)
&& memory_operand (op, mode)));
}
/* Handle storing a half-word to memory during reload. */

View file

@ -2689,6 +2689,7 @@ extern int making_const_table;
{"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \
{"index_operand", {SUBREG, REG, CONST_INT}}, \
{"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, \
{"thumb_cbrch_target_operand", {SUBREG, REG, MEM}}, \
{"offsettable_memory_operand", {MEM}}, \
{"bad_signed_byte_operand", {MEM}}, \
{"alignable_memory_operand", {MEM}}, \

View file

@ -1721,6 +1721,39 @@
(set_attr "length" "8")]
)
(define_split
[(set (match_operand:SI 0 "s_register_operand" "")
(zero_extract:SI (match_operand:SI 1 "s_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")
(match_operand:SI 3 "const_int_operand" "")))
(clobber (match_operand:SI 4 "s_register_operand" ""))]
"TARGET_THUMB"
[(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2)))
(set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))]
"{
HOST_WIDE_INT temp = INTVAL (operands[2]);
operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
operands[3] = GEN_INT (32 - temp);
}"
)
(define_split
[(set (match_operand:SI 0 "s_register_operand" "")
(sign_extract:SI (match_operand:SI 1 "s_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")
(match_operand:SI 3 "const_int_operand" "")))]
"TARGET_THUMB"
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))]
"{
HOST_WIDE_INT temp = INTVAL (operands[2]);
operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
operands[3] = GEN_INT (32 - temp);
}"
)
;;; ??? This pattern is bogus. If operand3 has bits outside the range
;;; represented by the bitfield, then this will produce incorrect results.
;;; Somewhere, the value needs to be truncated. On targets like the m68k,
@ -5246,6 +5279,365 @@
(const_int 8))))]
)
(define_insn "*tbit_cbranch"
[(set (pc)
(if_then_else
(match_operator 0 "equality_operator"
[(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
(const_int 1)
(match_operand:SI 2 "const_int_operand" "i"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (match_scratch:SI 4 "=l"))]
"TARGET_THUMB"
"*
{
rtx op[3];
op[0] = operands[4];
op[1] = operands[1];
op[2] = GEN_INT (32 - 1 - INTVAL (operands[2]));
output_asm_insn (\"lsl\\t%0, %1, %2\", op);
switch (get_attr_length (insn))
{
case 4: return \"b%d0\\t%l3\";
case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -2040))
(le (minus (match_dup 3) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
(define_insn "*andsi3_cbranch_scratch"
[(set (pc)
(if_then_else
(match_operator 4 "equality_operator"
[(and:SI (match_operand:SI 1 "s_register_operand" "%0")
(match_operand:SI 2 "s_register_operand" "l"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (match_scratch:SI 0 "=l"))]
"TARGET_THUMB"
"*
{
output_asm_insn (\"and\\t%0, %2\", operands);
switch (get_attr_length (insn))
{
case 4: return \"b%d4\\t%l3\";
case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -2040))
(le (minus (match_dup 3) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
(define_insn "*andsi3_cbranch"
[(set (pc)
(if_then_else
(match_operator 5 "equality_operator"
[(and:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
(match_operand:SI 3 "s_register_operand" "l,l,l,l"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,?h,?m,?m")
(and:SI (match_dup 2) (match_dup 3)))
(clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
"TARGET_THUMB"
"*
{
if (which_alternative == 0)
output_asm_insn (\"and\\t%0, %3\", operands);
else if (which_alternative == 1)
{
output_asm_insn (\"and\\t%1, %3\", operands);
output_asm_insn (\"mov\\t%0, %1\", operands);
}
else
{
output_asm_insn (\"and\\t%1, %3\", operands);
output_asm_insn (\"str\\t%1, %0\", operands);
}
switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
{
case 4: return \"b%d5\\t%l4\";
case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(ior (and (eq (symbol_ref ("which_alternative"))
(const_int 0))
(eq_attr "length" "8"))
(eq_attr "length" "10"))
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(eq (symbol_ref ("which_alternative"))
(const_int 0))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -250))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2040))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8)))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -248))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 6)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2038))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 8)
(const_int 10)))))]
)
(define_insn "*orrsi3_cbranch_scratch"
[(set (pc)
(if_then_else
(match_operator 4 "equality_operator"
[(ior:SI (match_operand:SI 1 "s_register_operand" "%0")
(match_operand:SI 2 "s_register_operand" "l"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (match_scratch:SI 0 "=l"))]
"TARGET_THUMB"
"*
{
output_asm_insn (\"orr\\t%0, %2\", operands);
switch (get_attr_length (insn))
{
case 4: return \"b%d4\\t%l3\";
case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -2040))
(le (minus (match_dup 3) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
(define_insn "*orrsi3_cbranch"
[(set (pc)
(if_then_else
(match_operator 5 "equality_operator"
[(ior:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
(match_operand:SI 3 "s_register_operand" "l,l,l,l"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,?h,?m,?m")
(ior:SI (match_dup 2) (match_dup 3)))
(clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
"TARGET_THUMB"
"*
{
if (which_alternative == 0)
output_asm_insn (\"orr\\t%0, %3\", operands);
else if (which_alternative == 1)
{
output_asm_insn (\"orr\\t%1, %3\", operands);
output_asm_insn (\"mov\\t%0, %1\", operands);
}
else
{
output_asm_insn (\"orr\\t%1, %3\", operands);
output_asm_insn (\"str\\t%1, %0\", operands);
}
switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
{
case 4: return \"b%d5\\t%l4\";
case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(ior (and (eq (symbol_ref ("which_alternative"))
(const_int 0))
(eq_attr "length" "8"))
(eq_attr "length" "10"))
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(eq (symbol_ref ("which_alternative"))
(const_int 0))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -250))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2040))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8)))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -248))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 6)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2038))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 8)
(const_int 10)))))]
)
(define_insn "*xorsi3_cbranch_scratch"
[(set (pc)
(if_then_else
(match_operator 4 "equality_operator"
[(xor:SI (match_operand:SI 1 "s_register_operand" "%0")
(match_operand:SI 2 "s_register_operand" "l"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (match_scratch:SI 0 "=l"))]
"TARGET_THUMB"
"*
{
output_asm_insn (\"eor\\t%0, %2\", operands);
switch (get_attr_length (insn))
{
case 4: return \"b%d4\\t%l3\";
case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -2040))
(le (minus (match_dup 3) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
(define_insn "*xorsi3_cbranch"
[(set (pc)
(if_then_else
(match_operator 5 "equality_operator"
[(xor:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
(match_operand:SI 3 "s_register_operand" "l,l,l,l"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,?h,?m,?m")
(xor:SI (match_dup 2) (match_dup 3)))
(clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
"TARGET_THUMB"
"*
{
if (which_alternative == 0)
output_asm_insn (\"eor\\t%0, %3\", operands);
else if (which_alternative == 1)
{
output_asm_insn (\"eor\\t%1, %3\", operands);
output_asm_insn (\"mov\\t%0, %1\", operands);
}
else
{
output_asm_insn (\"eor\\t%1, %3\", operands);
output_asm_insn (\"str\\t%1, %0\", operands);
}
switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
{
case 4: return \"b%d5\\t%l4\";
case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
}
}"
[(set (attr "far_jump")
(if_then_else
(ior (and (eq (symbol_ref ("which_alternative"))
(const_int 0))
(eq_attr "length" "8"))
(eq_attr "length" "10"))
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(eq (symbol_ref ("which_alternative"))
(const_int 0))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -250))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2040))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8)))
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -248))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 6)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2038))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 8)
(const_int 10)))))]
)
(define_insn "*cbranchne_decr1"
[(set (pc)
(if_then_else (match_operator 3 "equality_operator"
@ -5253,7 +5645,7 @@
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_operand:SI 0 "s_register_operand" "=l,?h,?m,?m")
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,?h,?m,?m")
(plus:SI (match_dup 2) (const_int -1)))
(clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
"TARGET_THUMB"
@ -5262,7 +5654,7 @@
rtx cond[2];
cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
? GEU : LTU),
VOIDmode, NULL, NULL);
VOIDmode, operands[2], const1_rtx);
cond[1] = operands[4];
if (which_alternative == 0)
@ -5349,6 +5741,270 @@
(const_int 10)))])]
)
(define_insn "*addsi3_cbranch"
[(set (pc)
(if_then_else
(match_operator 4 "comparison_operator"
[(plus:SI
(match_operand:SI 2 "s_register_operand" "%l,0,*0,1,1,1")
(match_operand:SI 3 "reg_or_int_operand" "lL,IJ,*r,lIJ,lIJ,lIJ"))
(const_int 0)])
(label_ref (match_operand 5 "" ""))
(pc)))
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,?h,?m,?m")
(plus:SI (match_dup 2) (match_dup 3)))
(clobber (match_scratch:SI 1 "=X,X,X,l,&l,&l"))]
"TARGET_THUMB
&& (GET_CODE (operands[4]) == EQ
|| GET_CODE (operands[4]) == NE
|| GET_CODE (operands[4]) == GE
|| GET_CODE (operands[4]) == LT)"
"*
{
rtx cond[3];
cond[0] = (which_alternative < 3) ? operands[0] : operands[1];
cond[1] = operands[2];
cond[2] = operands[3];
if (GET_CODE (cond[2]) == CONST_INT && INTVAL (cond[2]) < 0)
output_asm_insn (\"sub\\t%0, %1, #%n2\", cond);
else
output_asm_insn (\"add\\t%0, %1, %2\", cond);
if (which_alternative >= 3
&& which_alternative < 4)
output_asm_insn (\"mov\\t%0, %1\", operands);
else if (which_alternative >= 4)
output_asm_insn (\"str\\t%1, %0\", operands);
switch (get_attr_length (insn) - ((which_alternative >= 3) ? 2 : 0))
{
case 4:
return \"b%d4\\t%l5\";
case 6:
return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
default:
return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
}
}
"
[(set (attr "far_jump")
(if_then_else
(ior (and (lt (symbol_ref ("which_alternative"))
(const_int 3))
(eq_attr "length" "8"))
(eq_attr "length" "10"))
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(lt (symbol_ref ("which_alternative"))
(const_int 3))
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -250))
(le (minus (match_dup 5) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -2040))
(le (minus (match_dup 5) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8)))
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -248))
(le (minus (match_dup 5) (pc)) (const_int 256)))
(const_int 6)
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -2038))
(le (minus (match_dup 5) (pc)) (const_int 2048)))
(const_int 8)
(const_int 10)))))]
)
(define_insn "*addsi3_cbranch_scratch"
[(set (pc)
(if_then_else
(match_operator 3 "comparison_operator"
[(plus:SI
(match_operand:SI 1 "s_register_operand" "%l,l,l,0")
(match_operand:SI 2 "reg_or_int_operand" "J,l,I,L"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
(clobber (match_scratch:SI 0 "=X,X,l,l"))]
"TARGET_THUMB
&& (GET_CODE (operands[3]) == EQ
|| GET_CODE (operands[3]) == NE
|| GET_CODE (operands[3]) == GE
|| GET_CODE (operands[3]) == LT)"
"*
{
switch (which_alternative)
{
case 0:
output_asm_insn (\"cmp\t%1, #%n2\", operands);
break;
case 1:
output_asm_insn (\"cmn\t%1, %2\", operands);
break;
case 3:
output_asm_insn (\"add\t%0, %1, %2\", operands);
break;
case 4:
output_asm_insn (\"add\t%0, %0, %2\", operands);
break;
}
switch (get_attr_length (insn))
{
case 4:
return \"b%d3\\t%l4\";
case 6:
return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
default:
return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
}
}
"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -250))
(le (minus (match_dup 4) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 4) (pc)) (const_int -2040))
(le (minus (match_dup 4) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
(define_insn "*subsi3_cbranch"
[(set (pc)
(if_then_else
(match_operator 4 "comparison_operator"
[(minus:SI
(match_operand:SI 2 "s_register_operand" "l,l,1,l")
(match_operand:SI 3 "s_register_operand" "l,l,l,l"))
(const_int 0)])
(label_ref (match_operand 5 "" ""))
(pc)))
(set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,?h,?m,?m")
(minus:SI (match_dup 2) (match_dup 3)))
(clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
"TARGET_THUMB
&& (GET_CODE (operands[4]) == EQ
|| GET_CODE (operands[4]) == NE
|| GET_CODE (operands[4]) == GE
|| GET_CODE (operands[4]) == LT)"
"*
{
if (which_alternative == 0)
output_asm_insn (\"sub\\t%0, %2, %3\", operands);
else if (which_alternative == 1)
{
/* We must provide an alternative for a hi reg because reload
cannot handle output reloads on a jump instruction, but we
can't subtract into that. Fortunately a mov from lo to hi
does not clobber the condition codes. */
output_asm_insn (\"sub\\t%1, %2, %3\", operands);
output_asm_insn (\"mov\\t%0, %1\", operands);
}
else
{
/* Similarly, but the target is memory. */
output_asm_insn (\"sub\\t%1, %2, %3\", operands);
output_asm_insn (\"str\\t%1, %0\", operands);
}
switch (get_attr_length (insn) - ((which_alternative != 0) ? 2 : 0))
{
case 4:
return \"b%d4\\t%l5\";
case 6:
return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
default:
return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
}
}
"
[(set (attr "far_jump")
(if_then_else
(ior (and (eq (symbol_ref ("which_alternative"))
(const_int 0))
(eq_attr "length" "8"))
(eq_attr "length" "10"))
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(eq (symbol_ref ("which_alternative"))
(const_int 0))
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -250))
(le (minus (match_dup 5) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -2040))
(le (minus (match_dup 5) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8)))
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -248))
(le (minus (match_dup 5) (pc)) (const_int 256)))
(const_int 6)
(if_then_else
(and (ge (minus (match_dup 5) (pc)) (const_int -2038))
(le (minus (match_dup 5) (pc)) (const_int 2048)))
(const_int 8)
(const_int 10)))))]
)
(define_insn "*subsi3_cbranch_scratch"
[(set (pc)
(if_then_else
(match_operator 0 "arm_comparison_operator"
[(minus:SI (match_operand:SI 1 "register_operand" "l")
(match_operand:SI 2 "nonmemory_operand" "l"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"TARGET_THUMB
&& (GET_CODE (operands[0]) == EQ
|| GET_CODE (operands[0]) == NE
|| GET_CODE (operands[0]) == GE
|| GET_CODE (operands[0]) == LT)"
"*
output_asm_insn (\"cmp\\t%1, %2\", operands);
switch (get_attr_length (insn))
{
case 4: return \"b%d0\\t%l3\";
case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
}
"
[(set (attr "far_jump")
(if_then_else
(eq_attr "length" "8")
(const_string "yes")
(const_string "no")))
(set (attr "length")
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 256)))
(const_int 4)
(if_then_else
(and (ge (minus (match_dup 3) (pc)) (const_int -2040))
(le (minus (match_dup 3) (pc)) (const_int 2048)))
(const_int 6)
(const_int 8))))]
)
;; Comparison and test insns
(define_expand "cmpsi"