On Fri, Mar 9, 2012 at 4:26 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Thu, Mar 8, 2012 at 7:20 AM, Uros Bizjak <ubiz...@gmail.com> wrote: >> On Sun, Mar 4, 2012 at 9:13 PM, Uros Bizjak <ubiz...@gmail.com> wrote: >> >>>> We only need to handle zero-extended addresses in DImode. >>>> OK for trunk? >>> >>>> 2012-03-02 H.J. Lu <hongjiu...@intel.com> >>>> >>>> * config/i386/i386.c (ix86_print_operand_address): Only handle >>>> zero-extended DImode addresses. >>> >>> OK. >> >> The patch was reverted due to PR target/52530. >> > > Revert breaks Pmode == SImode for x32. Here is a different patch. > It checks Pmode == DImode instead of TARGET_64BIT. Tested on > Linux/x32. OK for trunk?
This will still emit i.e. "leal 1(%rSImode), %rSImode" on Pmode == SImode targets, so you win nothing really. Attached patch finally decouples LEA operand handling from generic address handling, and by introducing %E operand modifier, we are able to always emit DImode registers for LEAs (which is good anyway to avoid unnecessary addr32 prefixes). Luckily, the "leal 1(%rSImode), %rSImode" triggered some unknown problem with Sun assembler, so we were able to detect the problem. I would like to point out that the patched compiler now also emits address registers in their natural mode (modulo zero-extended RTXes) and fixes following failure on Pmode == SImode targets: --cut here-- struct foo { int *f; int i; }; void __attribute__ ((noinline)) bar (struct foo x) { *(x.f) = 1; } --cut here-- For Pmode == SImode, the compiler emitted (%rdi) address, which was wrong, since "i" was passed in the high part of (%rdi) register. 2012-03-09 Uros Bizjak <ubiz...@gmail.com> PR target/52530 * config/i386/i386.c (ix86_print_operand): Handle 'E' operand modifier. (ix86_print_operand_address): Handle UNSPEC_LEA_ADDR. Do not fallback to set code to 'q'. * config/i386/i386.md (UNSPEC_LEA_ADDR): New unspec. (*movdi_internal_rex64): Use %E operand modifier for lea. (*movsi_internal): Ditto. (*lea_1): Ditto. (*lea<mode>_2): Ditto. (*lea_{3,4,5,6}_zext): Ditto. (*tls_global_dynamic_32_gnu): Ditto. (*tls_global_dynamic_64): Ditto. (*tls_dynamic_gnu2_lea_32): Ditto. (*tls_dynamic_gnu2_lea_64): Ditto. (pro_epilogue_adjust_stack_<mode>_add): Ditto. Patch was tested on x86_64-pc-linux-gnu {,-m32}. I have also eyeballed x32 code (Pmode == SImode) and found no problems. Committed to mainline SVN. H.J., can you please construct a runtime test from the above example code? Uros.
Index: i386.md =================================================================== --- i386.md (revision 185139) +++ i386.md (working copy) @@ -38,6 +38,7 @@ ;; Z -- likewise, with special suffixes for x87 instructions. ;; * -- print a star (in certain assembler syntax) ;; A -- print an absolute memory reference. +;; E -- print address with DImode register names if TARGET_64BIT. ;; w -- print the operand as if it's a "word" (HImode) even if it isn't. ;; s -- print a shift double count, followed by the assemblers argument ;; delimiter. @@ -111,6 +112,7 @@ UNSPEC_MS_TO_SYSV_CALL UNSPEC_CALL_NEEDS_VZEROUPPER UNSPEC_PAUSE + UNSPEC_LEA_ADDR ;; For SSE/MMX support: UNSPEC_FIX_NOTRUNC @@ -1965,7 +1967,7 @@ return "#"; case TYPE_LEA: - return "lea{q}\t{%a1, %0|%0, %a1}"; + return "lea{q}\t{%E1, %0|%0, %E1}"; default: gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); @@ -1974,7 +1976,7 @@ else if (which_alternative == 2) return "movabs{q}\t{%1, %0|%0, %1}"; else if (ix86_use_lea_for_mov (insn, operands)) - return "lea{q}\t{%a1, %0|%0, %a1}"; + return "lea{q}\t{%E1, %0|%0, %E1}"; else return "mov{q}\t{%1, %0|%0, %1}"; } @@ -2206,12 +2208,12 @@ return "movd\t{%1, %0|%0, %1}"; case TYPE_LEA: - return "lea{l}\t{%a1, %0|%0, %a1}"; + return "lea{l}\t{%E1, %0|%0, %E1}"; default: gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); if (ix86_use_lea_for_mov (insn, operands)) - return "lea{l}\t{%a1, %0|%0, %a1}"; + return "lea{l}\t{%E1, %0|%0, %E1}"; else return "mov{l}\t{%1, %0|%0, %1}"; } @@ -5426,7 +5428,7 @@ [(set (match_operand:SI 0 "register_operand" "=r") (subreg:SI (match_operand:DI 1 "lea_address_operand" "p") 0))] "TARGET_64BIT" - "lea{l}\t{%a1, %0|%0, %a1}" + "lea{l}\t{%E1, %0|%0, %E1}" "&& reload_completed && ix86_avoid_lea_for_addr (insn, operands)" [(const_int 0)] { @@ -5440,7 +5442,7 @@ [(set (match_operand:SWI48 0 "register_operand" "=r") (match_operand:SWI48 1 "lea_address_operand" "p"))] "" - "lea{<imodesuffix>}\t{%a1, %0|%0, %a1}" + "lea{<imodesuffix>}\t{%E1, %0|%0, %E1}" "reload_completed && ix86_avoid_lea_for_addr (insn, operands)" [(const_int 0)] { @@ -5455,7 +5457,7 @@ (zero_extend:DI (subreg:SI (match_operand:DI 1 "lea_address_operand" "j") 0)))] "TARGET_64BIT" - "lea{l}\t{%a1, %k0|%k0, %a1}" + "lea{l}\t{%E1, %k0|%k0, %E1}" [(set_attr "type" "lea") (set_attr "mode" "SI")]) @@ -5464,7 +5466,7 @@ (zero_extend:DI (match_operand:SI 1 "lea_address_operand" "j")))] "TARGET_64BIT" - "lea{l}\t{%a1, %k0|%k0, %a1}" + "lea{l}\t{%E1, %k0|%k0, %E1}" [(set_attr "type" "lea") (set_attr "mode" "SI")]) @@ -5474,7 +5476,7 @@ (subreg:DI (match_operand:SI 1 "lea_address_operand" "p") 0) (match_operand:DI 2 "const_32bit_mask" "n")))] "TARGET_64BIT" - "lea{l}\t{%a1, %k0|%k0, %a1}" + "lea{l}\t{%E1, %k0|%k0, %E1}" [(set_attr "type" "lea") (set_attr "mode" "SI")]) @@ -5484,7 +5486,7 @@ (match_operand:DI 1 "lea_address_operand" "p") (match_operand:DI 2 "const_32bit_mask" "n")))] "TARGET_64BIT" - "lea{l}\t{%a1, %k0|%k0, %a1}" + "lea{l}\t{%E1, %k0|%k0, %E1}" [(set_attr "type" "lea") (set_attr "mode" "SI")]) @@ -12541,7 +12543,7 @@ "!TARGET_64BIT && TARGET_GNU_TLS" { output_asm_insn - ("lea{l}\t{%a2@tlsgd(,%1,1), %0|%0, %a2@tlsgd[%1*1]}", operands); + ("lea{l}\t{%E2@tlsgd(,%1,1), %0|%0, %E2@tlsgd[%1*1]}", operands); if (TARGET_SUN_TLS) #ifdef HAVE_AS_IX86_TLSGDPLT return "call\t%a2@tlsgdplt"; @@ -12576,7 +12578,7 @@ if (!TARGET_X32) fputs (ASM_BYTE "0x66\n", asm_out_file); output_asm_insn - ("lea{q}\t{%a1@tlsgd(%%rip), %%rdi|rdi, %a1@tlsgd[rip]}", operands); + ("lea{q}\t{%E1@tlsgd(%%rip), %%rdi|rdi, %E1@tlsgd[rip]}", operands); fputs (ASM_SHORT "0x6666\n", asm_out_file); fputs ("\trex64\n", asm_out_file); if (TARGET_SUN_TLS) @@ -12802,7 +12804,7 @@ (unspec:SI [(match_operand:SI 2 "tls_symbolic_operand" "")] UNSPEC_TLSDESC))))] "!TARGET_64BIT && TARGET_GNU2_TLS" - "lea{l}\t{%a2@TLSDESC(%1), %0|%0, %a2@TLSDESC[%1]}" + "lea{l}\t{%E2@TLSDESC(%1), %0|%0, %E2@TLSDESC[%1]}" [(set_attr "type" "lea") (set_attr "mode" "SI") (set_attr "length" "6") @@ -12864,7 +12866,7 @@ (unspec:DI [(match_operand 1 "tls_symbolic_operand" "")] UNSPEC_TLSDESC))] "TARGET_64BIT && TARGET_GNU2_TLS" - "lea{q}\t{%a1@TLSDESC(%%rip), %0|%0, %a1@TLSDESC[rip]}" + "lea{q}\t{%E1@TLSDESC(%%rip), %0|%0, %E1@TLSDESC[rip]}" [(set_attr "type" "lea") (set_attr "mode" "DI") (set_attr "length" "7") @@ -16614,7 +16616,7 @@ default: operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{<imodesuffix>}\t{%a2, %0|%0, %a2}"; + return "lea{<imodesuffix>}\t{%E2, %0|%0, %E2}"; } } [(set (attr "type") Index: i386.c =================================================================== --- i386.c (revision 185139) +++ i386.c (working copy) @@ -13730,6 +13730,7 @@ get_some_local_dynamic_name (void) Z -- likewise, with special suffixes for x87 instructions. * -- print a star (in certain assembler syntax) A -- print an absolute memory reference. + E -- print address with DImode register names if TARGET_64BIT. w -- print the operand as if it's a "word" (HImode) even if it isn't. s -- print a shift double count, followed by the assemblers argument delimiter. @@ -13806,7 +13807,14 @@ ix86_print_operand (FILE *file, rtx x, int code) ix86_print_operand (file, x, 0); return; + case 'E': + /* Wrap address in an UNSPEC to declare special handling. */ + if (TARGET_64BIT) + x = gen_rtx_UNSPEC (DImode, gen_rtvec (1, x), UNSPEC_LEA_ADDR); + output_address (x); + return; + case 'L': if (ASSEMBLER_DIALECT == ASM_ATT) putc ('l', file); @@ -14418,6 +14426,7 @@ ix86_print_operand_address (FILE *file, rtx addr) int scale; int ok; bool vsib = false; + int code = 0; if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_VSIBADDR) { @@ -14428,6 +14437,12 @@ ix86_print_operand_address (FILE *file, rtx addr) addr = XVECEXP (addr, 0, 0); vsib = true; } + else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_LEA_ADDR) + { + gcc_assert (TARGET_64BIT); + ok = ix86_decompose_address (XVECEXP (addr, 0, 0), &parts); + code = 'q'; + } else ok = ix86_decompose_address (addr, &parts); @@ -14498,16 +14513,16 @@ ix86_print_operand_address (FILE *file, rtx addr) } else { - int code = 0; + /* Print SImode register names for zero-extended + addresses to force addr32 prefix. */ + if (TARGET_64BIT + && (GET_CODE (addr) == ZERO_EXTEND + || GET_CODE (addr) == AND)) + { + gcc_assert (!code); + code = 'l'; + } - /* Print SImode registers for zero-extended addresses to force - addr32 prefix. Otherwise print DImode registers to avoid it. */ - if (TARGET_64BIT) - code = ((GET_CODE (addr) == ZERO_EXTEND - || GET_CODE (addr) == AND) - ? 'l' - : 'q'); - if (ASSEMBLER_DIALECT == ASM_ATT) { if (disp)