Index: arm-protos.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/arm/arm-protos.h,v retrieving revision 1.60.4.4 diff -p -w -r1.60.4.4 arm-protos.h *** arm-protos.h 24 Dec 2003 11:51:58 -0000 1.60.4.4 --- arm-protos.h 7 Jan 2004 12:32:20 -0000 *************** extern void arm_final_prescan_insn (rtx) *** 140,146 **** extern int arm_go_if_legitimate_address (enum machine_mode, rtx); extern int arm_debugger_arg_offset (int, rtx); extern int arm_is_longcall_p (rtx, int, int); - extern int arm_emit_extendsi (enum rtx_code, rtx, rtx); extern int arm_emit_vector_const (FILE *, rtx); extern const char * arm_output_load_gr (rtx *); --- 140,145 ---- Index: arm.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v retrieving revision 1.303.2.11 diff -p -w -r1.303.2.11 arm.c *** arm.c 31 Dec 2003 00:44:18 -0000 1.303.2.11 --- arm.c 7 Jan 2004 12:32:20 -0000 *************** arm_output_mi_thunk (FILE *file, tree th *** 13482,13521 **** } } - /* Emit RTL for a sign/zero extend insn. */ - int - arm_emit_extendsi (enum rtx_code code, rtx op0, rtx op1) - { - rtx tmp; - rtx *p; - - if (GET_CODE (op1) != SUBREG - || !arm_arch6j) - return 0; - - p = &XEXP (op1, 0); - if (GET_CODE (*p) != REG) - return 0; - - if (XINT (op1, 1) != 0) - return 0; - - /* Put the low part of multiword regs into an SImode reg so we only - have to deal with subregs of SImode regs. */ - if (GET_MODE (*p) != SImode) - { - tmp = gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (VOIDmode, tmp, - gen_lowpart (SImode, *p))); - *p = tmp; - } - - emit_insn (gen_rtx_SET (VOIDmode, op0, - gen_rtx_fmt_e (code, SImode, op1))); - return 1; - } - - int arm_emit_vector_const (FILE *file, rtx x) { --- 13482,13487 ---- Index: arm.md =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v retrieving revision 1.145.2.10 diff -p -w -r1.145.2.10 arm.md *** arm.md 31 Dec 2003 00:44:19 -0000 1.145.2.10 --- arm.md 7 Jan 2004 12:32:20 -0000 *************** *** 3145,3193 **** rather than an LDR instruction, so we cannot get an unaligned word access. */ emit_insn (gen_rtx_SET (VOIDmode, operands[0], ! gen_rtx_ZERO_EXTEND (SImode, ! operands[1]))); DONE; } if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) { emit_insn (gen_movhi_bytes (operands[0], operands[1])); DONE; } ! if (arm_emit_extendsi (ZERO_EXTEND, operands[0], operands[1])) ! DONE; if (!s_register_operand (operands[1], HImode)) operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); ! if (TARGET_THUMB) { ! rtx ops[3]; ! ! ops[0] = operands[2]; ! ops[1] = operands[1]; ! ops[2] = GEN_INT (16); ! ! emit_insn (gen_rtx_SET (VOIDmode, ops[0], ! gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); ! ! ops[0] = operands[0]; ! ops[1] = operands[2]; ! ops[2] = GEN_INT (16); ! ! emit_insn (gen_rtx_SET (VOIDmode, ops[0], ! gen_rtx_LSHIFTRT (SImode, ops[1], ! ops[2]))); DONE; } }" ) (define_insn "*thumb_zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=l") (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ! "TARGET_THUMB" "* rtx mem = XEXP (operands[1], 0); --- 3145,3179 ---- rather than an LDR instruction, so we cannot get an unaligned word access. */ emit_insn (gen_rtx_SET (VOIDmode, operands[0], ! gen_rtx_ZERO_EXTEND (SImode, operands[1]))); DONE; } + if (TARGET_ARM && TARGET_MMU_TRAPS && 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_arch6j) { ! 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); }" ) (define_insn "*thumb_zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=l") (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ! "TARGET_THUMB && !arm_arch6j" "* rtx mem = XEXP (operands[1], 0); *************** *** 3226,3235 **** (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")))] ! "TARGET_ARM && arm_arch4" "ldr%?h\\t%0, %1" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") --- 3212,3268 ---- (set_attr "pool_range" "60")] ) + (define_insn "*thumb_zero_extendhisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB && arm_arch6j" + "* + rtx mem; + + if (which_alternative == 0) + return \"uxth\\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) + { + 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" "2,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")))] ! "TARGET_ARM && arm_arch4 && !arm_arch6j" "ldr%?h\\t%0, %1" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") *************** *** 3237,3257 **** (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_zero_extendhisi2_reg" ! [(set (match_operand:SI 0 "s_register_operand" "=r") ! (zero_extend:SI (subreg:HI ! (match_operand:SI 1 "s_register_operand" "r") 0)))] ! "TARGET_EITHER && arm_arch6j" ! "uxth%?\\t%0, %1" ) (define_insn "*arm_zero_extendhisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (zero_extend:SI (subreg:HI ! (match_operand:SI 1 "s_register_operand" "r") 0)) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "uxtah%?\\t%0, %2, %1" ) (define_split --- 3270,3296 ---- (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_zero_extendhisi2_v6" ! [(set (match_operand:SI 0 "s_register_operand" "=r,r") ! (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ! "TARGET_ARM && arm_arch6j" ! "@ ! uxth%?\\t%0, %1 ! 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")] ) (define_insn "*arm_zero_extendhisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (zero_extend:SI (match_operand:HI 1 "s_register_operand" "r")) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "uxtah%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "predicable" "yes")] ) (define_split *************** *** 3289,3297 **** (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" " ! if (arm_emit_extendsi (ZERO_EXTEND, operands[0], operands[1])) ! DONE; ! if (GET_CODE (operands[1]) != MEM) { if (TARGET_ARM) { --- 3328,3334 ---- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" " ! if (!arm_arch6j && GET_CODE (operands[1]) != MEM) { if (TARGET_ARM) { *************** *** 3329,3345 **** (define_insn "*thumb_zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=l") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_THUMB" "ldrb\\t%0, %1" [(set_attr "length" "2") (set_attr "type" "load_byte") (set_attr "pool_range" "32")] ) (define_insn "*arm_zero_extendqisi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_ARM" "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") --- 3366,3394 ---- (define_insn "*thumb_zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=l") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_THUMB && !arm_arch6j" "ldrb\\t%0, %1" [(set_attr "length" "2") (set_attr "type" "load_byte") (set_attr "pool_range" "32")] ) + (define_insn "*thumb_zero_extendqisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB && arm_arch6j" + "@ + uxtb\\t%0, %1 + ldrb\\t%0, %1" + [(set_attr "length" "2,2") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,32")] + ) + (define_insn "*arm_zero_extendqisi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_ARM && !arm_arch6j" "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") *************** *** 3347,3367 **** (set_attr "neg_pool_range" "4084")] ) ! (define_insn "*arm_zero_extendqisi2_reg" ! [(set (match_operand:SI 0 "s_register_operand" "=r") ! (zero_extend:SI (subreg:QI ! (match_operand:SI 1 "s_register_operand" "r") 0)))] ! "TARGET_EITHER && arm_arch6j" ! "uxtb%?\\t%0, %1" ) (define_insn "*arm_zero_extendqisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (zero_extend:SI (subreg:QI ! (match_operand:SI 1 "s_register_operand" "r") 0)) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "uxtab%?\\t%0, %2, %1" ) (define_split --- 3396,3422 ---- (set_attr "neg_pool_range" "4084")] ) ! (define_insn "*arm_zero_extendqisi2_v6" ! [(set (match_operand:SI 0 "s_register_operand" "=r,r") ! (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ! "TARGET_ARM && arm_arch6j" ! "@ ! uxtb%?\\t%0, %1 ! ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" ! [(set_attr "type" "alu_shift,load_byte") ! (set_attr "predicable" "yes") ! (set_attr "pool_range" "*,4096") ! (set_attr "neg_pool_range" "*,4084")] ) (define_insn "*arm_zero_extendqisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (zero_extend:SI (match_operand:QI 1 "s_register_operand" "r")) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "uxtab%?\\t%0, %2, %1" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_shift")] ) (define_split *************** *** 3393,3399 **** "TARGET_EITHER" " { ! if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) { /* Note: We do not have to worry about TARGET_MMU_TRAPS here because the insn below will generate an LDRH instruction --- 3448,3461 ---- "TARGET_EITHER" " { ! if (GET_CODE (operands[1]) == MEM) ! { ! if (TARGET_THUMB) ! { ! emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1])); ! DONE; ! } ! else if (arm_arch4) { /* Note: We do not have to worry about TARGET_MMU_TRAPS here because the insn below will generate an LDRH instruction *************** *** 3403,3449 **** gen_rtx_SIGN_EXTEND (SImode, operands[1]))); DONE; } if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) { emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); DONE; } ! if (arm_emit_extendsi (SIGN_EXTEND, operands[0], operands[1])) ! DONE; if (!s_register_operand (operands[1], HImode)) operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); ! if (TARGET_THUMB) { ! rtx ops[3]; ! ! ops[0] = operands[2]; ! ops[1] = operands[1]; ! ops[2] = GEN_INT (16); ! ! emit_insn (gen_rtx_SET (VOIDmode, ops[0], ! gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); ! ! ops[0] = operands[0]; ! ops[1] = operands[2]; ! ops[2] = GEN_INT (16); ! ! emit_insn (gen_rtx_SET (VOIDmode, ops[0], ! gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); DONE; } }" ) ! (define_insn "*thumb_extendhisi2_insn" [(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_THUMB" "* { rtx ops[4]; --- 3465,3502 ---- gen_rtx_SIGN_EXTEND (SImode, operands[1]))); DONE; } + } if (TARGET_ARM && TARGET_MMU_TRAPS && 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_arch6j) { ! if (TARGET_THUMB) ! emit_insn (gen_thumb_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 "thumb_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_THUMB && !arm_arch6j" "* { rtx ops[4]; *************** *** 3497,3502 **** --- 3550,3628 ---- (set_attr "pool_range" "1020")] ) + ;; We used to have an early-clobber on the scratch register here. + ;; However, there's a bug somewhere in reload which means that this + ;; can be partially ignored during spill allocation if the memory + ;; address also needs reloading; this causes an abort later on when + ;; 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 "*thumb_extendhisi2_insn_v6" + [(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_THUMB && arm_arch6j" + "* + { + rtx ops[4]; + rtx mem; + + if (which_alternative == 0) + return \"sxth\\t%0, %1\"; + + 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; + } + + if (GET_CODE (ops[1]) != REG) + { + debug_rtx (ops[1]); + abort (); + } + + ops[0] = operands[0]; + if (reg_mentioned_p (operands[2], ops[1])) + ops[3] = ops[0]; + else + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; + }" + [(set_attr "length" "2,4") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,1020")] + ) + (define_expand "extendhisi2_mem" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) (set (match_dup 3) *************** *** 3534,3543 **** }" ) ! (define_insn "*arm_extendhisi_insn" [(set (match_operand:SI 0 "s_register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ! "TARGET_ARM && arm_arch4" "ldr%?sh\\t%0, %1" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") --- 3660,3669 ---- }" ) ! (define_insn "*arm_extendhisi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ! "TARGET_ARM && arm_arch4 && !arm_arch6j" "ldr%?sh\\t%0, %1" [(set_attr "type" "load_byte") (set_attr "predicable" "yes") *************** *** 3545,3562 **** (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_extendhisi2_reg" ! [(set (match_operand:SI 0 "s_register_operand" "=r") ! (sign_extend:SI (subreg:HI ! (match_operand:SI 1 "s_register_operand" "r") 0)))] ! "TARGET_EITHER && arm_arch6j" ! "sxth%?\\t%0, %1" ) (define_insn "*arm_extendhisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (sign_extend:SI (subreg:HI ! (match_operand:SI 1 "s_register_operand" "r") 0)) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "sxtah%?\\t%0, %2, %1" --- 3671,3692 ---- (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_extendhisi2_v6" ! [(set (match_operand:SI 0 "s_register_operand" "=r,r") ! (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ! "TARGET_ARM && arm_arch6j" ! "@ ! sxth%?\\t%0, %1 ! ldr%?sh\\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")] ) (define_insn "*arm_extendhisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (sign_extend:SI (match_operand:HI 1 "s_register_operand" "r")) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "sxtah%?\\t%0, %2, %1" *************** *** 3679,3727 **** "TARGET_EITHER" " { ! if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) { ! emit_insn (gen_rtx_SET (VOIDmode, ! operands[0], gen_rtx_SIGN_EXTEND (SImode, operands[1]))); DONE; } ! if (arm_emit_extendsi (SIGN_EXTEND, operands[0], operands[1])) ! DONE; if (!s_register_operand (operands[1], QImode)) operands[1] = copy_to_mode_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); ! if (TARGET_THUMB) { ! rtx ops[3]; ! ! ops[0] = operands[2]; ! 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] = operands[2]; ! ops[2] = GEN_INT (24); ! ! emit_insn (gen_rtx_SET (VOIDmode, ops[0], ! gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); ! DONE; } }" ) ; Rather than restricting all byte accesses to memory addresses that ldrsb ; can handle, we fix up the ones that ldrsb can't grok with a split. ! (define_insn "*arm_extendqisi_insn" [(set (match_operand:SI 0 "s_register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_ARM && arm_arch4" "* /* If the address is invalid, this will split the instruction into two. */ if (bad_signed_byte_operand (operands[1], VOIDmode)) --- 3809,3842 ---- "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_arch6j) { ! 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); }" ) ; Rather than restricting all byte accesses to memory addresses that ldrsb ; can handle, we fix up the ones that ldrsb can't grok with a split. ! (define_insn "*arm_extendqisi" [(set (match_operand:SI 0 "s_register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ! "TARGET_ARM && arm_arch4 && !arm_arch6j" "* /* If the address is invalid, this will split the instruction into two. */ if (bad_signed_byte_operand (operands[1], VOIDmode)) *************** *** 3735,3755 **** (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_extendqisi2_reg" ! [(set (match_operand:SI 0 "s_register_operand" "=r") ! (sign_extend:SI (subreg:QI ! (match_operand:SI 1 "s_register_operand" "r") 0)))] ! "TARGET_EITHER && arm_arch6j" ! "sxtb%?\\t%0, %1" ) (define_insn "*arm_extendqisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (sign_extend:SI (subreg:QI ! (match_operand:SI 1 "s_register_operand" "r") 0)) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "sxtab%?\\t%0, %2, %1" ) (define_split --- 3850,3884 ---- (set_attr "neg_pool_range" "244")] ) ! (define_insn "*arm_extendqisi_v6" ! [(set (match_operand:SI 0 "s_register_operand" "=r,r") ! (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ! "TARGET_ARM && arm_arch6j" ! "* ! if (which_alternative == 0) ! return \"sxtb%?\\t%0, %1\"; ! ! /* If the address is invalid, this will split the instruction into two. */ ! if (bad_signed_byte_operand (operands[1], VOIDmode)) ! return \"#\"; ! ! return \"ldr%?sb\\t%0, %1\"; ! " ! [(set_attr "type" "alu_shift,load_byte") ! (set_attr "predicable" "yes") ! (set_attr "length" "4,8") ! (set_attr "pool_range" "*,256") ! (set_attr "neg_pool_range" "*,244")] ) (define_insn "*arm_extendqisi2addsi" [(set (match_operand:SI 0 "s_register_operand" "=r") ! (plus:SI (sign_extend:SI (match_operand:QI 1 "s_register_operand" "r")) (match_operand:SI 2 "s_register_operand" "r")))] "TARGET_ARM && arm_arch6j" "sxtab%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "predicable" "yes")] ) (define_split *************** *** 3785,3794 **** }" ) ! (define_insn "*thumb_extendqisi2_insn" [(set (match_operand:SI 0 "register_operand" "=l,l") (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] ! "TARGET_THUMB" "* { rtx ops[3]; --- 3914,3923 ---- }" ) ! (define_insn "*thumb_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=l,l") (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] ! "TARGET_THUMB && !arm_arch6j" "* { rtx ops[3]; *************** *** 3862,3867 **** --- 3991,4077 ---- [(set_attr "length" "2,6") (set_attr "type" "load_byte,load_byte") (set_attr "pool_range" "32,32")] + ) + + (define_insn "*thumb_extendqisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l,l") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))] + "TARGET_THUMB && arm_arch6j" + "* + { + 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 if (GET_CODE (b) != REG) + abort (); + else + { + 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")] ) (define_expand "extendsfdf2"