Skip to content

Commit 249baf9

Browse files
committed
[LLVM][CHERI] Introduce the llvm.launder.alignment intrinsic and use it to lower __builtin_cheri_address_get on sealed pointers
1 parent 300f4ed commit 249baf9

File tree

6 files changed

+63
-6
lines changed

6 files changed

+63
-6
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6026,10 +6026,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
60266026
return RValue::get(Builder.CreateIntToPtr(Ptr, ResultTy));
60276027
}
60286028

6029-
case Builtin::BI__builtin_cheri_address_get:
6030-
return RValue::get(
6031-
Builder.CreateIntrinsic(llvm::Intrinsic::cheri_cap_address_get,
6032-
{IntPtrTy}, {EmitScalarExpr(E->getArg(0))}));
6029+
case Builtin::BI__builtin_cheri_address_get: {
6030+
const auto *Arg = E->getArg(0);
6031+
auto *RArg = EmitScalarExpr(Arg);
6032+
if (Arg->getType()->isCHERISealedCapabilityType(getContext()))
6033+
RArg = Builder.CreateIntrinsic(llvm::Intrinsic::launder_alignment,
6034+
{UnqualPtrTy}, {RArg});
6035+
return RValue::get(Builder.CreateIntrinsic(
6036+
llvm::Intrinsic::cheri_cap_address_get, {IntPtrTy}, {RArg}));
6037+
}
60336038
case Builtin::BI__builtin_cheri_address_set: {
60346039
Value *Cap = EmitScalarExpr(E->getArg(0));
60356040
Value *Address = EmitScalarExpr(E->getArg(1));

clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,32 @@ SealedInt Obj2 = 10;
2525
// CHECK: @llvm.compiler.used = appending addrspace(200) global [2 x ptr addrspace(200)] [ptr addrspace(200) @Obj1, ptr addrspace(200) @Obj2], section "llvm.metadata"
2626

2727
void doSomething(struct SealedStructObj *__sealed_capability obj);
28+
void doSomethingWithAddr(int addr);
2829
void doSomething2(SealedInt *__sealed_capability obj);
2930

3031
// CHECK: ; Function Attrs: minsize nounwind optsize
3132
// CHECK: define dso_local void @func() local_unnamed_addr addrspace(200) #1 {
3233
void func() {
3334
// CHECK: entry:
34-
// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #3
35+
// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #5
3536
doSomething(&Obj1);
3637

37-
// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #3
38+
// Verify that observing the address of a sealed global value is done through a call to the launder built-in, so that
39+
// the KnownBits optimisation pass can't assume anything about the value of the pointer, specifically nothing about the alignment of the pointer.
40+
// This is because the CHERIoT RTOS uses the lower bits of the address to store the permissions of the sealed capability, and KnownBits can in turn
41+
// optimise away logical computations on lower parts of the address.
42+
43+
// CHECK: %0 = tail call ptr addrspace(200) @llvm.launder.alignment.p200(ptr addrspace(200) nonnull @Obj1)
44+
// CHECK: %1 = tail call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) nonnull %0)
45+
// CHECK: tail call void @doSomethingWithAddr(i32 noundef %1) #5
46+
doSomethingWithAddr(__builtin_cheri_address_get(&Obj1));
47+
48+
// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #5
3849
doSomething2(&Obj2);
3950
}
4051

4152
// CHECK: declare void @doSomething(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2
53+
// CHECK: declare void @doSomethingWithAddr(i32 noundef) local_unnamed_addr addrspace(200) #2
54+
// CHECK: declare ptr addrspace(200) @llvm.launder.alignment.p200(ptr addrspace(200)) addrspace(200) #3
55+
// CHECK: declare i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200)) addrspace(200) #4
4256
// CHECK: declare void @doSomething2(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2

llvm/docs/LangRef.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26826,6 +26826,38 @@ Returns another pointer that aliases its argument but which has no associated
2682626826
``invariant.group`` metadata.
2682726827
It does not read any memory and can be speculated.
2682826828

26829+
'``llvm.launder.alignment``' Intrinsic
26830+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26831+
26832+
Syntax:
26833+
"""""""
26834+
This is an overloaded intrinsic. The returned pointer must belong to the same
26835+
address space as the argument.
26836+
26837+
::
26838+
26839+
declare ptr @llvm.launder.alignment.p0(ptr <ptr>)
26840+
26841+
Overview:
26842+
"""""""""
26843+
26844+
The '``llvm.launder.alignment``' intrinsic can be used when the informations
26845+
regarding the alignment of the type the argument points to must be removed, so
26846+
to block unwanted optimizations.
26847+
26848+
26849+
Arguments:
26850+
""""""""""
26851+
26852+
The ``llvm.launder.alignment`` takes only one argument, which is a pointer
26853+
to the memory.
26854+
26855+
Semantics:
26856+
""""""""""
26857+
26858+
Returns another pointer that aliases its argument but which has no associated
26859+
alignment metadata.
26860+
It does not read any memory and can be speculated.
2682926861

2683026862

2683126863
.. _constrainedfp:

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,10 @@ def int_strip_invariant_group : DefaultAttrsIntrinsic<[llvm_anyptr_ty],
16991699
[LLVMMatchType<0>],
17001700
[IntrSpeculatable, IntrNoMem]>;
17011701

1702+
def int_launder_alignment : DefaultAttrsIntrinsic<[llvm_anyptr_ty],
1703+
[LLVMMatchType<0>],
1704+
[IntrInaccessibleMemOnly, IntrSpeculatable]>;
1705+
17021706
//===------------------------ Stackmap Intrinsics -------------------------===//
17031707
//
17041708
def int_experimental_stackmap : DefaultAttrsIntrinsic<[],

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6757,6 +6757,7 @@ bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
67576757
// MustPreserveNullness (and, at time of writing, they are not), but we
67586758
// document this fact out of an abundance of caution.
67596759
case Intrinsic::amdgcn_make_buffer_rsrc:
6760+
case Intrinsic::launder_alignment:
67606761
return true;
67616762
case Intrinsic::ptrmask:
67626763
return !MustPreserveNullness;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7463,6 +7463,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
74637463
case Intrinsic::annotation:
74647464
case Intrinsic::ptr_annotation:
74657465
case Intrinsic::launder_invariant_group:
7466+
case Intrinsic::launder_alignment:
74667467
case Intrinsic::strip_invariant_group:
74677468
// Drop the intrinsic, but forward the value
74687469
setValue(&I, getValue(I.getOperand(0)));

0 commit comments

Comments
 (0)