Hi, TARGET_MEM_REF only works on ptr_mode. That means base and index parts of x86 address operand in x32 mode may be in ptr_mode. This patch supports 32bit base and index parts in x32 mode. OK for trunk?
Thanks. H.J. --- 2011-07-09 H.J. Lu <hongjiu...@intel.com> * config/i386/i386.c (ix86_simplify_base_index_disp): New. (ix86_decompose_address): Support 32bit address in x32 mode. (ix86_legitimate_address_p): Likewise. (ix86_fixup_binary_operands): Likewise. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 04cb07d..c852719 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -10984,6 +11010,190 @@ ix86_live_on_entry (bitmap regs) } } +/* For TARGET_X32, IRA may generate + + (set (reg:SI 40 r11) + (plus:SI (plus:SI (mult:SI (reg:SI 1 dx) + (const_int 8)) + (subreg:SI (plus:DI (reg/f:DI 7 sp) + (const_int CONST1)) 0)) + (const_int CONST2))) + + We translate it into + + (set (reg:SI 40 r11) + (plus:SI (plus:SI (mult:SI (reg:SI 1 dx) + (const_int 8)) + (reg/f:SI 7 sp)) + (const_int [CONST1 + CONST2]))) + + We also translate + + (plus:DI (zero_extend:DI (plus:SI (plus:SI (reg:SI 4 si [70]) + (reg:SI 2 cx [86])) + (const_int CONST1))) + (const_int CONST2)) + + into + + (plus:DI (zero_extend:DI (plus:SI (reg:SI 4 si [70]) + (reg:SI 2 cx [86])) + (const_int [CONST1 + CONST2]))) + + We also translate + + (plus:SI (plus:SI (plus:SI (reg:SI 4 si [70]) + (reg:SI 2 cx [86])) + (symbol_ref:SI ("A.193.2210"))) + (const_int CONST)) + + into + + (plus:SI (plus:SI (reg:SI 4 si [70]) + (reg:SI 2 cx [86])) + (const (plus:SI (symbol_ref:SI ("A.193.2210")) + (const_int CONST)))) + + We also translate + + (plus:SI (reg:SI 0 ax [orig:74 D.4067 ] [74]) + (subreg:SI (plus:DI (reg/f:DI 7 sp) + (const_int 64 [0x40])) 0)) + + into + + (plus:SI (reg:SI 0 ax [orig:74 D.4067 ] [74]) + (plus:SI (reg/f:SI 7 sp) (const_int 64 [0x40]))) + + If PLUS is true, we also translate + + (set (reg:SI 40 r11) + (plus:SI (plus:SI (reg:SI 1 dx) + (subreg:SI (plus:DI (reg/f:DI 7 sp) + (const_int CONST1)) 0)) + (const_int CONST2))) + + into + + (set (reg:SI 40 r11) + (plus:SI (plus:SI (reg:SI 1 dx) + (reg/f:SI 7 sp)) + (const_int [CONST1 + CONST2]))) + + */ + +static void +ix86_simplify_base_index_disp (rtx *base_p, rtx *index_p, rtx *disp_p, + bool plus) +{ + rtx base = *base_p; + rtx disp, index, op0, op1; + + if (!base || GET_MODE (base) != ptr_mode) + return; + + disp = *disp_p; + if (disp != NULL_RTX + && disp != const0_rtx + && !CONST_INT_P (disp)) + return; + + if (GET_CODE (base) == SUBREG) + base = SUBREG_REG (base); + + if (GET_CODE (base) == PLUS) + { + rtx addend; + + op0 = XEXP (base, 0); + op1 = XEXP (base, 1); + + if ((REG_P (op0) + || (!plus + && GET_CODE (op0) == PLUS + && GET_MODE (op0) == ptr_mode + && REG_P (XEXP (op0, 0)) + && REG_P (XEXP (op0, 1)))) + && (CONST_INT_P (op1) + || GET_CODE (op1) == SYMBOL_REF + || GET_CODE (op1) == LABEL_REF)) + { + base = op0; + addend = op1; + } + else if (REG_P (op1) + && (CONST_INT_P (op0) + || GET_CODE (op0) == SYMBOL_REF + || GET_CODE (op0) == LABEL_REF)) + { + base = op1; + addend = op0; + } + else if (plus + && GET_CODE (op1) == SUBREG + && GET_MODE (op1) == ptr_mode) + { + op1 = SUBREG_REG (op1); + if (GET_CODE (op1) == PLUS) + { + addend = XEXP (op1, 1); + op1 = XEXP (op1, 0); + if (REG_P (op1) && CONST_INT_P (addend)) + { + op1 = gen_rtx_REG (ptr_mode, REGNO (op1)); + *base_p = gen_rtx_PLUS (ptr_mode, op0, op1); + } + else + return; + } + else + return; + } + else + return; + + if (disp == NULL_RTX || disp == const0_rtx) + *disp_p = addend; + else + { + if (CONST_INT_P (addend)) + *disp_p = GEN_INT (INTVAL (disp) + INTVAL (addend)); + else + { + disp = gen_rtx_PLUS (ptr_mode, addend, disp); + *disp_p = gen_rtx_CONST (ptr_mode, disp); + } + } + + if (!plus) + { + if (REG_P (base)) + *base_p = gen_rtx_REG (ptr_mode, REGNO (base)); + else + *base_p = base; + } + } + else if (!plus + && (disp == NULL_RTX || disp == const0_rtx) + && index_p + && (index = *index_p) != NULL_RTX + && GET_CODE (index) == SUBREG + && GET_MODE (index) == ptr_mode) + { + index = SUBREG_REG (index); + if (GET_CODE (index) == PLUS && GET_MODE (index) == Pmode) + { + op0 = XEXP (index, 0); + op1 = XEXP (index, 1); + if (REG_P (op0) && CONST_INT_P (op1)) + { + *index_p = gen_rtx_REG (ptr_mode, REGNO (op0)); + *disp_p = op1; + } + } + } +} + /* Extract the parts of an RTL expression that is a valid memory address for an instruction. Return 0 if the structure of the address is grossly off. Return -1 if the address contains ASHIFT, so it is not @@ -11000,6 +11210,13 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) int retval = 1; enum ix86_address_seg seg = SEG_DEFAULT; + /* Support 32bit address in x32 mode. */ + if (TARGET_X32 + && GET_CODE (addr) == ZERO_EXTEND + && GET_MODE (addr) == Pmode + && GET_CODE (XEXP (addr, 0)) == PLUS) + addr = XEXP (addr, 0); + if (REG_P (addr) || GET_CODE (addr) == SUBREG) base = addr; else if (GET_CODE (addr) == PLUS) @@ -11014,6 +11231,24 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) return 0; addends[n++] = XEXP (op, 1); op = XEXP (op, 0); + /* Support 32bit address in x32 mode. */ + if (TARGET_X32 && reload_completed) + { + if (GET_CODE (op) == ZERO_EXTEND + && GET_MODE (op) == Pmode + && GET_CODE (XEXP (op, 0)) == PLUS) + { + op = XEXP (op, 0); + if (n == 1) + ix86_simplify_base_index_disp (&op, NULL, + &addends[0], false); + } + else if (n == 1 + && GET_CODE (op) == PLUS + && GET_MODE (op) == ptr_mode) + ix86_simplify_base_index_disp (&op, NULL, &addends[0], + true); + } } while (GET_CODE (op) == PLUS); if (n >= 4) @@ -11107,13 +11342,17 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) scale = INTVAL (scale_rtx); } - base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base; - index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index; + if (TARGET_X32 && reload_completed) + ix86_simplify_base_index_disp (&base, &index, &disp, false); /* Avoid useless 0 displacement. */ if (disp == const0_rtx && (base || index)) disp = NULL_RTX; + index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index; + + base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base; + /* Allow arg pointer and stack pointer as index if there is not scaling. */ if (base_reg && index_reg && scale == 1 && (index_reg == arg_pointer_rtx @@ -11522,6 +11761,7 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, struct ix86_address parts; rtx base, index, disp; HOST_WIDE_INT scale; + enum machine_mode base_mode; if (ix86_decompose_address (addr, &parts) <= 0) /* Decomposition failed. */ @@ -11553,8 +11793,11 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, /* Base is not a register. */ return false; - if (GET_MODE (base) != Pmode) - /* Base is not in Pmode. */ + base_mode = GET_MODE (base); + if (base_mode != Pmode + && !(TARGET_X32 + && base_mode == ptr_mode)) + /* Base is not in Pmode nor ptr_mode. */ return false; if ((strict && ! REG_OK_FOR_BASE_STRICT_P (reg)) @@ -11562,6 +11805,8 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, /* Base is not valid. */ return false; } + else + base_mode = VOIDmode; /* Validate index register. @@ -11570,6 +11815,7 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, if (index) { rtx reg; + enum machine_mode index_mode; if (REG_P (index)) reg = index; @@ -11582,8 +11828,13 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, /* Index is not a register. */ return false; - if (GET_MODE (index) != Pmode) - /* Index is not in Pmode. */ + index_mode = GET_MODE (index); + if ((base_mode != VOIDmode + && base_mode != index_mode) + || (index_mode != Pmode + && !(TARGET_X32 + && index_mode == ptr_mode))) + /* Index is not in Pmode nor ptr_mode. */ return false; if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (reg)) @@ -15461,6 +15757,16 @@ ix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode, else src2 = force_reg (mode, src2); } + else + { + /* Support 32bit address in x32 mode. */ + if (TARGET_X32 + && code == PLUS + && !MEM_P (dst) + && !MEM_P (src1) + && MEM_P (src2) ) + src2 = force_reg (mode, src2); + } /* If the destination is memory, and we do not have matching source operands, do things in registers. */