Skip to content

Commit 41f430a

Browse files
authored
[X86] Don't fold very large offsets into addr displacements during ISel (#121678)
Doing so can cause the resulting displacement after frame layout to become inexpressible (or cause over/underflow currently during frame layout). Fixes the error reported in #101840 (comment).
1 parent fb2c9d9 commit 41f430a

File tree

3 files changed

+60
-8
lines changed

3 files changed

+60
-8
lines changed

llvm/lib/Target/X86/X86ISelDAGToDAG.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,10 +1800,10 @@ void X86DAGToDAGISel::emitFunctionEntryCode() {
18001800
emitSpecialCodeForMain();
18011801
}
18021802

1803-
static bool isDispSafeForFrameIndex(int64_t Val) {
1804-
// On 64-bit platforms, we can run into an issue where a frame index
1803+
static bool isDispSafeForFrameIndexOrRegBase(int64_t Val) {
1804+
// We can run into an issue where a frame index or a register base
18051805
// includes a displacement that, when added to the explicit displacement,
1806-
// will overflow the displacement field. Assuming that the frame index
1806+
// will overflow the displacement field. Assuming that the
18071807
// displacement fits into a 31-bit integer (which is only slightly more
18081808
// aggressive than the current fundamental assumption that it fits into
18091809
// a 32-bit integer), a 31-bit disp should always be safe.
@@ -1831,7 +1831,7 @@ bool X86DAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
18311831
// In addition to the checks required for a register base, check that
18321832
// we do not try to use an unsafe Disp with a frame index.
18331833
if (AM.BaseType == X86ISelAddressMode::FrameIndexBase &&
1834-
!isDispSafeForFrameIndex(Val))
1834+
!isDispSafeForFrameIndexOrRegBase(Val))
18351835
return true;
18361836
// In ILP32 (x32) mode, pointers are 32 bits and need to be zero-extended to
18371837
// 64 bits. Instructions with 32-bit register addresses perform this zero
@@ -1849,10 +1849,14 @@ bool X86DAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
18491849
// to get an address size override to be emitted. However, this
18501850
// pseudo-register is not part of any register class and therefore causes
18511851
// MIR verification to fail.
1852-
if (Subtarget->isTarget64BitILP32() && !isUInt<31>(Val) &&
1852+
if (Subtarget->isTarget64BitILP32() &&
1853+
!isDispSafeForFrameIndexOrRegBase((uint32_t)Val) &&
18531854
!AM.hasBaseOrIndexReg())
18541855
return true;
1855-
}
1856+
} else if (AM.hasBaseOrIndexReg() && !isDispSafeForFrameIndexOrRegBase(Val))
1857+
// For 32-bit X86, make sure the displacement still isn't close to the
1858+
// expressible limit.
1859+
return true;
18561860
AM.Disp = Val;
18571861
return false;
18581862
}
@@ -2553,7 +2557,7 @@ bool X86DAGToDAGISel::matchAddressRecursively(SDValue N, X86ISelAddressMode &AM,
25532557
case ISD::FrameIndex:
25542558
if (AM.BaseType == X86ISelAddressMode::RegBase &&
25552559
AM.Base_Reg.getNode() == nullptr &&
2556-
(!Subtarget->is64Bit() || isDispSafeForFrameIndex(AM.Disp))) {
2560+
(!Subtarget->is64Bit() || isDispSafeForFrameIndexOrRegBase(AM.Disp))) {
25572561
AM.BaseType = X86ISelAddressMode::FrameIndexBase;
25582562
AM.Base_FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
25592563
return false;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc < %s -mtriple=i386 --frame-pointer=all | FileCheck %s
3+
4+
; ISel will try to fold pointer arithmetic into the address displacement. However, we don't
5+
; want to do that if the offset is very close to the expressible limit because the final frame
6+
; layout may push it over/under the limit.
7+
8+
define i32 @foo(i1 %b) #0 {
9+
; CHECK-LABEL: foo:
10+
; CHECK: # %bb.0: # %entry
11+
; CHECK-NEXT: pushl %ebp
12+
; CHECK-NEXT: .cfi_def_cfa_offset 8
13+
; CHECK-NEXT: .cfi_offset %ebp, -8
14+
; CHECK-NEXT: movl %esp, %ebp
15+
; CHECK-NEXT: .cfi_def_cfa_register %ebp
16+
; CHECK-NEXT: subl $8, %esp
17+
; CHECK-NEXT: movl __stack_chk_guard, %eax
18+
; CHECK-NEXT: movl %eax, -4(%ebp)
19+
; CHECK-NEXT: testb $1, 8(%ebp)
20+
; CHECK-NEXT: jne .LBB0_1
21+
; CHECK-NEXT: # %bb.2: # %entry
22+
; CHECK-NEXT: xorl %eax, %eax
23+
; CHECK-NEXT: jmp .LBB0_3
24+
; CHECK-NEXT: .LBB0_1:
25+
; CHECK-NEXT: movl $-2147483647, %eax # imm = 0x80000001
26+
; CHECK-NEXT: leal -5(%ebp,%eax), %eax
27+
; CHECK-NEXT: .LBB0_3: # %entry
28+
; CHECK-NEXT: movl __stack_chk_guard, %ecx
29+
; CHECK-NEXT: cmpl -4(%ebp), %ecx
30+
; CHECK-NEXT: jne .LBB0_5
31+
; CHECK-NEXT: # %bb.4: # %entry
32+
; CHECK-NEXT: addl $8, %esp
33+
; CHECK-NEXT: popl %ebp
34+
; CHECK-NEXT: .cfi_def_cfa %esp, 4
35+
; CHECK-NEXT: retl
36+
; CHECK-NEXT: .LBB0_5: # %entry
37+
; CHECK-NEXT: .cfi_def_cfa %ebp, 8
38+
; CHECK-NEXT: calll __stack_chk_fail
39+
entry:
40+
%a = alloca i8, align 1
41+
%0 = ptrtoint ptr %a to i32
42+
%sub = add i32 %0, -2147483647
43+
%retval.0 = select i1 %b, i32 %sub, i32 0
44+
ret i32 %retval.0
45+
}
46+
47+
attributes #0 = { sspreq }

llvm/test/CodeGen/X86/xor-lea.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ define i32 @xor_shl_sminval_i32(i32 %x) {
327327
; X86-LABEL: xor_shl_sminval_i32:
328328
; X86: # %bb.0:
329329
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
330-
; X86-NEXT: leal -2147483648(,%eax,8), %eax
330+
; X86-NEXT: movl $-2147483648, %ecx # imm = 0x80000000
331+
; X86-NEXT: leal (%ecx,%eax,8), %eax
331332
; X86-NEXT: retl
332333
;
333334
; X64-LABEL: xor_shl_sminval_i32:

0 commit comments

Comments
 (0)