Skip to content

Commit 1c7fef2

Browse files
authored
[IR] Introduce llvm.experimental.provenance[begin,end] (#3211)
An experimental intrinisc and a builtin to provide a way to specify that the pointer is not aliasing with others. Helpful in cases where pointers are based on the same global value but with different indices.
1 parent 489b173 commit 1c7fef2

File tree

9 files changed

+102
-0
lines changed

9 files changed

+102
-0
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,18 @@ def Trap : Builtin {
11961196
let Prototype = "void()";
11971197
}
11981198

1199+
def ProvenanceBegin : Builtin {
1200+
let Spellings = ["__builtin_experimental_provenance_begin"];
1201+
let Attributes = [NoThrow];
1202+
let Prototype = "void*(void*)";
1203+
}
1204+
1205+
def ProvenanceEnd : Builtin {
1206+
let Spellings = ["__builtin_experimental_provenance_end"];
1207+
let Attributes = [NoThrow];
1208+
let Prototype = "void(void*)";
1209+
}
1210+
11991211
def VerboseTrap : Builtin {
12001212
let Spellings = ["__builtin_verbose_trap"];
12011213
let Attributes = [NoThrow, NoReturn];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3733,6 +3733,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
37333733
case Builtin::BI__builtin_trap:
37343734
EmitTrapCall(Intrinsic::trap);
37353735
return RValue::get(nullptr);
3736+
case Builtin::BI__builtin_experimental_provenance_begin:{
3737+
Value *Ptr = EmitScalarExpr(E->getArg(0));
3738+
SmallVector<Value *, 2> Args;
3739+
for (int i = 0, e = E->getNumArgs(); i != e; ++i)
3740+
Args.push_back(EmitScalarExpr(E->getArg(i)));
3741+
Function *F = CGM.getIntrinsic(Intrinsic::experimental_provenance_begin, {ConvertType(E->getType()), Ptr->getType()});
3742+
return RValue::get(Builder.CreateCall(F, {Args}));
3743+
}
3744+
case Builtin::BI__builtin_experimental_provenance_end:{
3745+
Value *Ptr = EmitScalarExpr(E->getArg(0));
3746+
Function *F = CGM.getIntrinsic(Intrinsic::experimental_provenance_end, Ptr->getType());
3747+
Builder.CreateCall(F, {Ptr});
3748+
return RValue::get(nullptr);
3749+
}
37363750
case Builtin::BI__builtin_verbose_trap: {
37373751
llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
37383752
if (getDebugInfo()) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s
3+
4+
static_assert(__has_builtin(__builtin_experimental_provenance_begin), "");
5+
static_assert(__has_builtin(__builtin_experimental_provenance_end), "");
6+
7+
void *Ptr;
8+
9+
// CHECK-LABEL: define dso_local void @_Z4testv(
10+
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
11+
// CHECK-NEXT: [[ENTRY:.*:]]
12+
// CHECK-NEXT: [[PTRPROV:%.*]] = alloca ptr, align 8
13+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @Ptr, align 8
14+
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr @Ptr, align 8
15+
// CHECK-NEXT: [[TMP2:%.*]] = call ptr @llvm.experimental.provenance.begin.p0.p0(ptr [[TMP1]])
16+
// CHECK-NEXT: store ptr [[TMP2]], ptr [[PTRPROV]], align 8
17+
// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[PTRPROV]], align 8
18+
// CHECK-NEXT: call void @llvm.experimental.provenance.end.p0(ptr [[TMP3]])
19+
// CHECK-NEXT: ret void
20+
//
21+
void test(){
22+
void *PtrProv = __builtin_experimental_provenance_begin(Ptr);
23+
__builtin_experimental_provenance_end(PtrProv);
24+
}

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,15 @@ def int_invariant_end : DefaultAttrsIntrinsic<[],
16701670
NoCapture<ArgIndex<2>>,
16711671
ImmArg<ArgIndex<1>>]>;
16721672

1673+
def int_experimental_provenance_begin : Intrinsic<
1674+
[llvm_anyptr_ty], [llvm_anyptr_ty],
1675+
[IntrArgMemOnly, NoAlias<RetIndex>]>,
1676+
ClangBuiltin<"__builtin_experimental_provenance_begin">;
1677+
1678+
def int_experimental_provenance_end : Intrinsic<
1679+
[], [llvm_anyptr_ty], []>,
1680+
ClangBuiltin<"__builtin_experimental_provenance_end">;
1681+
16731682
// launder.invariant.group can't be marked with 'readnone' (IntrNoMem),
16741683
// because it would cause CSE of two barriers with the same argument.
16751684
// Inaccessiblememonly says that the barrier doesn't read the argument,

llvm/lib/Analysis/MemoryDependenceAnalysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ static ModRefInfo GetLocation(const Instruction *Inst, MemoryLocation &Loc,
156156
// will allow them to be handled conservatively.
157157
return ModRefInfo::Mod;
158158
case Intrinsic::invariant_end:
159+
case Intrinsic::experimental_provenance_end:
159160
Loc = MemoryLocation::getForArgument(II, 2, TLI);
160161
// These intrinsics don't really modify the memory, but returning Mod
161162
// will allow them to be handled conservatively.

llvm/lib/Analysis/MemorySSA.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
300300
case Intrinsic::assume:
301301
case Intrinsic::experimental_noalias_scope_decl:
302302
case Intrinsic::pseudoprobe:
303+
case Intrinsic::experimental_provenance_end:
303304
return false;
304305
case Intrinsic::dbg_declare:
305306
case Intrinsic::dbg_label:

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ bool isNoopIntrinsic(Instruction *I) {
824824
case Intrinsic::invariant_end:
825825
case Intrinsic::launder_invariant_group:
826826
case Intrinsic::assume:
827+
case Intrinsic::experimental_provenance_end:
827828
return true;
828829
case Intrinsic::dbg_declare:
829830
case Intrinsic::dbg_label:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info 2>&1 | FileCheck %s
2+
3+
define void @test(ptr %g) {
4+
; CHECK-LABEL: test
5+
; CHECK: NoAlias: i32* %g, i32* %p1.p
6+
%p1.p = call ptr @llvm.experimental.provenance.begin(ptr %g)
7+
%r1 = load i32, ptr %g
8+
%r2 = load i32, ptr %p1.p
9+
call void @llvm.experimental.provenance.end(ptr %p1.p)
10+
ret void
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes=dse -S < %s | FileCheck %s
3+
4+
@g = global [100 x i32] zeroinitializer
5+
6+
define i32 @test(i32 %i1, i32 %i2, i32 %i3) {
7+
; CHECK-LABEL: define i32 @test(
8+
; CHECK-SAME: i32 [[I1:%.*]], i32 [[I2:%.*]], i32 [[I3:%.*]]) {
9+
; CHECK-NEXT: [[P1:%.*]] = getelementptr i32, ptr @g, i32 [[I1]]
10+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr @g, i32 [[I2]]
11+
; CHECK-NEXT: [[P1_P:%.*]] = call ptr @llvm.experimental.provenance.begin.p0.p0(ptr [[P1]])
12+
; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[P2]], align 4
13+
; CHECK-NEXT: store i32 1, ptr [[P1_P]], align 4
14+
; CHECK-NEXT: call void @llvm.experimental.provenance.end.p0(ptr [[P1_P]])
15+
; CHECK-NEXT: [[R1:%.*]] = load i32, ptr [[P1_P]], align 4
16+
; CHECK-NEXT: [[R2:%.*]] = add i32 [[R]], [[R1]]
17+
; CHECK-NEXT: ret i32 [[R2]]
18+
;
19+
%p1 = getelementptr i32, ptr @g, i32 %i1
20+
%p2 = getelementptr i32, ptr @g, i32 %i2
21+
%p1.p = call ptr @llvm.experimental.provenance.begin(ptr %p1)
22+
store i32 0, ptr %p1.p
23+
%r = load i32, ptr %p2
24+
store i32 1, ptr %p1.p
25+
call void @llvm.experimental.provenance.end(ptr %p1.p)
26+
%r1 = load i32, ptr %p1.p
27+
%r2 = add i32 %r, %r1
28+
ret i32 %r2
29+
}

0 commit comments

Comments
 (0)