Skip to content

Commit c9fbdba

Browse files
committed
Legalize lifetime intrinsics for DXIL
This commit legalizes lifetime intrinsics for DXIL by - Making lifetime intrinsics an exception to Int64Ops shader flag analysis - Adding a bitcast for the lifetime intrinsics' pointer operand in dxil-prepare to ensure it gets cast to an i8* - Making the DXIL bitcode writer write the base/demangled name of lifetime intrinsics to the symbol table
1 parent 23b4f4e commit c9fbdba

File tree

6 files changed

+136
-5
lines changed

6 files changed

+136
-5
lines changed

llvm/lib/Target/DirectX/DXILPrepare.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ class DXILPrepareModule : public ModulePass {
239239
for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
240240
F.removeParamAttrs(Idx, AttrMask);
241241

242+
// Match FnAttrs of lifetime intrinsics in LLVM 3.7
243+
if (F.isIntrinsic())
244+
switch (F.getIntrinsicID())
245+
case Intrinsic::lifetime_start:
246+
case Intrinsic::lifetime_end:
247+
F.removeFnAttr(Attribute::Memory);
248+
242249
for (auto &BB : F) {
243250
IRBuilder<> Builder(&BB);
244251
for (auto &I : make_early_inc_range(BB)) {
@@ -247,7 +254,7 @@ class DXILPrepareModule : public ModulePass {
247254

248255
// Emtting NoOp bitcast instructions allows the ValueEnumerator to be
249256
// unmodified as it reserves instruction IDs during contruction.
250-
if (auto LI = dyn_cast<LoadInst>(&I)) {
257+
if (auto *LI = dyn_cast<LoadInst>(&I)) {
251258
if (Value *NoOpBitcast = maybeGenerateBitcast(
252259
Builder, PointerTypes, I, LI->getPointerOperand(),
253260
LI->getType())) {
@@ -257,7 +264,7 @@ class DXILPrepareModule : public ModulePass {
257264
}
258265
continue;
259266
}
260-
if (auto SI = dyn_cast<StoreInst>(&I)) {
267+
if (auto *SI = dyn_cast<StoreInst>(&I)) {
261268
if (Value *NoOpBitcast = maybeGenerateBitcast(
262269
Builder, PointerTypes, I, SI->getPointerOperand(),
263270
SI->getValueOperand()->getType())) {
@@ -268,7 +275,7 @@ class DXILPrepareModule : public ModulePass {
268275
}
269276
continue;
270277
}
271-
if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
278+
if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
272279
if (Value *NoOpBitcast = maybeGenerateBitcast(
273280
Builder, PointerTypes, I, GEP->getPointerOperand(),
274281
GEP->getSourceElementType()))
@@ -280,6 +287,17 @@ class DXILPrepareModule : public ModulePass {
280287
CB->removeRetAttrs(AttrMask);
281288
for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
282289
CB->removeParamAttrs(Idx, AttrMask);
290+
// LLVM 3.7 Lifetime intrinics require an i8* pointer operand, so we
291+
// insert a bitcast here to ensure that is the case
292+
if (isa<LifetimeIntrinsic>(CB)) {
293+
Value *PtrOperand = CB->getArgOperand(1);
294+
Builder.SetInsertPoint(CB);
295+
PointerType *PtrTy = cast<PointerType>(PtrOperand->getType());
296+
Value *NoOpBitcast = Builder.Insert(
297+
CastInst::Create(Instruction::BitCast, PtrOperand,
298+
Builder.getPtrTy(PtrTy->getAddressSpace())));
299+
CB->setArgOperand(1, NoOpBitcast);
300+
}
283301
continue;
284302
}
285303
}

llvm/lib/Target/DirectX/DXILShaderFlags.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
152152
if (!CSF.Int64Ops)
153153
CSF.Int64Ops = I.getType()->isIntegerTy(64);
154154

155-
if (!CSF.Int64Ops) {
155+
if (!CSF.Int64Ops && !isa<LifetimeIntrinsic>(&I)) {
156156
for (const Value *Op : I.operands()) {
157157
if (Op->getType()->isIntegerTy(64)) {
158158
CSF.Int64Ops = true;

llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2559,8 +2559,22 @@ void DXILBitcodeWriter::writeFunctionLevelValueSymbolTable(
25592559
// to ensure the binary is the same no matter what values ever existed.
25602560
SmallVector<const ValueName *, 16> SortedTable;
25612561

2562+
MallocAllocator Allocator;
25622563
for (auto &VI : VST) {
2563-
SortedTable.push_back(VI.second->getValueName());
2564+
ValueName *VN = VI.second->getValueName();
2565+
// Clang mangles lifetime intrinsic names by appending '.p0' to the end,
2566+
// making them invalid lifetime intrinsics in LLVM 3.7. We can't
2567+
// demangle in dxil-prepare because it would result in invalid IR.
2568+
// Therefore we have to do this in the bitcode writer while writing its
2569+
// name to the symbol table.
2570+
if (const Function *Fn = dyn_cast<Function>(VI.getValue());
2571+
Fn && Fn->isIntrinsic()) {
2572+
Intrinsic::ID IID = Fn->getIntrinsicID();
2573+
if (IID == Intrinsic::lifetime_start || IID == Intrinsic::lifetime_end)
2574+
VN = ValueName::create(Intrinsic::getBaseName(IID), Allocator,
2575+
VI.second);
2576+
}
2577+
SortedTable.push_back(VN);
25642578
}
25652579
// The keys are unique, so there shouldn't be stability issues.
25662580
llvm::sort(SortedTable, [](const ValueName *A, const ValueName *B) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
3+
4+
target triple = "dxil-pc-shadermodel6.7-library"
5+
6+
; CHECK: ; Combined Shader Flags for Module
7+
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
8+
; CHECK-NEXT: ;
9+
; CHECK-NOT: ; Note: shader requires additional functionality:
10+
; CHECK-NOT: ; 64-Bit integer
11+
; CHECK-NOT: ; Note: extra DXIL module flags:
12+
; CHECK-NOT: ;
13+
; CHECK-NEXT: ; Shader Flags for Module Functions
14+
; CHECK-NEXT: ; Function lifetimes : 0x00000000
15+
16+
define void @lifetimes() #0 {
17+
%a = alloca [4 x i32], align 8
18+
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %a)
19+
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %a)
20+
ret void
21+
}
22+
23+
; Function Attrs: nounwind memory(argmem: readwrite)
24+
declare void @llvm.lifetime.start.p0(i64, ptr) #1
25+
26+
; Function Attrs: nounwind memory(argmem: readwrite)
27+
declare void @llvm.lifetime.end.p0(i64, ptr) #1
28+
29+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
30+
attributes #1 = { nounwind memory(argmem: readwrite) }
31+
32+
; DXC: - Name: SFI0
33+
; DXC-NEXT: Size: 8
34+
; DXC-NOT: Flags:
35+
; DXC-NOT: Int64Ops: true
36+
; DXC: ...

llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM63
22
; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM66
3+
; RUN: opt -S -dxil-op-lower -dxil-prepare -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-PREPARE
34

45
; CHECK-LABEL: define void @test_legal_lifetime() {
56
;
@@ -15,6 +16,14 @@
1516
; CHECK-SM66-NEXT: store i32 0, ptr [[GEP]], align 4
1617
; CHECK-SM66-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]])
1718
;
19+
; CHECK-PREPARE-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4
20+
; CHECK-PREPARE-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0
21+
; CHECK-PREPARE-NEXT: [[BITCAST:%.*]] = bitcast ptr [[ACCUM_I_FLAT]] to ptr
22+
; CHECK-PREPARE-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[BITCAST]])
23+
; CHECK-PREPARE-NEXT: store i32 0, ptr [[GEP]], align 4
24+
; CHECK-PREPARE-NEXT: [[BITCAST:%.*]] = bitcast ptr [[ACCUM_I_FLAT]] to ptr
25+
; CHECK-PREPARE-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[BITCAST]])
26+
;
1827
; CHECK-NEXT: ret void
1928
;
2029
define void @test_legal_lifetime() {
@@ -26,6 +35,22 @@ define void @test_legal_lifetime() {
2635
ret void
2736
}
2837

38+
; CHECK-PREPARE-DAG: attributes [[LIFETIME_ATTRS:#.*]] = { nounwind }
39+
40+
; CHECK-PREPARE-DAG: ; Function Attrs: nounwind
41+
; CHECK-PREPARE-DAG: declare void @llvm.lifetime.start.p0(i64, ptr) [[LIFETIME_ATTRS]]
42+
43+
; CHECK-PREPARE-DAG: ; Function Attrs: nounwind
44+
; CHECK-PREPARE-DAG: declare void @llvm.lifetime.end.p0(i64, ptr) [[LIFETIME_ATTRS]]
45+
46+
; Function Attrs: nounwind memory(argmem: readwrite)
47+
declare void @llvm.lifetime.end.p0(i64, ptr) #0
48+
49+
; Function Attrs: nounwind memory(argmem: readwrite)
50+
declare void @llvm.lifetime.start.p0(i64, ptr) #0
51+
52+
attributes #0 = { nounwind memory(argmem: readwrite) }
53+
2954
; Set the validator version to 1.6
3055
!dx.valver = !{!0}
3156
!0 = !{i32 1, i32 6}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
2+
target triple = "dxil-unknown-shadermodel6.7-library"
3+
4+
define void @test_lifetimes() {
5+
; CHECK-LABEL: test_lifetimes
6+
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [2 x i32], align 4
7+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], [2 x i32]* [[ALLOCA]], i32 0, i32 0
8+
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast [2 x i32]* [[ALLOCA]] to i8*
9+
; CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* nonnull [[BITCAST]])
10+
; CHECK-NEXT: store i32 0, i32* [[GEP]], align 4
11+
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast [2 x i32]* [[ALLOCA]] to i8*
12+
; CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* nonnull [[BITCAST]])
13+
; CHECK-NEXT: ret void
14+
;
15+
%a = alloca [2 x i32], align 4
16+
%gep = getelementptr i32, ptr %a, i32 0
17+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a)
18+
store i32 0, ptr %gep, align 4
19+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a)
20+
ret void
21+
}
22+
23+
; CHECK-DAG: attributes [[LIFETIME_ATTRS:#.*]] = { nounwind }
24+
25+
; CHECK-DAG: ; Function Attrs: nounwind
26+
; CHECK-DAG: declare void @llvm.lifetime.start(i64, i8* nocapture) [[LIFETIME_ATTRS]]
27+
28+
; CHECK-DAG: ; Function Attrs: nounwind
29+
; CHECK-DAG: declare void @llvm.lifetime.end(i64, i8* nocapture) [[LIFETIME_ATTRS]]
30+
31+
; Function Attrs: nounwind memory(argmem: readwrite)
32+
declare void @llvm.lifetime.end.p0(i64, ptr) #0
33+
34+
; Function Attrs: nounwind memory(argmem: readwrite)
35+
declare void @llvm.lifetime.start.p0(i64, ptr) #0
36+
37+
attributes #0 = { nounwind memory(argmem: readwrite) }
38+

0 commit comments

Comments
 (0)