Skip to content

Commit 2bd6296

Browse files
committed
Lower lifetime intrinsics to stores for dxil version < 1.6
1 parent 20b3ab5 commit 2bd6296

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

llvm/lib/Target/DirectX/DXILOpLowering.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ class OpLowerer {
3939
DXILOpBuilder OpBuilder;
4040
DXILResourceMap &DRM;
4141
DXILResourceTypeMap &DRTM;
42+
const ModuleMetadataInfo &MMDI;
4243
SmallVector<CallInst *> CleanupCasts;
4344

4445
public:
45-
OpLowerer(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM)
46-
: M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM) {}
46+
OpLowerer(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM,
47+
const ModuleMetadataInfo &MMDI)
48+
: M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
4749

4850
/// Replace every call to \c F using \c ReplaceCall, and then erase \c F. If
4951
/// there is an error replacing a call, we emit a diagnostic and return true.
@@ -745,6 +747,37 @@ class OpLowerer {
745747
});
746748
}
747749

750+
[[nodiscard]] bool lowerLifetimeIntrinsic(Function &F) {
751+
IRBuilder<> &IRB = OpBuilder.getIRB();
752+
return replaceFunction(F, [&](CallInst *CI) -> Error {
753+
IRB.SetInsertPoint(CI);
754+
Value *Ptr = CI->getArgOperand(1);
755+
assert(Ptr->getType()->isPointerTy() &&
756+
"Expected operand of lifetime intrinsic to be a pointer");
757+
758+
auto ZeroOrUndef = [&](Type *Ty) {
759+
return MMDI.ValidatorVersion < VersionTuple(1, 6)
760+
? Constant::getNullValue(Ty)
761+
: UndefValue::get(Ty);
762+
};
763+
764+
Value *Val = nullptr;
765+
if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) {
766+
if (GV->hasInitializer() || GV->isExternallyInitialized())
767+
return Error::success();
768+
Val = ZeroOrUndef(GV->getValueType());
769+
} else if (auto *AI = dyn_cast<AllocaInst>(Ptr))
770+
Val = ZeroOrUndef(AI->getAllocatedType());
771+
772+
assert(Val && "Expected operand of lifetime intrinsic to be a global "
773+
"variable or alloca instruction");
774+
IRB.CreateStore(Val, Ptr, false);
775+
776+
CI->eraseFromParent();
777+
return Error::success();
778+
});
779+
}
780+
748781
[[nodiscard]] bool lowerIsFPClass(Function &F) {
749782
IRBuilder<> &IRB = OpBuilder.getIRB();
750783
Type *RetTy = IRB.getInt1Ty();
@@ -803,8 +836,6 @@ class OpLowerer {
803836
case Intrinsic::dx_resource_casthandle:
804837
// NOTE: llvm.dbg.value is supported as is in DXIL.
805838
case Intrinsic::dbg_value:
806-
case Intrinsic::lifetime_start:
807-
case Intrinsic::lifetime_end:
808839
case Intrinsic::not_intrinsic:
809840
if (F.use_empty())
810841
F.eraseFromParent();
@@ -855,6 +886,17 @@ class OpLowerer {
855886
case Intrinsic::ctpop:
856887
HasErrors |= lowerCtpopToCountBits(F);
857888
break;
889+
case Intrinsic::lifetime_start:
890+
case Intrinsic::lifetime_end:
891+
if (F.use_empty())
892+
F.eraseFromParent();
893+
else {
894+
if (MMDI.DXILVersion < VersionTuple(1, 6))
895+
HasErrors |= lowerLifetimeIntrinsic(F);
896+
else
897+
continue;
898+
}
899+
break;
858900
case Intrinsic::is_fpclass:
859901
HasErrors |= lowerIsFPClass(F);
860902
break;
@@ -872,8 +914,9 @@ class OpLowerer {
872914
PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) {
873915
DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
874916
DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
917+
const ModuleMetadataInfo MMDI = MAM.getResult<DXILMetadataAnalysis>(M);
875918

876-
bool MadeChanges = OpLowerer(M, DRM, DRTM).lowerIntrinsics();
919+
bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
877920
if (!MadeChanges)
878921
return PreservedAnalyses::all();
879922
PreservedAnalyses PA;
@@ -891,8 +934,10 @@ class DXILOpLoweringLegacy : public ModulePass {
891934
getAnalysis<DXILResourceWrapperPass>().getResourceMap();
892935
DXILResourceTypeMap &DRTM =
893936
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
937+
const ModuleMetadataInfo MMDI =
938+
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
894939

895-
return OpLowerer(M, DRM, DRTM).lowerIntrinsics();
940+
return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
896941
}
897942
StringRef getPassName() const override { return "DXIL Op Lowering"; }
898943
DXILOpLoweringLegacy() : ModulePass(ID) {}
@@ -901,6 +946,7 @@ class DXILOpLoweringLegacy : public ModulePass {
901946
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
902947
AU.addRequired<DXILResourceTypeWrapperPass>();
903948
AU.addRequired<DXILResourceWrapperPass>();
949+
AU.addRequired<DXILMetadataAnalysisWrapperPass>();
904950
AU.addPreserved<DXILResourceWrapperPass>();
905951
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
906952
AU.addPreserved<ShaderFlagsAnalysisWrapper>();

llvm/test/CodeGen/DirectX/legalize-lifetimes.ll renamed to llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
; CHECK-LABEL: define void @test_legal_lifetime() {
44
; CHECK-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4
55
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0
6-
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]])
6+
; CHECK-NEXT: store [1 x i32] zeroinitializer, ptr [[ACCUM_I_FLAT]], align 4
77
; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4
8-
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]])
8+
; CHECK-NEXT: store [1 x i32] zeroinitializer, ptr [[ACCUM_I_FLAT]], align 4
99
; CHECK-NEXT: ret void
1010
;
1111
define void @test_legal_lifetime() {
@@ -16,3 +16,6 @@ define void @test_legal_lifetime() {
1616
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %accum.i.flat)
1717
ret void
1818
}
19+
20+
!dx.valver = !{!0}
21+
!0 = !{i32 1, i32 5}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM63
2+
; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM66
3+
4+
; CHECK-LABEL: define void @test_legal_lifetime() {
5+
;
6+
; CHECK-SM63-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4
7+
; CHECK-SM63-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0
8+
; CHECK-SM63-NEXT: store [1 x i32] undef, ptr [[ACCUM_I_FLAT]], align 4
9+
; CHECK-SM63-NEXT: store i32 0, ptr [[GEP]], align 4
10+
; CHECK-SM63-NEXT: store [1 x i32] undef, ptr [[ACCUM_I_FLAT]], align 4
11+
;
12+
; CHECK-SM66-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4
13+
; CHECK-SM66-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0
14+
; CHECK-SM66-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]])
15+
; CHECK-SM66-NEXT: store i32 0, ptr [[GEP]], align 4
16+
; CHECK-SM66-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]])
17+
;
18+
; CHECK-NEXT: ret void
19+
;
20+
define void @test_legal_lifetime() {
21+
%accum.i.flat = alloca [1 x i32], align 4
22+
%gep = getelementptr i32, ptr %accum.i.flat, i32 0
23+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %accum.i.flat)
24+
store i32 0, ptr %gep, align 4
25+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %accum.i.flat)
26+
ret void
27+
}
28+
29+
!dx.valver = !{!0}
30+
!0 = !{i32 1, i32 6}

0 commit comments

Comments
 (0)