[llvm] [LLVM] [X86] Fix integer overflows in frame layout for huge frames (PR #101840)
Wesley Wiser via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 3 20:06:54 PST 2025
wesleywiser wrote:
Apologies for how long it's taken for me to get back to this, I've been looking at it off and on for the last few months in my spare time.
I've reduced the `SystemInfo.cpp` reproducer into a self-contained 482 lines [here](https://gist.github.com/wesleywiser/f7bea9708557647c65cf303a36cdb054) and trimmed the compile flags a bit as well. It can probably be reduced even more but I haven't had much additional luck as the reproducer is very fragile. I think the problematic bit comes from libcxx:
https://github.com/llvm/llvm-project/blob/7c86ab8a18897c434fdb1ee3cd5ff2a71e6aae5a/libcxx/include/sstream#L727-L730
This code is dead code in the reproducer. During instruction selection, I see we optimize an add which is very close to `min(int32_t)` into an `lea`:
```
Optimized legalized selection DAG: %bb.21 '?ParseAMDCatalystDriverVersion@@YA_NABVbasic_string at __Cr@std@@@Z:while.body.i.preheader'
SelectionDAG has 36 nodes:
t0: ch,glue = EntryToken
t18: i32,ch = CopyFromReg t0, Register:i32 %5
t20: i32 = add t18, Constant:i32<-2147483647>
t48: i32 = X86ISD::CMP t20, Constant:i32<0>
t50: i32 = X86ISD::CMOV t20, Constant:i32<1>, TargetConstant:i8<8>, t48
t26: ch = CopyToReg t0, Register:i32 %22, t50
# this add becomes...
t15: i32 = add FrameIndex:i32<0>, Constant:i32<-2147483625>
t10: i32,ch = CopyFromReg t0, Register:i32 %1
t12: i32 = add nuw t10, Constant:i32<2147483647>
t2: i32,ch = CopyFromReg t0, Register:i32 %3
t4: i32 = AssertSext t2, ValueType:ch:i8
t5: i8 = truncate t4
t44: i32 = X86ISD::CMP t5, Constant:i8<0>
t47: i32 = X86ISD::CMOV t15, t12, TargetConstant:i8<8>, t44
t35: i32 = sra t20, Constant:i8<31>
t36: i32 = and t35, Constant:i32<2147483647>
t28: i32 = add t47, t36
t30: ch = CopyToReg t0, Register:i32 %23, t28
t32: ch = TokenFactor t26, t30
t33: ch = br t32, BasicBlock:ch<if.then23.i 0x569e4deeb3c8>
Selected selection DAG: %bb.21 '?ParseAMDCatalystDriverVersion@@YA_NABVbasic_string at __Cr@std@@@Z:while.body.i.preheader'
SelectionDAG has 41 nodes:
t0: ch,glue = EntryToken
t18: i32,ch = CopyFromReg t0, Register:i32 %5
t20: i32,i32 = ADD32ri t18, TargetConstant:i32<-2147483647>
t2: i32,ch = CopyFromReg t0, Register:i32 %3
t58: i32 = COPY_TO_REGCLASS t2, TargetConstant:i32<48>
t5: i8 = EXTRACT_SUBREG t58, TargetConstant:i32<1>
t23: i32 = MOV32ri TargetConstant:i32<1>
t48: i32 = TEST32rr t20, t20
t55: ch,glue = CopyToReg t0, Register:i32 $eflags, t48
t50: i32 = CMOV_GR32 t20, t23, TargetConstant:i8<8>, t55:1
t26: ch = CopyToReg t0, Register:i32 %22, t50
# ... this lea
t15: i32 = LEA32r TargetFrameIndex:i32<0>, TargetConstant:i8<1>, Register:i32 $noreg, TargetConstant:i32<-2147483625>, Register:i16 $noreg
t10: i32,ch = CopyFromReg t0, Register:i32 %1
t12: i32,i32 = ADD32ri nuw t10, TargetConstant:i32<2147483647>
t44: i32 = TEST8rr t5, t5
t53: ch,glue = CopyToReg t0, Register:i32 $eflags, t44
t47: i32 = CMOV_GR32 t15, t12, TargetConstant:i8<8>, t53:1
t35: i32,i32 = SAR32ri t20, TargetConstant:i8<31>
t36: i32,i32 = AND32ri t35, TargetConstant:i32<2147483647>
t28: i32,i32 = ADD32rr t47, t36
t30: ch = CopyToReg t0, Register:i32 %23, t28
t32: ch = TokenFactor t26, t30
t33: ch = JMP_1 BasicBlock:ch<if.then23.i 0x569e4deeb3c8>, t32
```
and then during frame layout, when we adjust the offset to accommodate the frame layout and the frame pointer, we underflow `int32_t` and trigger the (corrected) offset assertion.
It looks like there's already code that tries to handle this kind of thing in X86 ISel here:
https://github.com/llvm/llvm-project/blob/dc3cd2e95ee56cdb75f4d0d0742626f912b5c6f3/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp#L1803-L1811
If I add a check to [`X86DAGToDAGISel::foldOffsetIntoAddress`](https://github.com/llvm/llvm-project/blob/dc3cd2e95ee56cdb75f4d0d0742626f912b5c6f3/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp#L1813C6-L1813C44), then the reproducer no longer asserts and the add isn't converted into an `lea`:
```diff
@@ -1821,7 +1826,11 @@ bool X86DAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
if (Subtarget->isTarget64BitILP32() && !isUInt<31>(Val) &&
!AM.hasBaseOrIndexReg())
return true;
- }
+ }
+ else if (AM.hasBaseOrIndexReg() && ! isDispSafeForFrameIndex(Val))
+ // For 32-bit X86, make sure the displacement still isn't close to the
+ // expressible limit.
+ return true;
AM.Disp = Val;
return false;
}
```
@arsenm does that seem like a reasonable thing to do?
https://github.com/llvm/llvm-project/pull/101840
More information about the llvm-commits
mailing list