diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e1ad9926e525c..7eb2865a1e71f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6026,10 +6026,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Builder.CreateIntToPtr(Ptr, ResultTy)); } - case Builtin::BI__builtin_cheri_address_get: - return RValue::get( - Builder.CreateIntrinsic(llvm::Intrinsic::cheri_cap_address_get, - {IntPtrTy}, {EmitScalarExpr(E->getArg(0))})); + case Builtin::BI__builtin_cheri_address_get: { + const auto *Arg = E->getArg(0); + auto *RArg = EmitScalarExpr(Arg); + if (Arg->getType()->isCHERISealedCapabilityType(getContext())) + RArg = Builder.CreateIntrinsic(llvm::Intrinsic::launder_alignment, + {UnqualPtrTy}, {RArg}); + return RValue::get(Builder.CreateIntrinsic( + llvm::Intrinsic::cheri_cap_address_get, {IntPtrTy}, {RArg})); + } case Builtin::BI__builtin_cheri_address_set: { Value *Cap = EmitScalarExpr(E->getArg(0)); Value *Address = EmitScalarExpr(E->getArg(1)); diff --git a/clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c b/clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c index 91cf1017fe30c..c75d44ba13b4f 100644 --- a/clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c +++ b/clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c @@ -25,18 +25,32 @@ SealedInt Obj2 = 10; // CHECK: @llvm.compiler.used = appending addrspace(200) global [2 x ptr addrspace(200)] [ptr addrspace(200) @Obj1, ptr addrspace(200) @Obj2], section "llvm.metadata" void doSomething(struct SealedStructObj *__sealed_capability obj); +void doSomethingWithAddr(int addr); void doSomething2(SealedInt *__sealed_capability obj); // CHECK: ; Function Attrs: minsize nounwind optsize // CHECK: define dso_local void @func() local_unnamed_addr addrspace(200) #1 { void func() { // CHECK: entry: -// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #3 +// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #5 doSomething(&Obj1); -// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #3 +// Verify that observing the address of a sealed global value is done through a call to the launder built-in, so that +// the KnownBits optimisation pass can't assume anything about the value of the pointer, specifically nothing about the alignment of the pointer. +// 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 +// optimise away logical computations on lower parts of the address. + +// CHECK: %0 = tail call ptr addrspace(200) @llvm.launder.alignment.p200(ptr addrspace(200) nonnull @Obj1) +// CHECK: %1 = tail call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) nonnull %0) +// CHECK: tail call void @doSomethingWithAddr(i32 noundef %1) #5 + doSomethingWithAddr(__builtin_cheri_address_get(&Obj1)); + +// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #5 doSomething2(&Obj2); } // CHECK: declare void @doSomething(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2 +// CHECK: declare void @doSomethingWithAddr(i32 noundef) local_unnamed_addr addrspace(200) #2 +// CHECK: declare ptr addrspace(200) @llvm.launder.alignment.p200(ptr addrspace(200)) addrspace(200) #3 +// CHECK: declare i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200)) addrspace(200) #4 // CHECK: declare void @doSomething2(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2 diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 2a9b67b671e11..ffeba7d343dee 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -26826,6 +26826,38 @@ Returns another pointer that aliases its argument but which has no associated ``invariant.group`` metadata. It does not read any memory and can be speculated. +'``llvm.launder.alignment``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" +This is an overloaded intrinsic. The returned pointer must belong to the same +address space as the argument. + +:: + + declare ptr @llvm.launder.alignment.p0(ptr ) + +Overview: +""""""""" + +The '``llvm.launder.alignment``' intrinsic can be used when the informations +regarding the alignment of the type the argument points to must be removed, so +to block unwanted optimizations. + + +Arguments: +"""""""""" + +The ``llvm.launder.alignment`` takes only one argument, which is a pointer +to the memory. + +Semantics: +"""""""""" + +Returns another pointer that aliases its argument but which has no associated +alignment metadata. +It does not read any memory and can be speculated. .. _constrainedfp: diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 1b41cf2395306..1742e9314afc5 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1699,6 +1699,10 @@ def int_strip_invariant_group : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>], [IntrSpeculatable, IntrNoMem]>; +def int_launder_alignment : DefaultAttrsIntrinsic<[llvm_anyptr_ty], + [LLVMMatchType<0>], + [IntrInaccessibleMemOnly, IntrSpeculatable]>; + //===------------------------ Stackmap Intrinsics -------------------------===// // def int_experimental_stackmap : DefaultAttrsIntrinsic<[], diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index dce24be8047c5..f3b99442750b1 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6757,6 +6757,7 @@ bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing( // MustPreserveNullness (and, at time of writing, they are not), but we // document this fact out of an abundance of caution. case Intrinsic::amdgcn_make_buffer_rsrc: + case Intrinsic::launder_alignment: return true; case Intrinsic::ptrmask: return !MustPreserveNullness; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 815d26ec6446c..0dde33c1af3ce 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7463,6 +7463,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, case Intrinsic::annotation: case Intrinsic::ptr_annotation: case Intrinsic::launder_invariant_group: + case Intrinsic::launder_alignment: case Intrinsic::strip_invariant_group: // Drop the intrinsic, but forward the value setValue(&I, getValue(I.getOperand(0)));