aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorH.J. Lu <hjl@gcc.gnu.org>2012-11-13 10:35:32 -0800
committerH.J. Lu <hjl@gcc.gnu.org>2012-11-13 10:35:32 -0800
commitd10e419bebe07f5506836ea65ab7638321305305 (patch)
treee85c5539e0ff5c7572a0fa5cadd12da746ddc2fc /gcc/config
parent141a9e06ad6d6f7d57f33435bd12c4df20cec0db (diff)
downloadgcc-d10e419bebe07f5506836ea65ab7638321305305.zip
gcc-d10e419bebe07f5506836ea65ab7638321305305.tar.gz
gcc-d10e419bebe07f5506836ea65ab7638321305305.tar.bz2
Workaround PR middle-end/55142
gcc/ 2012-11-13 Eric Botcazou <ebotcazou@adacore.com> H.J. Lu <hongjiu.lu@intel.com> PR middle-end/55142 * config/i386/i386.c (legitimize_pic_address): Properly handle REG + CONST. (ix86_print_operand_address): Set code to 'k' when forcing addr32 prefix. For x32, zero-extend negative displacement if it < -16*1024*1024. gcc/testsuite/ 2012-11-13 H.J. Lu <hongjiu.lu@intel.com> PR middle-end/55142 * gcc.target/i386/pr55142-1.c: New file. * gcc.target/i386/pr55142-2.c: Likewise. From-SVN: r193483
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/i386/i386.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 6da59814..3af1cf8 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -12203,7 +12203,6 @@ legitimize_pic_address (rtx orig, rtx reg)
{
rtx addr = orig;
rtx new_rtx = orig;
- rtx base;
#if TARGET_MACHO
if (TARGET_MACHO && !TARGET_64BIT)
@@ -12408,20 +12407,33 @@ legitimize_pic_address (rtx orig, rtx reg)
}
else
{
- base = legitimize_pic_address (XEXP (addr, 0), reg);
- new_rtx = legitimize_pic_address (XEXP (addr, 1),
- base == reg ? NULL_RTX : reg);
+ rtx base = legitimize_pic_address (op0, reg);
+ enum machine_mode mode = GET_MODE (base);
+ new_rtx
+ = legitimize_pic_address (op1, base == reg ? NULL_RTX : reg);
if (CONST_INT_P (new_rtx))
- new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx));
+ {
+ if (INTVAL (new_rtx) < -16*1024*1024
+ || INTVAL (new_rtx) >= 16*1024*1024)
+ {
+ if (!x86_64_immediate_operand (new_rtx, mode))
+ new_rtx = force_reg (mode, new_rtx);
+ new_rtx
+ = gen_rtx_PLUS (mode, force_reg (mode, base), new_rtx);
+ }
+ else
+ new_rtx = plus_constant (mode, base, INTVAL (new_rtx));
+ }
else
{
- if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
+ if (GET_CODE (new_rtx) == PLUS
+ && CONSTANT_P (XEXP (new_rtx, 1)))
{
- base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
+ base = gen_rtx_PLUS (mode, base, XEXP (new_rtx, 0));
new_rtx = XEXP (new_rtx, 1);
}
- new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
+ new_rtx = gen_rtx_PLUS (mode, base, new_rtx);
}
}
}
@@ -14510,7 +14522,30 @@ ix86_print_operand_address (FILE *file, rtx addr)
}
#endif
gcc_assert (!code);
- code = 'l';
+ code = 'k';
+ }
+ else if (code == 0
+ && TARGET_X32
+ && disp
+ && CONST_INT_P (disp)
+ && INTVAL (disp) < -16*1024*1024)
+ {
+ /* X32 runs in 64-bit mode, where displacement, DISP, in
+ address DISP(%r64), is encoded as 32-bit immediate sign-
+ extended from 32-bit to 64-bit. For -0x40000300(%r64),
+ address is %r64 + 0xffffffffbffffd00. When %r64 <
+ 0x40000300, like 0x37ffe064, address is 0xfffffffff7ffdd64,
+ which is invalid for x32. The correct address is %r64
+ - 0x40000300 == 0xf7ffdd64. To properly encode
+ -0x40000300(%r64) for x32, we zero-extend negative
+ displacement by forcing addr32 prefix which truncates
+ 0xfffffffff7ffdd64 to 0xf7ffdd64. In theory, we should
+ zero-extend all negative displacements, including -1(%rsp).
+ However, for small negative displacements, sign-extension
+ won't cause overflow. We only zero-extend negative
+ displacements if they < -16*1024*1024, which is also used
+ to check legitimate address displacements for PIC. */
+ code = 'k';
}
if (ASSEMBLER_DIALECT == ASM_ATT)