2010-08-29 Chung-Lin Tang Backport from mainline: 2010-04-16 Bernd Schmidt PR target/41514 gcc/ * config/arm/arm.md (cbranchsi4_insn): Renamed from "*cbranchsi4_insn". If the previous insn is a cbranchsi4_insn with the same arguments, omit the compare instruction. gcc/testsuite/ * gcc.target/arm/thumb-comparisons.c: New test. gcc/ * config/arm/arm.md (addsi3_cbranch): If destination is a high register, inputs must be low registers and we need a low register scratch. Handle alternative 2 like alternative 3. PR target/40603 gcc/ * config/arm/arm.md (cbranchqi4): New pattern. * config/arm/predicates.md (const0_operand, cbranchqi4_comparison_operator): New predicates. gcc/testsuite/ * gcc.target/arm/thumb-cbranchqi.c: New test. 2010-04-27 Bernd Schmidt PR target/40657 gcc/ * config/arm/arm.c (thumb1_extra_regs_pushed): New function. (thumb1_expand_prologue, thumb1_output_function_prologue): Call it here to determine which regs to push and how much stack to reserve. gcc/testsuite/ * gcc.target/arm/thumb-stackframe.c: New test. 2010-07-02 Bernd Schmidt PR target/42835 gcc/ * config/arm/arm-modes.def (CC_NOTB): New mode. * config/arm/arm.c (get_arm_condition_code): Handle it. * config/arm/thumb2.md (thumb2_compare_scc): Delete pattern. * config/arm/arm.md (subsi3_compare0_c): New pattern. (compare_scc): Now a define_and_split. Add a number of extra splitters before it. gcc/testsuite/ * gcc.target/arm/pr42835.c: New test. PR target/42172 gcc/ * config/arm/arm.c (thumb1_rtx_costs): Improve support for SIGN_EXTEND and ZERO_EXTEND. (arm_rtx_costs_1): Likewise. (arm_size_rtx_costs): Use arm_rtx_costs_1 for these codes. * config/arm/arm.md (is_arch6): New attribute. (zero_extendhisi2, zero_extendqisi2, extendhisi2, extendqisi2): Tighten the code somewhat, avoiding invalid RTL to occur in the expander patterns. (thumb1_zero_extendhisi2): Merge with thumb1_zero_extendhisi2_v6. (thumb1_zero_extendhisi2_v6): Delete. (thumb1_extendhisi2): Merge with thumb1_extendhisi2_v6. (thumb1_extendhisi2_v6): Delete. (thumb1_extendqisi2): Merge with thumb1_extendhisi2_v6. (thumb1_extendqisi2_v6): Delete. (zero_extendhisi2 for register input splitter): New. (zero_extendqisi2 for register input splitter): New. (thumb1_extendhisi2 for register input splitter): New. (extendhisi2 for register input splitter): New. (extendqisi2 for register input splitter): New. (TARGET_THUMB1 extendqisi2 for memory input splitter): New. (arm_zero_extendhisi2): Allow nonimmediate_operand for operand 1, and add support for a register alternative requiring a split. (thumb1_zero_extendqisi2): Likewise. (arm_zero_extendqisi2): Likewise. (arm_extendhisi2): Likewise. (arm_extendqisi2): Likewise. gcc/testsuite/ * gcc.target/arm/pr42172-1.c: New test. 2010-07-05 Bernd Schmidt * config/arm/arm.c (get_arm_condition_code): Remove CC_NOTBmode case. * arm-modes.def (CC_NOTB): Don't define. * config/arm/arm.md (arm_adddi3): Generate canonical RTL. (adddi_sesidi_di, adddi_zesidi_di): Likewise. (LTUGEU): New code_iterator. (cnb, optab): New corresponding code_attrs. (addsi3_carryin_): Renamed from addsi3_carryin. Change pattern to canonical form. Operands 1 and 2 are commutative. Parametrize using LTUGEU. (addsi3_carryin_shift_): Likewise. (addsi3_carryin_alt2_): Renamed from addsi3_carryin_alt2. Operands 1 and 2 are commutative. Parametrize using LTUGEU. (addsi3_carryin_alt1, addsi3_carryin_alt3): Remove. (subsi3_compare): Renamed from subsi3_compare0_c. Change CC_NOTB to CC. (arm_subsi3_insn): Allow constants for operand 0. (compare_scc peephole for eq case): New. (compare_scc splitters): Change CC_NOTB to CC. 2010-07-09 Bernd Schmidt PR target/40657 gcc/ * config/arm/arm.c (thumb1_extra_regs_pushed): New arg FOR_PROLOGUE. All callers changed. Handle the case when we're called for the epilogue. (thumb_unexpanded_epilogue): Use it. (thumb1_expand_epilogue): Likewise. gcc/testsuite/ * gcc.target/arm/pr40657-1.c: New test. * gcc.target/arm/pr40657-2.c: New test. * gcc.c-torture/execute/pr40657.c: New test. gcc/ * config/arm/arm.md (addsi3_cbranch): Switch alternatives 0 and 1. * config/arm/arm.md (Thumb-1 ldrsb peephole): New. * config/arm/arm.md (cbranchqi4): Fix array size. (addsi3_cbranch): Also andle alternative 2 like alternative 3 when calculating length. 2010-08-27 Paul Brook gcc/ === modified file 'gcc/config/arm/arm-modes.def' --- old/gcc/config/arm/arm-modes.def 2010-07-29 16:58:56 +0000 +++ new/gcc/config/arm/arm-modes.def 2010-08-31 10:00:27 +0000 @@ -34,6 +34,8 @@ 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_Cmode should be used if only the C flag is set correctly, after an + addition. CC_Nmode should be used if only the N (sign) flag is set correctly CC_CZmode should be used if only the C and Z flags are correct (used for DImode unsigned comparisons). === modified file 'gcc/config/arm/arm.c' --- old/gcc/config/arm/arm.c 2010-08-25 16:22:17 +0000 +++ new/gcc/config/arm/arm.c 2010-08-31 10:00:27 +0000 @@ -6443,6 +6443,7 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) { enum machine_mode mode = GET_MODE (x); + int total; switch (code) { @@ -6545,24 +6546,20 @@ return 14; return 2; + case SIGN_EXTEND: case ZERO_EXTEND: - /* XXX still guessing. */ - switch (GET_MODE (XEXP (x, 0))) - { - case QImode: - return (1 + (mode == DImode ? 4 : 0) - + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); - - case HImode: - return (4 + (mode == DImode ? 4 : 0) - + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); - - case SImode: - return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); - - default: - return 99; - } + total = mode == DImode ? COSTS_N_INSNS (1) : 0; + total += thumb1_rtx_costs (XEXP (x, 0), GET_CODE (XEXP (x, 0)), code); + + if (mode == SImode) + return total; + + if (arm_arch6) + return total + COSTS_N_INSNS (1); + + /* Assume a two-shift sequence. Increase the cost slightly so + we prefer actual shifts over an extend operation. */ + return total + 1 + COSTS_N_INSNS (2); default: return 99; @@ -7046,44 +7043,39 @@ return false; case SIGN_EXTEND: - if (GET_MODE_CLASS (mode) == MODE_INT) - { - *total = 0; - if (mode == DImode) - *total += COSTS_N_INSNS (1); - - if (GET_MODE (XEXP (x, 0)) != SImode) - { - if (arm_arch6) - { - if (GET_CODE (XEXP (x, 0)) != MEM) - *total += COSTS_N_INSNS (1); - } - else if (!arm_arch4 || GET_CODE (XEXP (x, 0)) != MEM) - *total += COSTS_N_INSNS (2); - } - - return false; - } - - /* Fall through */ case ZERO_EXTEND: *total = 0; if (GET_MODE_CLASS (mode) == MODE_INT) { + rtx op = XEXP (x, 0); + enum machine_mode opmode = GET_MODE (op); + if (mode == DImode) *total += COSTS_N_INSNS (1); - if (GET_MODE (XEXP (x, 0)) != SImode) + if (opmode != SImode) { - if (arm_arch6) + if (MEM_P (op)) { - if (GET_CODE (XEXP (x, 0)) != MEM) - *total += COSTS_N_INSNS (1); + /* If !arm_arch4, we use one of the extendhisi2_mem + or movhi_bytes patterns for HImode. For a QImode + sign extension, we first zero-extend from memory + and then perform a shift sequence. */ + if (!arm_arch4 && (opmode != QImode || code == SIGN_EXTEND)) + *total += COSTS_N_INSNS (2); } - else if (!arm_arch4 || GET_CODE (XEXP (x, 0)) != MEM) - *total += COSTS_N_INSNS (GET_MODE (XEXP (x, 0)) == QImode ? - 1 : 2); + else if (arm_arch6) + *total += COSTS_N_INSNS (1); + + /* We don't have the necessary insn, so we need to perform some + other operation. */ + else if (TARGET_ARM && code == ZERO_EXTEND && mode == QImode) + /* An and with constant 255. */ + *total += COSTS_N_INSNS (1); + else + /* A shift sequence. Increase costs slightly to avoid + combining two shifts into an extend operation. */ + *total += COSTS_N_INSNS (2) + 1; } return false; @@ -7333,41 +7325,8 @@ return false; case SIGN_EXTEND: - *total = 0; - if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4) - { - if (!(arm_arch4 && MEM_P (XEXP (x, 0)))) - *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2); - } - if (mode == DImode) - *total += COSTS_N_INSNS (1); - return false; - case ZERO_EXTEND: - *total = 0; - if (!(arm_arch4 && MEM_P (XEXP (x, 0)))) - { - switch (GET_MODE (XEXP (x, 0))) - { - case QImode: - *total += COSTS_N_INSNS (1); - break; - - case HImode: - *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2); - - case SImode: - break; - - default: - *total += COSTS_N_INSNS (2); - } - } - - if (mode == DImode) - *total += COSTS_N_INSNS (1); - - return false; + return arm_rtx_costs_1 (x, outer_code, total, 0); case CONST_INT: if (const_ok_for_arm (INTVAL (x))) @@ -16898,11 +16857,11 @@ case CC_Cmode: switch (comp_code) - { - case LTU: return ARM_CS; - case GEU: return ARM_CC; - default: gcc_unreachable (); - } + { + case LTU: return ARM_CS; + case GEU: return ARM_CC; + default: gcc_unreachable (); + } case CC_CZmode: switch (comp_code) @@ -20127,6 +20086,81 @@ #endif } +/* Given the stack offsets and register mask in OFFSETS, decide how + many additional registers to push instead of subtracting a constant + from SP. For epilogues the principle is the same except we use pop. + FOR_PROLOGUE indicates which we're generating. */ +static int +thumb1_extra_regs_pushed (arm_stack_offsets *offsets, bool for_prologue) +{ + HOST_WIDE_INT amount; + unsigned long live_regs_mask = offsets->saved_regs_mask; + /* Extract a mask of the ones we can give to the Thumb's push/pop + instruction. */ + unsigned long l_mask = live_regs_mask & (for_prologue ? 0x40ff : 0xff); + /* Then count how many other high registers will need to be pushed. */ + unsigned long high_regs_pushed = bit_count (live_regs_mask & 0x0f00); + int n_free, reg_base; + + if (!for_prologue && frame_pointer_needed) + amount = offsets->locals_base - offsets->saved_regs; + else + amount = offsets->outgoing_args - offsets->saved_regs; + + /* If the stack frame size is 512 exactly, we can save one load + instruction, which should make this a win even when optimizing + for speed. */ + if (!optimize_size && amount != 512) + return 0; + + /* Can't do this if there are high registers to push. */ + if (high_regs_pushed != 0) + return 0; + + /* Shouldn't do it in the prologue if no registers would normally + be pushed at all. In the epilogue, also allow it if we'll have + a pop insn for the PC. */ + if (l_mask == 0 + && (for_prologue + || TARGET_BACKTRACE + || (live_regs_mask & 1 << LR_REGNUM) == 0 + || TARGET_INTERWORK + || crtl->args.pretend_args_size != 0)) + return 0; + + /* Don't do this if thumb_expand_prologue wants to emit instructions + between the push and the stack frame allocation. */ + if (for_prologue + && ((flag_pic && arm_pic_register != INVALID_REGNUM) + || (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0))) + return 0; + + reg_base = 0; + n_free = 0; + if (!for_prologue) + { + reg_base = arm_size_return_regs () / UNITS_PER_WORD; + live_regs_mask >>= reg_base; + } + + while (reg_base + n_free < 8 && !(live_regs_mask & 1) + && (for_prologue || call_used_regs[reg_base + n_free])) + { + live_regs_mask >>= 1; + n_free++; + } + + if (n_free == 0) + return 0; + gcc_assert (amount / 4 * 4 == amount); + + if (amount >= 512 && (amount - n_free * 4) < 512) + return (amount - 508) / 4; + if (amount <= n_free * 4) + return amount / 4; + return 0; +} + /* The bits which aren't usefully expanded as rtl. */ const char * thumb_unexpanded_epilogue (void) @@ -20135,6 +20169,7 @@ int regno; unsigned long live_regs_mask = 0; int high_regs_pushed = 0; + int extra_pop; int had_to_push_lr; int size; @@ -20154,6 +20189,13 @@ the register is used to hold a return value. */ size = arm_size_return_regs (); + extra_pop = thumb1_extra_regs_pushed (offsets, false); + if (extra_pop > 0) + { + unsigned long extra_mask = (1 << extra_pop) - 1; + live_regs_mask |= extra_mask << (size / UNITS_PER_WORD); + } + /* The prolog may have pushed some high registers to use as work registers. e.g. the testsuite file: gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c @@ -20237,7 +20279,9 @@ live_regs_mask); /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function. */ + PC or it is was kept in LR for the entire function. + Note that thumb_pushpop has already called thumb_exit if the + PC was in the list. */ if (!had_to_push_lr) thumb_exit (asm_out_file, LR_REGNUM); } @@ -20419,6 +20463,7 @@ stack_pointer_rtx); amount = offsets->outgoing_args - offsets->saved_regs; + amount -= 4 * thumb1_extra_regs_pushed (offsets, true); if (amount) { if (amount < 512) @@ -20503,6 +20548,7 @@ emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx)); amount = offsets->locals_base - offsets->saved_regs; } + amount -= 4 * thumb1_extra_regs_pushed (offsets, false); gcc_assert (amount >= 0); if (amount) @@ -20723,7 +20769,11 @@ register. */ else if ((l_mask & 0xff) != 0 || (high_regs_pushed == 0 && l_mask)) - thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask); + { + unsigned long mask = l_mask; + mask |= (1 << thumb1_extra_regs_pushed (offsets, true)) - 1; + thumb_pushpop (f, mask, 1, &cfa_offset, mask); + } if (high_regs_pushed) { === modified file 'gcc/config/arm/arm.md' --- old/gcc/config/arm/arm.md 2010-08-25 16:22:17 +0000 +++ new/gcc/config/arm/arm.md 2010-08-31 10:00:27 +0000 @@ -150,6 +150,9 @@ ; patterns that share the same RTL in both ARM and Thumb code. (define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code"))) +; IS_ARCH6 is set to 'yes' when we are generating code form ARMv6. +(define_attr "is_arch6" "no,yes" (const (symbol_ref "arm_arch6"))) + ;; Operand number of an input operand that is shifted. Zero if the ;; given instruction does not shift one of its input operands. (define_attr "shift" "" (const_int 0)) @@ -515,8 +518,8 @@ (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) - (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (plus:SI (match_dup 4) (match_dup 5))))] + (set (match_dup 3) (plus:SI (plus:SI (match_dup 4) (match_dup 5)) + (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))] " { operands[3] = gen_highpart (SImode, operands[0]); @@ -543,10 +546,10 @@ (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) - (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (plus:SI (ashiftrt:SI (match_dup 2) + (set (match_dup 3) (plus:SI (plus:SI (ashiftrt:SI (match_dup 2) (const_int 31)) - (match_dup 4))))] + (match_dup 4)) + (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))] " { operands[3] = gen_highpart (SImode, operands[0]); @@ -572,8 +575,8 @@ (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) - (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (plus:SI (match_dup 4) (const_int 0))))] + (set (match_dup 3) (plus:SI (plus:SI (match_dup 4) (const_int 0)) + (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))] " { operands[3] = gen_highpart (SImode, operands[0]); @@ -861,24 +864,38 @@ [(set_attr "conds" "set")] ) -(define_insn "*addsi3_carryin" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (plus:SI (match_operand:SI 1 "s_register_operand" "r") - (match_operand:SI 2 "arm_rhs_operand" "rI"))))] - "TARGET_32BIT" - "adc%?\\t%0, %1, %2" - [(set_attr "conds" "use")] -) - -(define_insn "*addsi3_carryin_shift" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (plus:SI - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "reg_or_int_operand" "rM")]) - (match_operand:SI 1 "s_register_operand" "r"))))] +(define_code_iterator LTUGEU [ltu geu]) +(define_code_attr cnb [(ltu "CC_C") (geu "CC")]) +(define_code_attr optab [(ltu "ltu") (geu "geu")]) + +(define_insn "*addsi3_carryin_" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (LTUGEU:SI (reg: CC_REGNUM) (const_int 0))))] + "TARGET_32BIT" + "adc%?\\t%0, %1, %2" + [(set_attr "conds" "use")] +) + +(define_insn "*addsi3_carryin_alt2_" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (LTUGEU:SI (reg: CC_REGNUM) (const_int 0)) + (match_operand:SI 1 "s_register_operand" "%r")) + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "TARGET_32BIT" + "adc%?\\t%0, %1, %2" + [(set_attr "conds" "use")] +) + +(define_insn "*addsi3_carryin_shift_" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")]) + (match_operand:SI 1 "s_register_operand" "r")) + (LTUGEU:SI (reg: CC_REGNUM) (const_int 0))))] "TARGET_32BIT" "adc%?\\t%0, %1, %3%S2" [(set_attr "conds" "use") @@ -887,36 +904,6 @@ (const_string "alu_shift_reg")))] ) -(define_insn "*addsi3_carryin_alt1" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") - (match_operand:SI 2 "arm_rhs_operand" "rI")) - (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))] - "TARGET_32BIT" - "adc%?\\t%0, %1, %2" - [(set_attr "conds" "use")] -) - -(define_insn "*addsi3_carryin_alt2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (match_operand:SI 1 "s_register_operand" "r")) - (match_operand:SI 2 "arm_rhs_operand" "rI")))] - "TARGET_32BIT" - "adc%?\\t%0, %1, %2" - [(set_attr "conds" "use")] -) - -(define_insn "*addsi3_carryin_alt3" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) - (match_operand:SI 2 "arm_rhs_operand" "rI")) - (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_32BIT" - "adc%?\\t%0, %1, %2" - [(set_attr "conds" "use")] -) - (define_expand "incscc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_operator:SI 2 "arm_comparison_operator" @@ -1116,24 +1103,27 @@ ; ??? Check Thumb-2 split length (define_insn_and_split "*arm_subsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,rk,r") - (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,!k,?n") - (match_operand:SI 2 "s_register_operand" "r, r, r")))] + [(set (match_operand:SI 0 "s_register_operand" "=r,r,rk,r,r") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,r,!k,?n,r") + (match_operand:SI 2 "reg_or_int_operand" "r,rI, r, r,?n")))] "TARGET_32BIT" "@ rsb%?\\t%0, %2, %1 sub%?\\t%0, %1, %2 + sub%?\\t%0, %1, %2 + # #" - "TARGET_32BIT - && GET_CODE (operands[1]) == CONST_INT - && !const_ok_for_arm (INTVAL (operands[1]))" + "&& ((GET_CODE (operands[1]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[1]))) + || (GET_CODE (operands[2]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[2]))))" [(clobber (const_int 0))] " arm_split_constant (MINUS, SImode, curr_insn, INTVAL (operands[1]), operands[0], operands[2], 0); DONE; " - [(set_attr "length" "4,4,16") + [(set_attr "length" "4,4,4,16,16") (set_attr "predicable" "yes")] ) @@ -1165,6 +1155,19 @@ [(set_attr "conds" "set")] ) +(define_insn "*subsi3_compare" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:SI 1 "arm_rhs_operand" "r,I") + (match_operand:SI 2 "arm_rhs_operand" "rI,r"))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "TARGET_32BIT" + "@ + sub%.\\t%0, %1, %2 + rsb%.\\t%0, %2, %1" + [(set_attr "conds" "set")] +) + (define_expand "decscc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") @@ -4050,93 +4053,46 @@ ) (define_expand "zero_extendhisi2" - [(set (match_dup 2) - (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") - (const_int 16))) - (set (match_operand:SI 0 "s_register_operand" "") - (lshiftrt:SI (match_dup 2) (const_int 16)))] + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" - " - { - if ((TARGET_THUMB1 || arm_arch4) && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ZERO_EXTEND (SImode, operands[1]))); - DONE; - } - - if (TARGET_ARM && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_movhi_bytes (operands[0], operands[1])); - DONE; - } - - if (!s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - - if (arm_arch6) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ZERO_EXTEND (SImode, operands[1]))); - DONE; - } - - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - }" -) +{ + if (TARGET_ARM && !arm_arch4 && MEM_P (operands[1])) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } + if (!arm_arch6 && !MEM_P (operands[1])) + { + rtx t = gen_lowpart (SImode, operands[1]); + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_ashlsi3 (tmp, t, GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], tmp, GEN_INT (16))); + DONE; + } +}) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "register_operand" "l,m")))] + "!TARGET_THUMB2 && !arm_arch6" + [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 16))) + (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 16)))] +{ + operands[2] = gen_lowpart (SImode, operands[1]); +}) (define_insn "*thumb1_zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "TARGET_THUMB1 && !arm_arch6" - "* - rtx mem = XEXP (operands[1], 0); - - if (GET_CODE (mem) == CONST) - mem = XEXP (mem, 0); - - if (GET_CODE (mem) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (GET_CODE (mem) == PLUS) - { - rtx a = XEXP (mem, 0); - rtx b = XEXP (mem, 1); - - /* This can happen due to bugs in reload. */ - if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM) - { - rtx ops[2]; - ops[0] = operands[0]; - ops[1] = a; - - output_asm_insn (\"mov %0, %1\", ops); - - XEXP (mem, 0) = operands[0]; - } - - else if ( GET_CODE (a) == LABEL_REF - && GET_CODE (b) == CONST_INT) - return \"ldr\\t%0, %1\"; - } - - return \"ldrh\\t%0, %1\"; - " - [(set_attr "length" "4") - (set_attr "type" "load_byte") - (set_attr "pool_range" "60")] -) - -(define_insn "*thumb1_zero_extendhisi2_v6" [(set (match_operand:SI 0 "register_operand" "=l,l") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))] - "TARGET_THUMB1 && arm_arch6" + "TARGET_THUMB1" "* rtx mem; - if (which_alternative == 0) + if (which_alternative == 0 && arm_arch6) return \"uxth\\t%0, %1\"; + if (which_alternative == 0) + return \"#\"; mem = XEXP (operands[1], 0); @@ -4170,20 +4126,25 @@ return \"ldrh\\t%0, %1\"; " - [(set_attr "length" "2,4") + [(set_attr_alternative "length" + [(if_then_else (eq_attr "is_arch6" "yes") + (const_int 2) (const_int 4)) + (const_int 4)]) (set_attr "type" "alu_shift,load_byte") (set_attr "pool_range" "*,60")] ) (define_insn "*arm_zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] "TARGET_ARM && arm_arch4 && !arm_arch6" - "ldr%(h%)\\t%0, %1" - [(set_attr "type" "load_byte") + "@ + # + ldr%(h%)\\t%0, %1" + [(set_attr "type" "alu_shift,load_byte") (set_attr "predicable" "yes") - (set_attr "pool_range" "256") - (set_attr "neg_pool_range" "244")] + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) (define_insn "*arm_zero_extendhisi2_v6" @@ -4213,50 +4174,49 @@ [(set (match_operand:SI 0 "s_register_operand" "") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" - " - if (!arm_arch6 && GET_CODE (operands[1]) != MEM) - { - if (TARGET_ARM) - { - emit_insn (gen_andsi3 (operands[0], - gen_lowpart (SImode, operands[1]), - GEN_INT (255))); - } - else /* TARGET_THUMB */ - { - rtx temp = gen_reg_rtx (SImode); - rtx ops[3]; - - operands[1] = copy_to_mode_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - - ops[0] = temp; - ops[1] = operands[1]; - ops[2] = GEN_INT (24); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); - - ops[0] = operands[0]; - ops[1] = temp; - ops[2] = GEN_INT (24); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_LSHIFTRT (SImode, ops[1], ops[2]))); - } - DONE; - } - " -) +{ + if (TARGET_ARM && !arm_arch6 && GET_CODE (operands[1]) != MEM) + { + emit_insn (gen_andsi3 (operands[0], + gen_lowpart (SImode, operands[1]), + GEN_INT (255))); + DONE; + } + if (!arm_arch6 && !MEM_P (operands[1])) + { + rtx t = gen_lowpart (SImode, operands[1]); + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_ashlsi3 (tmp, t, GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], tmp, GEN_INT (24))); + DONE; + } +}) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "register_operand" "")))] + "!arm_arch6" + [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 24))) + (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 24)))] +{ + operands[2] = simplify_gen_subreg (SImode, operands[1], QImode, 0); + if (TARGET_ARM) + { + emit_insn (gen_andsi3 (operands[0], operands[2], GEN_INT (255))); + DONE; + } +}) (define_insn "*thumb1_zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] "TARGET_THUMB1 && !arm_arch6" - "ldrb\\t%0, %1" - [(set_attr "length" "2") - (set_attr "type" "load_byte") - (set_attr "pool_range" "32")] + "@ + # + ldrb\\t%0, %1" + [(set_attr "length" "4,2") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,32")] ) (define_insn "*thumb1_zero_extendqisi2_v6" @@ -4272,14 +4232,17 @@ ) (define_insn "*arm_zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] "TARGET_ARM && !arm_arch6" - "ldr%(b%)\\t%0, %1\\t%@ zero_extendqisi2" - [(set_attr "type" "load_byte") + "@ + # + ldr%(b%)\\t%0, %1\\t%@ zero_extendqisi2" + [(set_attr "length" "8,4") + (set_attr "type" "alu_shift,load_byte") (set_attr "predicable" "yes") - (set_attr "pool_range" "4096") - (set_attr "neg_pool_range" "4084")] + (set_attr "pool_range" "*,4096") + (set_attr "neg_pool_range" "*,4084")] ) (define_insn "*arm_zero_extendqisi2_v6" @@ -4358,108 +4321,42 @@ ) (define_expand "extendhisi2" - [(set (match_dup 2) - (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") - (const_int 16))) - (set (match_operand:SI 0 "s_register_operand" "") - (ashiftrt:SI (match_dup 2) - (const_int 16)))] + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" - " - { - if (GET_CODE (operands[1]) == MEM) - { - if (TARGET_THUMB1) - { - emit_insn (gen_thumb1_extendhisi2 (operands[0], operands[1])); - DONE; - } - else if (arm_arch4) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; - } - } - - if (TARGET_ARM && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); - DONE; - } - - if (!s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - - if (arm_arch6) - { - if (TARGET_THUMB1) - emit_insn (gen_thumb1_extendhisi2 (operands[0], operands[1])); - else - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - - DONE; - } - - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - }" -) - -(define_insn "thumb1_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "TARGET_THUMB1 && !arm_arch6" - "* - { - rtx ops[4]; - rtx mem = XEXP (operands[1], 0); - - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (mem) == CONST) - mem = XEXP (mem, 0); - - if (GET_CODE (mem) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (GET_CODE (mem) == PLUS) - { - rtx a = XEXP (mem, 0); - rtx b = XEXP (mem, 1); - - if (GET_CODE (a) == LABEL_REF - && GET_CODE (b) == CONST_INT) - return \"ldr\\t%0, %1\"; - - if (GET_CODE (b) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[1] = a; - ops[2] = b; - } - else - { - ops[1] = mem; - ops[2] = const0_rtx; - } - - gcc_assert (GET_CODE (ops[1]) == REG); - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; - }" - [(set_attr "length" "4") - (set_attr "type" "load_byte") - (set_attr "pool_range" "1020")] -) +{ + if (TARGET_THUMB1) + { + emit_insn (gen_thumb1_extendhisi2 (operands[0], operands[1])); + DONE; + } + if (MEM_P (operands[1]) && TARGET_ARM && !arm_arch4) + { + emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); + DONE; + } + + if (!arm_arch6 && !MEM_P (operands[1])) + { + rtx t = gen_lowpart (SImode, operands[1]); + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_ashlsi3 (tmp, t, GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], tmp, GEN_INT (16))); + DONE; + } +}) + +(define_split + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "register_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "!arm_arch6" + [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 16))) + (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 16)))] +{ + operands[2] = simplify_gen_subreg (SImode, operands[1], HImode, 0); +}) ;; We used to have an early-clobber on the scratch register here. ;; However, there's a bug somewhere in reload which means that this @@ -4468,16 +4365,18 @@ ;; we try to verify the operands. Fortunately, we don't really need ;; the early-clobber: we can always use operand 0 if operand 2 ;; overlaps the address. -(define_insn "*thumb1_extendhisi2_insn_v6" +(define_insn "thumb1_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=l,l") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m"))) (clobber (match_scratch:SI 2 "=X,l"))] - "TARGET_THUMB1 && arm_arch6" + "TARGET_THUMB1" "* { rtx ops[4]; rtx mem; + if (which_alternative == 0 && !arm_arch6) + return \"#\"; if (which_alternative == 0) return \"sxth\\t%0, %1\"; @@ -4525,7 +4424,10 @@ output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); return \"\"; }" - [(set_attr "length" "2,4") + [(set_attr_alternative "length" + [(if_then_else (eq_attr "is_arch6" "yes") + (const_int 2) (const_int 4)) + (const_int 4)]) (set_attr "type" "alu_shift,load_byte") (set_attr "pool_range" "*,1020")] ) @@ -4566,15 +4468,28 @@ }" ) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] + "!arm_arch6" + [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 16))) + (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 16)))] +{ + operands[2] = simplify_gen_subreg (SImode, operands[1], HImode, 0); +}) + (define_insn "*arm_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] "TARGET_ARM && arm_arch4 && !arm_arch6" - "ldr%(sh%)\\t%0, %1" - [(set_attr "type" "load_byte") + "@ + # + ldr%(sh%)\\t%0, %1" + [(set_attr "length" "8,4") + (set_attr "type" "alu_shift,load_byte") (set_attr "predicable" "yes") - (set_attr "pool_range" "256") - (set_attr "neg_pool_range" "244")] + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) ;; ??? Check Thumb-2 pool range @@ -4636,46 +4551,45 @@ ) (define_expand "extendqisi2" - [(set (match_dup 2) - (ashift:SI (match_operand:QI 1 "arm_reg_or_extendqisi_mem_op" "") - (const_int 24))) - (set (match_operand:SI 0 "s_register_operand" "") - (ashiftrt:SI (match_dup 2) - (const_int 24)))] + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "arm_reg_or_extendqisi_mem_op" "")))] "TARGET_EITHER" - " - { - if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; - } - - if (!s_register_operand (operands[1], QImode)) - operands[1] = copy_to_mode_reg (QImode, operands[1]); - - if (arm_arch6) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; - } - - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - }" -) +{ + if (!arm_arch4 && MEM_P (operands[1])) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + + if (!arm_arch6 && !MEM_P (operands[1])) + { + rtx t = gen_lowpart (SImode, operands[1]); + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_ashlsi3 (tmp, t, GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], tmp, GEN_INT (24))); + DONE; + } +}) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] + "!arm_arch6" + [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 24))) + (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 24)))] +{ + operands[2] = simplify_gen_subreg (SImode, operands[1], QImode, 0); +}) (define_insn "*arm_extendqisi" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:QI 1 "arm_extendqisi_mem_op" "Uq")))] + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "arm_reg_or_extendqisi_mem_op" "r,Uq")))] "TARGET_ARM && arm_arch4 && !arm_arch6" - "ldr%(sb%)\\t%0, %1" - [(set_attr "type" "load_byte") + "@ + # + ldr%(sb%)\\t%0, %1" + [(set_attr "length" "8,4") + (set_attr "type" "alu_shift,load_byte") (set_attr "predicable" "yes") - (set_attr "pool_range" "256") - (set_attr "neg_pool_range" "244")] + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) (define_insn "*arm_extendqisi_v6" @@ -4703,162 +4617,103 @@ (set_attr "predicable" "yes")] ) -(define_insn "*thumb1_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "TARGET_THUMB1 && !arm_arch6" - "* - { - rtx ops[3]; - rtx mem = XEXP (operands[1], 0); - - if (GET_CODE (mem) == CONST) - mem = XEXP (mem, 0); - - if (GET_CODE (mem) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (GET_CODE (mem) == PLUS - && GET_CODE (XEXP (mem, 0)) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - - ops[0] = operands[0]; - - if (GET_CODE (mem) == PLUS) - { - rtx a = XEXP (mem, 0); - rtx b = XEXP (mem, 1); - - ops[1] = a; - ops[2] = b; - - if (GET_CODE (a) == REG) - { - if (GET_CODE (b) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (REGNO (a) == REGNO (ops[0])) - { - output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops); - output_asm_insn (\"lsl\\t%0, %0, #24\", ops); - output_asm_insn (\"asr\\t%0, %0, #24\", ops); - } - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - gcc_assert (GET_CODE (b) == REG); - if (REGNO (b) == REGNO (ops[0])) - { - output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops); - output_asm_insn (\"lsl\\t%0, %0, #24\", ops); - output_asm_insn (\"asr\\t%0, %0, #24\", ops); - } - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem)) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops); - output_asm_insn (\"lsl\\t%0, %0, #24\", ops); - output_asm_insn (\"asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = mem; - ops[2] = const0_rtx; - - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; - }" - [(set_attr "length" "2,6") - (set_attr "type" "load_byte,load_byte") - (set_attr "pool_range" "32,32")] -) - -(define_insn "*thumb1_extendqisi2_v6" +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "")))] + "TARGET_THUMB1 && reload_completed" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (sign_extend:SI (match_dup 3)))] +{ + rtx addr = XEXP (operands[1], 0); + + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + if (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))) + /* No split necessary. */ + FAIL; + + if (GET_CODE (addr) == PLUS + && !REG_P (XEXP (addr, 0)) && !REG_P (XEXP (addr, 1))) + FAIL; + + if (reg_overlap_mentioned_p (operands[0], addr)) + { + rtx t = gen_lowpart (QImode, operands[0]); + emit_move_insn (t, operands[1]); + emit_insn (gen_thumb1_extendqisi2 (operands[0], t)); + DONE; + } + + if (REG_P (addr)) + { + addr = gen_rtx_PLUS (Pmode, addr, operands[0]); + operands[2] = const0_rtx; + } + else if (GET_CODE (addr) != PLUS) + FAIL; + else if (REG_P (XEXP (addr, 0))) + { + operands[2] = XEXP (addr, 1); + addr = gen_rtx_PLUS (Pmode, XEXP (addr, 0), operands[0]); + } + else + { + operands[2] = XEXP (addr, 0); + addr = gen_rtx_PLUS (Pmode, XEXP (addr, 1), operands[0]); + } + + operands[3] = change_address (operands[1], QImode, addr); +}) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_dup 0) (match_operand 1 "const_int_operand"))) + (set (match_operand:SI 2 "register_operand" "") (const_int 0)) + (set (match_operand:SI 3 "register_operand" "") + (sign_extend:SI (match_operand:QI 4 "memory_operand" "")))] + "TARGET_THUMB1 + && GET_CODE (XEXP (operands[4], 0)) == PLUS + && rtx_equal_p (operands[0], XEXP (XEXP (operands[4], 0), 0)) + && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 1)) + && (peep2_reg_dead_p (3, operands[0]) + || rtx_equal_p (operands[0], operands[3])) + && (peep2_reg_dead_p (3, operands[2]) + || rtx_equal_p (operands[2], operands[3]))" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 3) (sign_extend:SI (match_dup 4)))] +{ + rtx addr = gen_rtx_PLUS (Pmode, operands[0], operands[2]); + operands[4] = change_address (operands[4], QImode, addr); +}) + +(define_insn "thumb1_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=l,l,l") (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))] - "TARGET_THUMB1 && arm_arch6" - "* - { - rtx ops[3]; - rtx mem; - - if (which_alternative == 0) - return \"sxtb\\t%0, %1\"; - - mem = XEXP (operands[1], 0); - - if (GET_CODE (mem) == CONST) - mem = XEXP (mem, 0); - - if (GET_CODE (mem) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (GET_CODE (mem) == PLUS - && GET_CODE (XEXP (mem, 0)) == LABEL_REF) - return \"ldr\\t%0, %1\"; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - - ops[0] = operands[0]; - - if (GET_CODE (mem) == PLUS) - { - rtx a = XEXP (mem, 0); - rtx b = XEXP (mem, 1); - - ops[1] = a; - ops[2] = b; - - if (GET_CODE (a) == REG) - { - if (GET_CODE (b) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (REGNO (a) == REGNO (ops[0])) - { - output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops); - output_asm_insn (\"sxtb\\t%0, %0\", ops); - } - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - gcc_assert (GET_CODE (b) == REG); - if (REGNO (b) == REGNO (ops[0])) - { - output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops); - output_asm_insn (\"sxtb\\t%0, %0\", ops); - } - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem)) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops); - output_asm_insn (\"sxtb\\t%0, %0\", ops); - } - else - { - ops[1] = mem; - ops[2] = const0_rtx; - - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; - }" - [(set_attr "length" "2,2,4") - (set_attr "type" "alu_shift,load_byte,load_byte") - (set_attr "pool_range" "*,32,32")] + "TARGET_THUMB1" +{ + rtx addr; + + if (which_alternative == 0 && arm_arch6) + return "sxtb\\t%0, %1"; + if (which_alternative == 0) + return "#"; + + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))) + return "ldrsb\\t%0, %1"; + + return "#"; +} + [(set_attr_alternative "length" + [(if_then_else (eq_attr "is_arch6" "yes") + (const_int 2) (const_int 4)) + (const_int 2) + (if_then_else (eq_attr "is_arch6" "yes") + (const_int 4) (const_int 6))]) + (set_attr "type" "alu_shift,load_byte,load_byte")] ) (define_expand "extendsfdf2" @@ -6784,6 +6639,30 @@ operands[2] = force_reg (SImode, operands[2]); ") +;; A pattern to recognize a special situation and optimize for it. +;; On the thumb, zero-extension from memory is preferrable to sign-extension +;; due to the available addressing modes. Hence, convert a signed comparison +;; with zero into an unsigned comparison with 127 if possible. +(define_expand "cbranchqi4" + [(set (pc) (if_then_else + (match_operator 0 "lt_ge_comparison_operator" + [(match_operand:QI 1 "memory_operand" "") + (match_operand:QI 2 "const0_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB1" +{ + rtx xops[4]; + xops[1] = gen_reg_rtx (SImode); + emit_insn (gen_zero_extendqisi2 (xops[1], operands[1])); + xops[2] = GEN_INT (127); + xops[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]) == GE ? LEU : GTU, + VOIDmode, xops[1], xops[2]); + xops[3] = operands[3]; + emit_insn (gen_cbranchsi4 (xops[0], xops[1], xops[2], xops[3])); + DONE; +}) + (define_expand "cbranchsf4" [(set (pc) (if_then_else (match_operator 0 "arm_comparison_operator" @@ -6849,7 +6728,7 @@ }" ) -(define_insn "*cbranchsi4_insn" +(define_insn "cbranchsi4_insn" [(set (pc) (if_then_else (match_operator 0 "arm_comparison_operator" [(match_operand:SI 1 "s_register_operand" "l,*h") @@ -6858,7 +6737,20 @@ (pc)))] "TARGET_THUMB1" "* - output_asm_insn (\"cmp\\t%1, %2\", operands); + rtx t = prev_nonnote_insn (insn); + if (t != NULL_RTX + && INSN_P (t) + && INSN_CODE (t) == CODE_FOR_cbranchsi4_insn) + { + t = XEXP (SET_SRC (PATTERN (t)), 0); + if (!rtx_equal_p (XEXP (t, 0), operands[1]) + || !rtx_equal_p (XEXP (t, 1), operands[2])) + t = NULL_RTX; + } + else + t = NULL_RTX; + if (t == NULL_RTX) + output_asm_insn (\"cmp\\t%1, %2\", operands); switch (get_attr_length (insn)) { @@ -7674,15 +7566,15 @@ (if_then_else (match_operator 4 "arm_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")) + (match_operand:SI 2 "s_register_operand" "%0,l,*l,1,1,1") + (match_operand:SI 3 "reg_or_int_operand" "IJ,lL,*l,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"))] + (clobber (match_scratch:SI 1 "=X,X,l,l,&l,&l"))] "TARGET_THUMB1 && (GET_CODE (operands[4]) == EQ || GET_CODE (operands[4]) == NE @@ -7692,8 +7584,7 @@ { rtx cond[3]; - - cond[0] = (which_alternative < 3) ? operands[0] : operands[1]; + cond[0] = (which_alternative < 2) ? operands[0] : operands[1]; cond[1] = operands[2]; cond[2] = operands[3]; @@ -7702,13 +7593,13 @@ else output_asm_insn (\"add\\t%0, %1, %2\", cond); - if (which_alternative >= 3 + if (which_alternative >= 2 && 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)) + switch (get_attr_length (insn) - ((which_alternative >= 2) ? 2 : 0)) { case 4: return \"b%d4\\t%l5\"; @@ -7722,7 +7613,7 @@ [(set (attr "far_jump") (if_then_else (ior (and (lt (symbol_ref ("which_alternative")) - (const_int 3)) + (const_int 2)) (eq_attr "length" "8")) (eq_attr "length" "10")) (const_string "yes") @@ -7730,7 +7621,7 @@ (set (attr "length") (if_then_else (lt (symbol_ref ("which_alternative")) - (const_int 3)) + (const_int 2)) (if_then_else (and (ge (minus (match_dup 5) (pc)) (const_int -250)) (le (minus (match_dup 5) (pc)) (const_int 256))) @@ -9483,41 +9374,117 @@ (set_attr "length" "4,8")] ) -(define_insn "*compare_scc" +; A series of splitters for the compare_scc pattern below. Note that +; order is important. +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (lt:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (lshiftrt:SI (match_dup 1) (const_int 31)))]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ge:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (not:SI (match_dup 1))) + (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31)))]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (eq:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && reload_completed" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (const_int 1) (match_dup 1))) + (set (match_dup 0) + (minus:SI (const_int 1) (match_dup 1)))]) + (cond_exec (ltu:CC (reg:CC CC_REGNUM) (const_int 0)) + (set (match_dup 0) (const_int 0)))]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ne:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && reload_completed" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))]) + (cond_exec (ne:CC (reg:CC CC_REGNUM) (const_int 0)) + (set (match_dup 0) (const_int 1)))] +{ + operands[3] = GEN_INT (-INTVAL (operands[2])); +}) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ne:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_add_operand" ""))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && reload_completed" + [(parallel + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (minus:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))]) + (cond_exec (ne:CC_NOOV (reg:CC_NOOV CC_REGNUM) (const_int 0)) + (set (match_dup 0) (const_int 1)))]) + +(define_insn_and_split "*compare_scc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (match_operator:SI 1 "arm_comparison_operator" [(match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 3 "arm_add_operand" "rI,L")])) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" - "* - if (operands[3] == const0_rtx) - { - if (GET_CODE (operands[1]) == LT) - return \"mov\\t%0, %2, lsr #31\"; - - if (GET_CODE (operands[1]) == GE) - return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; - - if (GET_CODE (operands[1]) == EQ) - return \"rsbs\\t%0, %2, #1\;movcc\\t%0, #0\"; - } - - if (GET_CODE (operands[1]) == NE) - { - if (which_alternative == 1) - return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\"; - return \"subs\\t%0, %2, %3\;movne\\t%0, #1\"; - } - if (which_alternative == 1) - output_asm_insn (\"cmn\\t%2, #%n3\", operands); - else - output_asm_insn (\"cmp\\t%2, %3\", operands); - return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\"; - " - [(set_attr "conds" "clob") - (set_attr "length" "12")] -) + "TARGET_32BIT" + "#" + "&& reload_completed" + [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 2) (match_dup 3))) + (cond_exec (match_dup 4) (set (match_dup 0) (const_int 0))) + (cond_exec (match_dup 5) (set (match_dup 0) (const_int 1)))] +{ + rtx tmp1; + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), + operands[2], operands[3]); + enum rtx_code rc = GET_CODE (operands[1]); + + tmp1 = gen_rtx_REG (mode, CC_REGNUM); + + operands[5] = gen_rtx_fmt_ee (rc, VOIDmode, tmp1, const0_rtx); + if (mode == CCFPmode || mode == CCFPEmode) + rc = reverse_condition_maybe_unordered (rc); + else + rc = reverse_condition (rc); + operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, tmp1, const0_rtx); +}) + +;; Attempt to improve the sequence generated by the compare_scc splitters +;; not to use conditional execution. +(define_peephole2 + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" ""))) + (cond_exec (ne (reg:CC CC_REGNUM) (const_int 0)) + (set (match_operand:SI 0 "register_operand" "") (const_int 0))) + (cond_exec (eq (reg:CC CC_REGNUM) (const_int 0)) + (set (match_dup 0) (const_int 1))) + (match_scratch:SI 3 "r")] + "TARGET_32BIT" + [(set (match_dup 3) (minus:SI (match_dup 1) (match_dup 2))) + (parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (const_int 0) (match_dup 3))) + (set (match_dup 0) (minus:SI (const_int 0) (match_dup 3)))]) + (set (match_dup 0) + (plus:SI (plus:SI (match_dup 0) (match_dup 3)) + (geu:SI (reg:CC CC_REGNUM) (const_int 0))))]) (define_insn "*cond_move" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") === modified file 'gcc/config/arm/predicates.md' --- old/gcc/config/arm/predicates.md 2010-08-31 09:40:16 +0000 +++ new/gcc/config/arm/predicates.md 2010-08-31 10:00:27 +0000 @@ -115,6 +115,10 @@ (and (match_code "const_int") (match_test "const_ok_for_arm (~INTVAL (op))"))) +(define_predicate "const0_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 0"))) + ;; Something valid on the RHS of an ARM data-processing instruction (define_predicate "arm_rhs_operand" (ior (match_operand 0 "s_register_operand") @@ -233,6 +237,9 @@ && (TARGET_FPA || TARGET_VFP)") (match_code "unordered,ordered,unlt,unle,unge,ungt")))) +(define_special_predicate "lt_ge_comparison_operator" + (match_code "lt,ge")) + (define_special_predicate "minmax_operator" (and (match_code "smin,smax,umin,umax") (match_test "mode == GET_MODE (op)"))) === modified file 'gcc/config/arm/thumb2.md' --- old/gcc/config/arm/thumb2.md 2010-08-31 09:40:16 +0000 +++ new/gcc/config/arm/thumb2.md 2010-08-31 10:00:27 +0000 @@ -599,42 +599,6 @@ (set_attr "length" "6,10")] ) -(define_insn "*thumb2_compare_scc" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (match_operator:SI 1 "arm_comparison_operator" - [(match_operand:SI 2 "s_register_operand" "r,r") - (match_operand:SI 3 "arm_add_operand" "rI,L")])) - (clobber (reg:CC CC_REGNUM))] - "TARGET_THUMB2" - "* - if (operands[3] == const0_rtx) - { - if (GET_CODE (operands[1]) == LT) - return \"lsr\\t%0, %2, #31\"; - - if (GET_CODE (operands[1]) == GE) - return \"mvn\\t%0, %2\;lsr\\t%0, %0, #31\"; - - if (GET_CODE (operands[1]) == EQ) - return \"rsbs\\t%0, %2, #1\;it\\tcc\;movcc\\t%0, #0\"; - } - - if (GET_CODE (operands[1]) == NE) - { - if (which_alternative == 1) - return \"adds\\t%0, %2, #%n3\;it\\tne\;movne\\t%0, #1\"; - return \"subs\\t%0, %2, %3\;it\\tne\;movne\\t%0, #1\"; - } - if (which_alternative == 1) - output_asm_insn (\"cmn\\t%2, #%n3\", operands); - else - output_asm_insn (\"cmp\\t%2, %3\", operands); - return \"ite\\t%D1\;mov%D1\\t%0, #0\;mov%d1\\t%0, #1\"; - " - [(set_attr "conds" "clob") - (set_attr "length" "14")] -) - (define_insn "*thumb2_cond_move" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (if_then_else:SI (match_operator 3 "equality_operator" === added file 'gcc/testsuite/gcc.c-torture/execute/pr40657.c' --- old/gcc/testsuite/gcc.c-torture/execute/pr40657.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.c-torture/execute/pr40657.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,23 @@ +/* Verify that that Thumb-1 epilogue size optimization does not clobber the + return value. */ + +long long v = 0x123456789abc; + +__attribute__((noinline)) void bar (int *x) +{ + asm volatile ("" : "=m" (x) ::); +} + +__attribute__((noinline)) long long foo() +{ + int x; + bar(&x); + return v; +} + +int main () +{ + if (foo () != v) + abort (); + exit (0); +} === added file 'gcc/testsuite/gcc.target/arm/pr40657-1.c' --- old/gcc/testsuite/gcc.target/arm/pr40657-1.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/pr40657-1.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,13 @@ +/* { dg-options "-Os -march=armv5te -mthumb" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-final { scan-assembler "pop.*r1.*pc" } } */ +/* { dg-final { scan-assembler-not "sub\[\\t \]*sp,\[\\t \]*sp" } } */ +/* { dg-final { scan-assembler-not "add\[\\t \]*sp,\[\\t \]*sp" } } */ + +extern void bar(int*); +int foo() +{ + int x; + bar(&x); + return x; +} === added file 'gcc/testsuite/gcc.target/arm/pr40657-2.c' --- old/gcc/testsuite/gcc.target/arm/pr40657-2.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/pr40657-2.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,20 @@ +/* { dg-options "-Os -march=armv4t -mthumb" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-final { scan-assembler-not "sub\[\\t \]*sp,\[\\t \]*sp" } } */ +/* { dg-final { scan-assembler-not "add\[\\t \]*sp,\[\\t \]*sp" } } */ + +/* Here, we test that if there's a pop of r[4567] in the epilogue, + add sp,sp,#12 is removed and replaced by three additional pops + of lower-numbered regs. */ + +extern void bar(int*); + +int t1, t2, t3, t4, t5; +int foo() +{ + int i,j,k,x = 0; + for (i = 0; i < t1; i++) + for (j = 0; j < t2; j++) + bar(&x); + return x; +} === added file 'gcc/testsuite/gcc.target/arm/pr42172-1.c' --- old/gcc/testsuite/gcc.target/arm/pr42172-1.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/pr42172-1.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,19 @@ +/* { dg-options "-O2" } */ + +struct A { + unsigned int f1 : 3; + unsigned int f2 : 3; + unsigned int f3 : 1; + unsigned int f4 : 1; + +}; + +void init_A (struct A *this) +{ + this->f1 = 0; + this->f2 = 1; + this->f3 = 0; + this->f4 = 0; +} + +/* { dg-final { scan-assembler-times "ldr" 1 } } */ === added file 'gcc/testsuite/gcc.target/arm/pr42835.c' --- old/gcc/testsuite/gcc.target/arm/pr42835.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/pr42835.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os" } */ +/* { dg-require-effective-target arm_thumb2_ok } */ + +int foo(int *p, int i) +{ + return( (i < 0 && *p == 1) + || (i > 0 && *p == 2) ); +} + +/* { dg-final { scan-assembler-times "movne\[\\t \]*r.,\[\\t \]*#" 1 } } */ +/* { dg-final { scan-assembler-times "moveq\[\\t \]*r.,\[\\t \]*#" 1 } } */ === added file 'gcc/testsuite/gcc.target/arm/thumb-cbranchqi.c' --- old/gcc/testsuite/gcc.target/arm/thumb-cbranchqi.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/thumb-cbranchqi.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ + +int ldrb(unsigned char* p) +{ + if (p[8] <= 0x7F) + return 2; + else + return 5; +} + + +/* { dg-final { scan-assembler "127" } } */ +/* { dg-final { scan-assembler "bhi" } } */ === added file 'gcc/testsuite/gcc.target/arm/thumb-comparisons.c' --- old/gcc/testsuite/gcc.target/arm/thumb-comparisons.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/thumb-comparisons.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ + +int foo(char ch) +{ + switch (ch) { + case '-': + case '?': + case '/': + case 99: + return 1; + default: + return 0; + } +} + +/* { dg-final { scan-assembler-times "cmp\[\\t \]*r.,\[\\t \]*#63" 1 } } */ === added file 'gcc/testsuite/gcc.target/arm/thumb-stackframe.c' --- old/gcc/testsuite/gcc.target/arm/thumb-stackframe.c 1970-01-01 00:00:00 +0000 +++ new/gcc/testsuite/gcc.target/arm/thumb-stackframe.c 2010-08-31 10:00:27 +0000 @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ + +extern void bar(int*); +int foo() +{ + int x; + bar(&x); + return x; +} + +/* { dg-final { scan-assembler-not "sub\[\\t \]*sp,\[\\t \]*sp," } } */