diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -1699,10 +1699,28 @@ if (AM.BaseType == X86ISelAddressMode::FrameIndexBase && !isDispSafeForFrameIndex(Val)) return true; + // In ILP32 (x32) mode, pointers are 32 bits and need to be zero-extended to + // 64 bits. Instructions with 32-bit register addresses perform this zero + // extension for us and we can safely ignore the high bits of Offset. + // Instructions with only a 32-bit immediate address do not, though: they + // sign extend instead. This means only address the low 2GB of address space + // is directly addressable, we need indirect addressing for the high 2GB of + // address space. + // TODO: Some of the earlier checks may be relaxed for ILP32 mode as the + // implicit zero extension of instructions would cover up any problem. + // However, we have asserts elsewhere that get triggered if we do, so keep + // the checks for now. + // TODO: We would actually be able to accept these, as well as the same + // addresses in LP64 mode, by adding the EIZ pseudo-register as an operand + // to get an address size override to be emitted. However, this + // pseudo-register is not part of any register class and therefore causes + // MIR verification to fail. + if (Subtarget->isTarget64BitILP32() && !isUInt<31>(Val) && + !AM.hasBaseOrIndexReg()) + return true; } AM.Disp = Val; return false; - } bool X86DAGToDAGISel::matchLoadInAddress(LoadSDNode *N, X86ISelAddressMode &AM, diff --git a/llvm/test/CodeGen/X86/large-constants-x32.ll b/llvm/test/CodeGen/X86/large-constants-x32.ll --- a/llvm/test/CodeGen/X86/large-constants-x32.ll +++ b/llvm/test/CodeGen/X86/large-constants-x32.ll @@ -4,12 +4,16 @@ define void @constant_expressions() { ; CHECK-LABEL: constant_expressions: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movl -289477652, %eax -; CHECK-NEXT: movl -289477644, %ecx -; CHECK-NEXT: addl -289477648, %eax -; CHECK-NEXT: addl -289477636, %ecx -; CHECK-NEXT: addl %eax, %ecx -; CHECK-NEXT: movl %ecx, -289477652 +; CHECK-NEXT: movl $-289477652, %eax # imm = 0xEEBEEBEC +; CHECK-NEXT: movl (%eax), %ecx +; CHECK-NEXT: movl $-289477644, %edx # imm = 0xEEBEEBF4 +; CHECK-NEXT: movl (%edx), %edx +; CHECK-NEXT: movl $-289477648, %esi # imm = 0xEEBEEBF0 +; CHECK-NEXT: addl (%esi), %ecx +; CHECK-NEXT: movl $-289477636, %esi # imm = 0xEEBEEBFC +; CHECK-NEXT: addl (%esi), %edx +; CHECK-NEXT: addl %ecx, %edx +; CHECK-NEXT: movl %edx, (%eax) ; CHECK-NEXT: retq entry: %0 = load i32, i32* inttoptr (i32 add (i32 -289477652, i32 0) to i32*) @@ -27,12 +31,16 @@ define void @constant_expressions2() { ; CHECK-LABEL: constant_expressions2: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movl -289477652, %eax -; CHECK-NEXT: movl -289477644, %ecx -; CHECK-NEXT: addl -289477648, %eax -; CHECK-NEXT: addl -289477640, %ecx -; CHECK-NEXT: addl %eax, %ecx -; CHECK-NEXT: movl %ecx, -289477652 +; CHECK-NEXT: movl $-289477652, %eax # imm = 0xEEBEEBEC +; CHECK-NEXT: movl (%eax), %ecx +; CHECK-NEXT: movl $-289477644, %edx # imm = 0xEEBEEBF4 +; CHECK-NEXT: movl (%edx), %edx +; CHECK-NEXT: movl $-289477648, %esi # imm = 0xEEBEEBF0 +; CHECK-NEXT: addl (%esi), %ecx +; CHECK-NEXT: movl $-289477640, %esi # imm = 0xEEBEEBF8 +; CHECK-NEXT: addl (%esi), %edx +; CHECK-NEXT: addl %ecx, %edx +; CHECK-NEXT: movl %edx, (%eax) ; CHECK-NEXT: retq entry: %0 = load i32, i32* inttoptr (i32 -289477652 to i32*)