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 @@ -1681,10 +1681,23 @@ 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. + 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 new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/large-constants-x32.ll @@ -0,0 +1,55 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-linux-gnux32 | FileCheck %s + +define void @constant_expressions() { +; CHECK-LABEL: constant_expressions: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl $-289477652, %eax # imm = 0xEEBEEBEC +; CHECK-NEXT: movl (%eax), %ecx +; CHECK-NEXT: movl $-289477636, %edx # imm = 0xEEBEEBFC +; CHECK-NEXT: movl (%edx), %edx +; CHECK-NEXT: movl $-289477644, %esi # imm = 0xEEBEEBF4 +; CHECK-NEXT: addl (%esi), %ecx +; CHECK-NEXT: movl $-289477628, %esi # imm = 0xEEBEEC04 +; 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*) + %1 = load i32, i32* inttoptr (i32 add (i32 -289477652, i32 8) to i32*) + %2 = load i32, i32* inttoptr (i32 add (i32 -289477652, i32 16) to i32*) + %3 = load i32, i32* inttoptr (i32 add (i32 -289477652, i32 24) to i32*) + %4 = add i32 %0, %1 + %5 = add i32 %2, %3 + %6 = add i32 %4, %5 + store i32 %6, i32* inttoptr (i32 add (i32 -289477652, i32 0) to i32*) + ret void +} + + +define void @constant_expressions2() { +; CHECK-LABEL: constant_expressions2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl $-289477652, %eax # imm = 0xEEBEEBEC +; CHECK-NEXT: movl (%eax), %ecx +; CHECK-NEXT: movl $-289477636, %edx # imm = 0xEEBEEBFC +; CHECK-NEXT: movl (%edx), %edx +; CHECK-NEXT: movl $-289477644, %esi # imm = 0xEEBEEBF4 +; CHECK-NEXT: addl (%esi), %ecx +; CHECK-NEXT: movl $-289477628, %esi # imm = 0xEEBEEC04 +; 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*) + %1 = load i32, i32* inttoptr (i32 -289477644 to i32*) + %2 = load i32, i32* inttoptr (i32 -289477636 to i32*) + %3 = load i32, i32* inttoptr (i32 -289477628 to i32*) + %4 = add i32 %0, %1 + %5 = add i32 %2, %3 + %6 = add i32 %4, %5 + store i32 %6, i32* inttoptr (i32 -289477652 to i32*) + ret void +}