Hi This is the second part of the fixing for
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47855 This patch contains the length computation for insn patterns "*arm_movqi_insn" and "*arm_addsi3". Since the alternatives and encodings are much more complex, the attribute length is computed in separate C functions. The patch has been tested on qemu with both ARM and thumb mode. thanks Carrot ChangeLog: 2011-04-08 Wei Guozhi <car...@google.com> PR target/47855 * config/arm/arm-protos.h (arm_attr_length_movqi): New prototype. (arm_attr_length_addsi3): Likewise. * config/arm/arm.c (arm_attr_length_movqi): New function. (arm_attr_length_addsi3): Likewise. * config/arm/arm.md (*arm_movqi_insn): Compute attr "length". (*arm_addsi3): Change "length" computation by calling C function. Index: arm.c =================================================================== --- arm.c (revision 172017) +++ arm.c (working copy) @@ -23694,4 +23694,179 @@ arm_preferred_rename_class (reg_class_t return NO_REGS; } +/* Compute the atrribute "length" of insn "*arm_movqi_insn". + So this function MUST be kept in sync with that insn pattern. */ +int +arm_attr_length_movqi (rtx dst, rtx src) +{ + enum rtx_code dst_code = GET_CODE (dst); + enum rtx_code src_code = GET_CODE (src); + rtx address, reg_op, base; + + /* ARM mode. */ + if (TARGET_ARM) + return 4; + + /* Thumb2 mode. */ + /* Register move. */ + if ((dst_code == REG) && (src_code == REG)) + return 2; + + /* Load an immediate. */ + if ((dst_code == REG) && (src_code == CONST_INT)) + { + HOST_WIDE_INT i = INTVAL (src); + if ((arm_regno_class (REGNO (dst)) == LO_REGS) && (i >= 0) && (i <= 255)) + return 2; + else + return 4; + } + + /* Load/store a byte from/to memory. */ + if ((dst_code == REG) && (src_code == MEM)) + { + reg_op = dst; + address = XEXP (src, 0); + } + else + { + gcc_assert ((dst_code == MEM) && (src_code == REG)); + reg_op = src; + address = XEXP (dst, 0); + } + + if (GET_CODE (address) == PLUS) + { + rtx op1 = XEXP (address, 1); + base = XEXP (address, 0); + if (GET_CODE (op1) == REG) + { + if (arm_regno_class (REGNO (op1)) != LO_REGS) + return 4; + } + else if ((GET_CODE (op1) != CONST_INT) + || (INTVAL (op1) < 0) || (INTVAL (op1) > 31)) + return 4; + } + else + base = address; + + if (GET_CODE (base) != REG) + return 4; + if ((arm_regno_class (REGNO (base)) == LO_REGS) + && (arm_regno_class (REGNO (reg_op)) == LO_REGS)) + return 2; + + return 4; +} + +/* Compute the atrribute "length" of insn "*arm_addsi3". + So this function MUST be kept in sync with that insn pattern. */ +int +arm_attr_length_addsi3 (rtx dst, rtx src1, rtx src2) +{ + HOST_WIDE_INT v; + + /* The splite case. */ + if (which_alternative == 5) + return 16; + + /* ARM mode. */ + if (TARGET_ARM) + return 4; + + /* Thumb2 mode. */ + if (which_alternative == 4) + { + /* SUB (SP minus immediate). */ + v = -INTVAL (src2); + gcc_assert (v >= 0); + if (((v & 3) == 0) && (v < 512)) + return 2; + return 4; + } + else if (which_alternative == 3) + { + /* SUB immediate. */ + HOST_WIDE_INT max_offset = 7; + v = -INTVAL (src2); + gcc_assert (v >= 0); + if (REGNO (dst) == REGNO (src1)) + max_offset = 255; + if ((arm_regno_class (REGNO (dst)) == LO_REGS) + && (arm_regno_class (REGNO (src1)) == LO_REGS) + && (v <= max_offset)) + return 2; + return 4; + } + else if (which_alternative == 1) + { + if (REG_P (src2)) /* ADD SP,SP,<Rm>*/ + return 2; + v = INTVAL (src2); + if (((v & 3) == 0) && (v < 1024)) /* ADD SP,SP,#<imm> */ + return 2; + return 4; + } + else + { + if (which_alternative == 2) + { + rtx tmp = src1; src1 = src2; src2 = tmp; + } + /* Now we are in the most general case, (which_alternative == 0). */ + gcc_assert (REG_P (src1)); + if (REGNO (src1) == SP_REGNUM) + { + if (REG_P (src2)) + { + /* ADD <Rdm>, SP, <Rdm> */ + if (REGNO (src2) == REGNO (src1)) + return 2; + return 4; + } + else + { + gcc_assert (GET_CODE (src2) == CONST_INT); + v = INTVAL (src2); + /* ADD <Rd>, SP, #<imm> */ + if ((arm_regno_class (REGNO (dst)) == LO_REGS) + && ((v & 3) == 0) && (v < 1024)) + return 2; + return 4; + } + } + else + { + if (REG_P (src2)) + { + /* ADD <Rdn>, <Rm> */ + if ((REGNO (dst) == REGNO (src1)) + || (REGNO (dst) == REGNO (src2))) + return 2; + /* ADDS <Rd>, <Rn>, <Rm> */ + else if ((arm_regno_class (REGNO (dst)) == LO_REGS) + && (arm_regno_class (REGNO (src1)) == LO_REGS) + && (arm_regno_class (REGNO (src2)) == LO_REGS)) + return 2; + return 4; + } + else + { + /* ADD immediate. */ + HOST_WIDE_INT max_offset = 7; + gcc_assert (GET_CODE (src2) == CONST_INT); + v = INTVAL (src2); + if (REGNO (dst) == REGNO (src1)) + max_offset = 255; + if ((arm_regno_class (REGNO (dst)) == LO_REGS) + && (arm_regno_class (REGNO (src1)) == LO_REGS) + && (v <= max_offset)) + return 2; + return 4; + } + } + } +} + #include "gt-arm.h" Index: arm-protos.h =================================================================== --- arm-protos.h (revision 172017) +++ arm-protos.h (working copy) @@ -152,6 +152,8 @@ extern void arm_expand_sync (enum machin extern const char *arm_output_memory_barrier (rtx *); extern const char *arm_output_sync_insn (rtx, rtx *); extern unsigned int arm_sync_loop_insns (rtx , rtx *); +extern int arm_attr_length_movqi (rtx, rtx); +extern int arm_attr_length_addsi3 (rtx, rtx, rtx); #if defined TREE_CODE extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree); Index: arm.md =================================================================== --- arm.md (revision 172017) +++ arm.md (working copy) @@ -730,8 +730,10 @@ operands[1], 0); DONE; " - [(set_attr "length" "4,4,4,4,4,16") - (set_attr "predicable" "yes")] + [(set_attr "predicable" "yes") + (set (attr "length") + (symbol_ref + "arm_attr_length_addsi3 (operands[0], operands[1], operands[2])"))] ) (define_insn_and_split "*thumb1_addsi3" @@ -5958,7 +5960,9 @@ str%(b%)\\t%1, %0" [(set_attr "type" "*,*,load1,store1") (set_attr "insn" "mov,mvn,*,*") - (set_attr "predicable" "yes")] + (set_attr "predicable" "yes") + (set (attr "length") + (symbol_ref "arm_attr_length_movqi (operands[0], operands[1])"))] ) (define_insn "*thumb1_movqi_insn"