Skip to content

Commit cf67262

Browse files
committed
[CHERIoT] Fix an issue where large frame indices could cause cause LLVM to generate an offset sequence leading to an invalid pointer.
When the frame is very large, LLVM would try to decompose frame indices by folding the (signed) low 12 bits of the offset into a CIncOffsetImm instruction, materializing the base (containing only the high bits) using an LUI + CIncOffset. This could cause problems when the sign of the low 12 bits did not match the sign of the high bits. In the triggering example, we would generate a sequence which first added a large offset to CSP (taking it out of the representable bounds, clearing the tag) before adding a smaller negative offset to arrive at the intended final offset. The fix is straightforward: disallow this transformation on CHERIoT when the signs of the two offsets do not match.
1 parent 9ac3c7c commit cf67262

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
625625
int64_t Val = Offset.getFixed();
626626
int64_t Lo12 = SignExtend64<12>(Val);
627627
unsigned Opc = MI.getOpcode();
628+
bool Lo12HasSameSign = (Val < 0) == (Lo12 < 0);
628629
if (Opc == RISCV::ADDI && !isInt<12>(Val)) {
629630
// We chose to emit the canonical immediate sequence rather than folding
630631
// the offset into the using add under the theory that doing so doesn't
@@ -644,10 +645,13 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
644645
// instruction will add 4 to the immediate. If that would overflow 12
645646
// bits, we can't fold the offset.
646647
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
647-
} else {
648+
} else if (Lo12HasSameSign || !ST.hasVendorXCheriot()) {
648649
// We can encode an add with 12 bit signed immediate in the immediate
649650
// operand of our user instruction. As a result, the remaining
650651
// offset can by construction, at worst, a LUI and a ADD.
652+
// NOTE: XCheriot requires that the displacement be materialized entirely
653+
// by offset with the same sign, as otherwise we risk invalidating the
654+
// pointer when it goes out of range.
651655
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Lo12);
652656
Offset = StackOffset::get((uint64_t)Val - (uint64_t)Lo12,
653657
Offset.getScalable());
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
; RUN: llc --filetype=asm --mcpu=cheriot --mtriple=riscv32-unknown-unknown -target-abi cheriot -mattr=+xcheri,+xcheripurecap -o - -verify-machineinstrs < %s | FileCheck %s
2+
target datalayout = "e-m:e-p:32:32-i64:64-n32-S128-pf200:64:64:64:32-A200-P200-G200"
3+
target triple = "riscv32-unknown-cheriotrtos"
4+
5+
%struct.b = type { [3 x %struct.c] }
6+
%struct.c = type { [256 x i16] }
7+
8+
; Function Attrs: minsize nounwind optsize
9+
define dso_local void @test() local_unnamed_addr addrspace(200) #0 {
10+
entry:
11+
; CHECK: test:
12+
; CHECK: ct.cincoffset sp, sp, -256
13+
; CHECK: ct.csc ra, 248(sp)
14+
; CHECK: ct.cincoffset sp, sp, -1872
15+
; Verify that the stack offsets are materialized without taking the pointer out of bounds.
16+
; CHECK-NOT: lui a0, 1
17+
; CHECK-NOT: ct.cincoffset a0, sp, a0
18+
; CHECK-NOT: ct.cincoffset a0, a0, -2040
19+
; We have to use increment twice in the same direction instead.
20+
; CHECK: ct.cincoffset a0, sp, 2047
21+
; CHECK: ct.cincoffset a0, a0, 9
22+
; CHECK: ct.cincoffset a1, sp, 520
23+
; CHECK: ct.cincoffset a3, sp, 8
24+
%a = alloca [64 x i8], align 1, addrspace(200)
25+
%b = alloca %struct.b, align 2, addrspace(200)
26+
%c = alloca %struct.c, align 2, addrspace(200)
27+
call void @llvm.lifetime.start.p200(i64 64, ptr addrspace(200) nonnull %a) #3
28+
call void @llvm.lifetime.start.p200(i64 1536, ptr addrspace(200) nonnull %b) #3
29+
call void @llvm.lifetime.start.p200(i64 512, ptr addrspace(200) nonnull %c) #3
30+
call void @foo(ptr addrspace(200) noundef nonnull %c, ptr addrspace(200) noundef nonnull %b, ptr addrspace(200) noundef nonnull %a) #4
31+
call void @llvm.lifetime.end.p200(i64 512, ptr addrspace(200) nonnull %c) #3
32+
call void @llvm.lifetime.end.p200(i64 1536, ptr addrspace(200) nonnull %b) #3
33+
call void @llvm.lifetime.end.p200(i64 64, ptr addrspace(200) nonnull %a) #3
34+
ret void
35+
}
36+
37+
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
38+
declare void @llvm.lifetime.start.p200(i64 immarg, ptr addrspace(200) captures(none)) addrspace(200) #1
39+
40+
; Function Attrs: minsize optsize
41+
declare dso_local void @foo(ptr addrspace(200) noundef, ptr addrspace(200) noundef, ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2
42+
43+
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
44+
declare void @llvm.lifetime.end.p200(i64 immarg, ptr addrspace(200) captures(none)) addrspace(200) #1
45+
46+
attributes #0 = { minsize nounwind optsize "cheri-compartment"="scheduler" "no-builtin-longjmp" "no-builtin-printf" "no-builtin-setjmp" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cheriot-ibex" "target-features"="+32bit,+b,+c,+e,+m,+relax,+unaligned-scalar-mem,+xcheri,+xcheriot,+xcheripurecap,+zba,+zbb,+zbkb,+zbkc,+zbs,+zca,+zmmul,-a,-d,-experimental-p,-experimental-smctr,-experimental-ssctr,-experimental-svukte,-experimental-xqccmp,-experimental-xqcia,-experimental-xqciac,-experimental-xqcibi,-experimental-xqcibm,-experimental-xqcicli,-experimental-xqcicm,-experimental-xqcics,-experimental-xqcicsr,-experimental-xqciint,-experimental-xqciio,-experimental-xqcilb,-experimental-xqcili,-experimental-xqcilia,-experimental-xqcilo,-experimental-xqcilsm,-experimental-xqcisim,-experimental-xqcisls,-experimental-xqcisync,-experimental-xrivosvisni,-experimental-xrivosvizip,-experimental-xsfmclic,-experimental-xsfsclic,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-experimental-zvqdotq,-f,-h,-i,-q,-sdext,-sdtrig,-sha,-shcounterenw,-shgatpa,-shlcofideleg,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcntrpmf,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-v,-xandesbfhcvt,-xandesperf,-xandesvbfhcvt,-xandesvdot,-xandesvpackfph,-xandesvsintload,-xcheri-norvc,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xmipscbop,-xmipscmov,-xmipslsp,-xsfcease,-xsfmm128t,-xsfmm16t,-xsfmm32a16f,-xsfmm32a32f,-xsfmm32a8f,-xsfmm32a8i,-xsfmm32t,-xsfmm64a64f,-xsfmm64t,-xsfmmbase,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zacas,-zalrsc,-zama16b,-zawrs,-zbc,-zbkx,-zcb,-zcd,-zce,-zcf,-zclsd,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccamoc,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zilsd,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" }
47+
attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
48+
attributes #2 = { minsize optsize "cheri-compartment"="scheduler" "no-builtin-longjmp" "no-builtin-printf" "no-builtin-setjmp" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cheriot-ibex" "target-features"="+32bit,+b,+c,+e,+m,+relax,+unaligned-scalar-mem,+xcheri,+xcheriot,+xcheripurecap,+zba,+zbb,+zbkb,+zbkc,+zbs,+zca,+zmmul,-a,-d,-experimental-p,-experimental-smctr,-experimental-ssctr,-experimental-svukte,-experimental-xqccmp,-experimental-xqcia,-experimental-xqciac,-experimental-xqcibi,-experimental-xqcibm,-experimental-xqcicli,-experimental-xqcicm,-experimental-xqcics,-experimental-xqcicsr,-experimental-xqciint,-experimental-xqciio,-experimental-xqcilb,-experimental-xqcili,-experimental-xqcilia,-experimental-xqcilo,-experimental-xqcilsm,-experimental-xqcisim,-experimental-xqcisls,-experimental-xqcisync,-experimental-xrivosvisni,-experimental-xrivosvizip,-experimental-xsfmclic,-experimental-xsfsclic,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-experimental-zvqdotq,-f,-h,-i,-q,-sdext,-sdtrig,-sha,-shcounterenw,-shgatpa,-shlcofideleg,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcntrpmf,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-v,-xandesbfhcvt,-xandesperf,-xandesvbfhcvt,-xandesvdot,-xandesvpackfph,-xandesvsintload,-xcheri-norvc,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xmipscbop,-xmipscmov,-xmipslsp,-xsfcease,-xsfmm128t,-xsfmm16t,-xsfmm32a16f,-xsfmm32a32f,-xsfmm32a8f,-xsfmm32a8i,-xsfmm32t,-xsfmm64a64f,-xsfmm64t,-xsfmmbase,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zacas,-zalrsc,-zama16b,-zawrs,-zbc,-zbkx,-zcb,-zcd,-zce,-zcf,-zclsd,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccamoc,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zilsd,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" }
49+
attributes #3 = { nounwind }
50+
attributes #4 = { minsize nounwind optsize "no-builtin-longjmp" "no-builtin-printf" "no-builtin-setjmp" }
51+
52+
!llvm.module.flags = !{!0, !1, !2, !4}
53+
!llvm.ident = !{!5}
54+
55+
!0 = !{i32 1, !"wchar_size", i32 2}
56+
!1 = !{i32 1, !"target-abi", !"cheriot"}
57+
!2 = !{i32 6, !"riscv-isa", !3}
58+
!3 = !{!"rv32e2p0_m2p0_c2p0_b1p0_zmmul1p0_zca1p0_zba1p0_zbb1p0_zbkb1p0_zbkc1p0_zbs1p0_xcheri0p0_xcheriot1p0_xcheripurecap0p0"}
59+
!4 = !{i32 8, !"SmallDataLimit", i32 0}
60+
!5 = !{!"clang version 21.1.7 ([email protected]:resistor/llvm-project-1.git 9ac3c7cfe2ca1ca95cebf8aa89eea8c18c13fc3d)"}

0 commit comments

Comments
 (0)