Skip to content

Commit ebe98ff

Browse files
arichardsonresistor
authored andcommitted
[InstSimplify] Simplify @llvm.cheri.cap.high.get
As part of this refactor some of the CHERI get intrinsics folding code. This refactoring introduces a minor change to getoffset folding as well: we no longer fold arbitrary getoffset(setoffset(A, B)) -> B since the setoffset could have changed the bounds interpretation and therefore also the result. This optimization is unlikely to make a difference in practice and is somewhat incorrect so I believe dropping it makes sense.
1 parent 2f79e06 commit ebe98ff

File tree

8 files changed

+68
-47
lines changed

8 files changed

+68
-47
lines changed

clang/test/CodeGen/cheri/vaddr-mode.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ long write_uintcap(__uintcap_t *cap) {
4848
// OFFSET-NEXT: entry:
4949
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
5050
// OFFSET-NEXT: [[AND:%.*]] = and i64 [[TMP0]], 3
51-
// OFFSET-NEXT: ret i64 [[AND]]
51+
// OFFSET-NEXT: [[TMP1:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[AND]])
52+
// OFFSET-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP1]])
53+
// OFFSET-NEXT: ret i64 [[TMP2]]
5254
//
5355
long get_low_bits(__uintcap_t cap) {
5456
return cap & 3;
@@ -126,7 +128,9 @@ __uintcap_t xor_uintcap(__uintcap_t cap, __uintcap_t cap2) {
126128
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
127129
// OFFSET-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP2:%.*]])
128130
// OFFSET-NEXT: [[XOR:%.*]] = xor i64 [[TMP1]], [[TMP0]]
129-
// OFFSET-NEXT: ret i64 [[XOR]]
131+
// OFFSET-NEXT: [[TMP2:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[XOR]])
132+
// OFFSET-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP2]])
133+
// OFFSET-NEXT: ret i64 [[TMP3]]
130134
//
131135
long xor_uintcap_return_long(__uintcap_t cap, __uintcap_t cap2) {
132136
return cap ^ cap2;
@@ -160,7 +164,9 @@ __uintcap_t modulo_return_uintcap(__uintcap_t cap) {
160164
// OFFSET-NEXT: entry:
161165
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
162166
// OFFSET-NEXT: [[REM:%.*]] = and i64 [[TMP0]], 31
163-
// OFFSET-NEXT: ret i64 [[REM]]
167+
// OFFSET-NEXT: [[TMP1:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[REM]])
168+
// OFFSET-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP1]])
169+
// OFFSET-NEXT: ret i64 [[TMP2]]
164170
//
165171
long modulo_return_long(__uintcap_t cap) {
166172
return cap % 32;

llvm/include/llvm/IR/CheriIntrinsics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ correspondingSetIntrinsic(Intrinsic::ID GetIntrin) {
3030
return Intrinsic::cheri_cap_address_set;
3131
case Intrinsic::cheri_cap_flags_get:
3232
return Intrinsic::cheri_cap_flags_set;
33+
case Intrinsic::cheri_cap_high_get:
34+
return Intrinsic::cheri_cap_high_set;
3335
default:
3436
llvm_unreachable("No matching set intrinsic");
3537
}
@@ -43,6 +45,8 @@ correspondingGetIntrinsic(Intrinsic::ID SetIntrin) {
4345
return Intrinsic::cheri_cap_address_get;
4446
case Intrinsic::cheri_cap_flags_set:
4547
return Intrinsic::cheri_cap_flags_get;
48+
case Intrinsic::cheri_cap_high_set:
49+
return Intrinsic::cheri_cap_high_get;
4650
default:
4751
llvm_unreachable("No matching get intrinsic");
4852
}

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6366,26 +6366,45 @@ stripAndAccumulateGEPsAndPointerCastsSameRepr(Value *V, const DataLayout &DL,
63666366
return Result;
63676367
}
63686368

6369+
// Common helper to fold llvm.cheri.get.foo intrinsics
63696370
template <Intrinsic::ID Intrin>
6370-
static Value *inferCapabilityOffsetOrAddr(Value *V, Type *ResultTy,
6371-
const DataLayout &DL) {
6371+
static Value *foldCheriGetSetPair(Value *V, Type *ResultTy,
6372+
const DataLayout &DL) {
63726373
constexpr Intrinsic::ID SetIntrin = cheri::correspondingSetIntrinsic(Intrin);
6373-
// Try to infer the offset/address from a prior setoffset/setaddr value
6374+
// getFoo(setFoo(A, B)) -> B
6375+
// This is true for address and high, but not necessarily true for flags and
6376+
// offset since setflags truncates the value and setoffset may change the
6377+
// bounds representation (and thus the offset) if it is significantly OOB.
6378+
constexpr bool SetUpdatesAllGetBits =
6379+
SetIntrin != Intrinsic::cheri_cap_offset_set &&
6380+
SetIntrin != Intrinsic::cheri_cap_flags_set;
63746381
Value *IntrinArg = nullptr;
6375-
// getaddr(setaddr(A, B)) -> B and getoffset(setoffset(A, B)) -> B
6376-
if (match(V, m_Intrinsic<SetIntrin>(m_Value(), m_Value(IntrinArg)))) {
6377-
return IntrinArg;
6378-
}
6379-
// get{addr,offset}(setaddr(NULL, B)) -> B
6380-
if (match(V, m_Intrinsic<Intrinsic::cheri_cap_address_set>(
6381-
m_Zero(), m_Value(IntrinArg)))) {
6382+
if (SetUpdatesAllGetBits &&
6383+
match(V, m_Intrinsic<SetIntrin>(m_Value(), m_Value(IntrinArg)))) {
63826384
return IntrinArg;
63836385
}
6384-
// get{addr,offset}(setoffset(NULL, B)) -> B
6385-
if (match(V, m_Intrinsic<Intrinsic::cheri_cap_offset_set>(
6386-
m_Zero(), m_Value(IntrinArg)))) {
6387-
return IntrinArg;
6386+
// All intrinsics we call this function for return zero for NULL inputs.
6387+
// In fact, we can extend this to any input derived from NULL where the only
6388+
// operations have been address manipulations (unless we are retrieving a
6389+
// result depending on the address), since those cannot affect non-bounds
6390+
// capability metadata.
6391+
constexpr bool CanIgnoreAddressManipulation =
6392+
Intrin != Intrinsic::cheri_cap_address_get &&
6393+
Intrin != Intrinsic::cheri_cap_offset_get;
6394+
Value *Base = CanIgnoreAddressManipulation
6395+
? getBasePtrIgnoringCapabilityAddressManipulation(V, DL)
6396+
: V->stripPointerCastsSameRepresentation();
6397+
if (isa<ConstantPointerNull>(Base)) {
6398+
return Constant::getNullValue(ResultTy);
63886399
}
6400+
return nullptr;
6401+
}
6402+
6403+
template <Intrinsic::ID Intrin>
6404+
static Value *inferCapabilityOffsetOrAddr(Value *V, Type *ResultTy,
6405+
const DataLayout &DL) {
6406+
if (Value *Ret = foldCheriGetSetPair<Intrin>(V, ResultTy, DL))
6407+
return Ret;
63896408

63906409
APInt OffsetAPInt(DL.getIndexTypeSizeInBits(V->getType()), 0);
63916410
// Look through pointer casts and accumulate constant GEPs:
@@ -6419,6 +6438,7 @@ static Value *inferCapabilityOffsetOrAddr(Value *V, Type *ResultTy,
64196438
// We can also fold chains of constant GEPS:
64206439
// For example: getoffset(GEP(setoffset(A, Const1), 100) -> Const1 + 100
64216440
ConstantInt *ConstSetArg;
6441+
constexpr Intrinsic::ID SetIntrin = cheri::correspondingSetIntrinsic(Intrin);
64226442
if (match(BasePtr,
64236443
m_Intrinsic<SetIntrin>(m_Value(), m_ConstantInt(ConstSetArg)))) {
64246444
return ConstantInt::get(ResultTy, ConstSetArg->getValue() + OffsetAPInt);
@@ -6472,7 +6492,6 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
64726492
return Constant::getNullValue(F->getReturnType());
64736493
break;
64746494
case Intrinsic::cheri_cap_sealed_get:
6475-
case Intrinsic::cheri_cap_flags_get:
64766495
case Intrinsic::cheri_cap_base_get:
64776496
// Values derived from NULL and where the only operations that have been
64786497
// applied are address manipulations, always have the following properties:
@@ -6510,6 +6529,18 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
65106529
Op0, F->getReturnType(), Q.DL))
65116530
return V;
65126531
break;
6532+
case Intrinsic::cheri_cap_flags_get: {
6533+
if (auto *Ret = foldCheriGetSetPair<Intrinsic::cheri_cap_flags_get>(
6534+
Op0, F->getReturnType(), Q.DL))
6535+
return Ret;
6536+
break;
6537+
}
6538+
case Intrinsic::cheri_cap_high_get: {
6539+
if (auto *Ret = foldCheriGetSetPair<Intrinsic::cheri_cap_high_get>(
6540+
Op0, F->getReturnType(), Q.DL))
6541+
return Ret;
6542+
break;
6543+
}
65136544
case Intrinsic::cheri_cap_offset_get:
65146545
if (auto *V = inferCapabilityOffsetOrAddr<Intrinsic::cheri_cap_offset_get>(
65156546
Op0, F->getReturnType(), Q.DL))

llvm/test/CodeGen/CHERI-Generic/Inputs/cheri-intrinsics-folding-broken-module-regression.ll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
; This used to create a broken function.
2-
; FIXME: the getoffset+add sequence should be folded to an increment
3-
; REQUIRES: mips-registered-target
42
; RUN: opt @PURECAP_HARDFLOAT_ARGS@ -S -passes=instcombine %s -o - | FileCheck %s
53
; RUN: opt @PURECAP_HARDFLOAT_ARGS@ -S '-passes=default<O3>' %s | llc @PURECAP_HARDFLOAT_ARGS@ -O3 -o - | FileCheck %s --check-prefix ASM
64
target datalayout = "@PURECAP_DATALAYOUT@"

llvm/test/CodeGen/CHERI-Generic/MIPS/cheri-intrinsics-folding-broken-module-regression.ll

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2
22
; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/cheri-intrinsics-folding-broken-module-regression.ll
33
; This used to create a broken function.
4-
; FIXME: the getoffset+add sequence should be folded to an increment
5-
; REQUIRES: mips-registered-target
64
; RUN: opt -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap -S -passes=instcombine %s -o - | FileCheck %s
75
; RUN: opt -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap -S '-passes=default<O3>' %s | llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap -O3 -o - | FileCheck %s --check-prefix ASM
86
target datalayout = "E-m:e-pf200:128:128:128:64-i8:8:32-i16:16:32-i64:64-n32:64-S128-A200-P200-G200"
@@ -23,13 +21,10 @@ define void @g(i64 %x, i64 %y) addrspace(200) nounwind {
2321
; ASM-NEXT: lui $1, %pcrel_hi(_CHERI_CAPABILITY_TABLE_-8)
2422
; ASM-NEXT: daddiu $1, $1, %pcrel_lo(_CHERI_CAPABILITY_TABLE_-4)
2523
; ASM-NEXT: cgetpccincoffset $c1, $1
26-
; ASM-NEXT: daddu $2, $5, $4
2724
; ASM-NEXT: clcbi $c2, %captab20(d)($c1)
2825
; ASM-NEXT: clcbi $c1, %captab20(e)($c1)
29-
; ASM-NEXT: cgetoffset $1, $c2
3026
; ASM-NEXT: cincoffset $c2, $c2, $4
31-
; ASM-NEXT: daddu $1, $2, $1
32-
; ASM-NEXT: csetoffset $c2, $c2, $1
27+
; ASM-NEXT: cincoffset $c2, $c2, $5
3328
; ASM-NEXT: cjr $c17
3429
; ASM-NEXT: csc $c2, $zero, 0($c1)
3530
; CHECK-LABEL: define void @g

llvm/test/CodeGen/CHERI-Generic/RISCV32/cheri-intrinsics-folding-broken-module-regression.ll

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2
22
; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/cheri-intrinsics-folding-broken-module-regression.ll
33
; This used to create a broken function.
4-
; FIXME: the getoffset+add sequence should be folded to an increment
5-
; REQUIRES: mips-registered-target
64
; RUN: opt -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+xcheripurecap,+f -S -passes=instcombine %s -o - | FileCheck %s
75
; RUN: opt -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+xcheripurecap,+f -S '-passes=default<O3>' %s | llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+xcheripurecap,+f -O3 -o - | FileCheck %s --check-prefix ASM
86
target datalayout = "e-m:e-pf200:64:64:64:32-p:32:32-i64:64-n32-S128-A200-P200-G200"
@@ -23,14 +21,11 @@ define void @g(i32 %x, i32 %y) addrspace(200) nounwind {
2321
; ASM-NEXT: .LBB0_1: # Label of block must be emitted
2422
; ASM-NEXT: auipcc a2, %captab_pcrel_hi(d)
2523
; ASM-NEXT: clc a2, %pcrel_lo(.LBB0_1)(a2)
26-
; ASM-NEXT: add a1, a1, a0
2724
; ASM-NEXT: .LBB0_2: # Label of block must be emitted
2825
; ASM-NEXT: auipcc a3, %captab_pcrel_hi(e)
2926
; ASM-NEXT: clc a3, %pcrel_lo(.LBB0_2)(a3)
3027
; ASM-NEXT: cincoffset a0, a2, a0
31-
; ASM-NEXT: cgetoffset a2, a2
32-
; ASM-NEXT: add a1, a1, a2
33-
; ASM-NEXT: csetoffset a0, a0, a1
28+
; ASM-NEXT: cincoffset a0, a0, a1
3429
; ASM-NEXT: csc a0, 0(a3)
3530
; ASM-NEXT: cret
3631
; CHECK-LABEL: define void @g

llvm/test/CodeGen/CHERI-Generic/RISCV64/cheri-intrinsics-folding-broken-module-regression.ll

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2
22
; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/cheri-intrinsics-folding-broken-module-regression.ll
33
; This used to create a broken function.
4-
; FIXME: the getoffset+add sequence should be folded to an increment
5-
; REQUIRES: mips-registered-target
64
; RUN: opt -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+xcheripurecap,+f,+d -S -passes=instcombine %s -o - | FileCheck %s
75
; RUN: opt -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+xcheripurecap,+f,+d -S '-passes=default<O3>' %s | llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+xcheripurecap,+f,+d -O3 -o - | FileCheck %s --check-prefix ASM
86
target datalayout = "e-m:e-pf200:128:128:128:64-p:64:64-i64:64-i128:128-n64-S128-A200-P200-G200"
@@ -23,14 +21,11 @@ define void @g(i64 %x, i64 %y) addrspace(200) nounwind {
2321
; ASM-NEXT: .LBB0_1: # Label of block must be emitted
2422
; ASM-NEXT: auipcc a2, %captab_pcrel_hi(d)
2523
; ASM-NEXT: clc a2, %pcrel_lo(.LBB0_1)(a2)
26-
; ASM-NEXT: add a1, a1, a0
2724
; ASM-NEXT: .LBB0_2: # Label of block must be emitted
2825
; ASM-NEXT: auipcc a3, %captab_pcrel_hi(e)
2926
; ASM-NEXT: clc a3, %pcrel_lo(.LBB0_2)(a3)
3027
; ASM-NEXT: cincoffset a0, a2, a0
31-
; ASM-NEXT: cgetoffset a2, a2
32-
; ASM-NEXT: add a1, a1, a2
33-
; ASM-NEXT: csetoffset a0, a0, a1
28+
; ASM-NEXT: cincoffset a0, a0, a1
3429
; ASM-NEXT: csc a0, 0(a3)
3530
; ASM-NEXT: cret
3631
; CHECK-LABEL: define void @g

llvm/test/Transforms/InstSimplify/cheri-intrinsics-get-set.ll

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ define i64 @fold_get_of_set(ptr addrspace(200) %arg, i64 %value) nounwind {
8585
;
8686
; HIGH-LABEL: define {{[^@]+}}@fold_get_of_set
8787
; HIGH-SAME: (ptr addrspace(200) [[ARG:%.*]], i64 [[VALUE:%.*]]) addrspace(200) #[[ATTR0]] {
88-
; HIGH-NEXT: [[MODIFIED:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.high.set.i64(ptr addrspace(200) [[ARG]], i64 [[VALUE]])
89-
; HIGH-NEXT: [[RET:%.*]] = tail call i64 @llvm.cheri.cap.high.get.i64(ptr addrspace(200) [[MODIFIED]])
90-
; HIGH-NEXT: ret i64 [[RET]]
88+
; HIGH-NEXT: ret i64 [[VALUE]]
9189
;
9290
; OFFSET-LABEL: define {{[^@]+}}@fold_get_of_set
9391
; OFFSET-SAME: (ptr addrspace(200) [[ARG:%.*]], i64 [[VALUE:%.*]]) addrspace(200) #[[ATTR0]] {
94-
; OFFSET-NEXT: ret i64 [[VALUE]]
92+
; OFFSET-NEXT: [[MODIFIED:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[ARG]], i64 [[VALUE]])
93+
; OFFSET-NEXT: [[RET:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[MODIFIED]])
94+
; OFFSET-NEXT: ret i64 [[RET]]
9595
;
9696
%modified = tail call ptr addrspace(200) @llvm.cheri.cap.FIELD.set.i64(ptr addrspace(200) %arg, i64 %value)
9797
%ret = tail call i64 @llvm.cheri.cap.FIELD.get.i64(ptr addrspace(200) %modified)
@@ -136,8 +136,7 @@ define i64 @fold_get_on_null() nounwind {
136136
;
137137
; HIGH-LABEL: define {{[^@]+}}@fold_get_on_null
138138
; HIGH-SAME: () addrspace(200) #[[ATTR0]] {
139-
; HIGH-NEXT: [[RET:%.*]] = tail call i64 @llvm.cheri.cap.high.get.i64(ptr addrspace(200) null)
140-
; HIGH-NEXT: ret i64 [[RET]]
139+
; HIGH-NEXT: ret i64 0
141140
;
142141
; OFFSET-LABEL: define {{[^@]+}}@fold_get_on_null
143142
; OFFSET-SAME: () addrspace(200) #[[ATTR0]] {
@@ -158,9 +157,7 @@ define i64 @fold_get_on_null_with_gep(i64 %value, i64 %gepoff) nounwind {
158157
;
159158
; HIGH-LABEL: define {{[^@]+}}@fold_get_on_null_with_gep
160159
; HIGH-SAME: (i64 [[VALUE:%.*]], i64 [[GEPOFF:%.*]]) addrspace(200) #[[ATTR0]] {
161-
; HIGH-NEXT: [[TMP:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[GEPOFF]]
162-
; HIGH-NEXT: [[RET:%.*]] = tail call i64 @llvm.cheri.cap.high.get.i64(ptr addrspace(200) [[TMP]])
163-
; HIGH-NEXT: ret i64 [[RET]]
160+
; HIGH-NEXT: ret i64 0
164161
;
165162
; OFFSET-LABEL: define {{[^@]+}}@fold_get_on_null_with_gep
166163
; OFFSET-SAME: (i64 [[VALUE:%.*]], i64 [[GEPOFF:%.*]]) addrspace(200) #[[ATTR0]] {

0 commit comments

Comments
 (0)