From 2bd62963da6fdb061166e354129df6db6fe80449 Mon Sep 17 00:00:00 2001 From: Icohedron Date: Mon, 7 Jul 2025 22:05:16 +0000 Subject: [PATCH 1/5] Lower lifetime intrinsics to stores for dxil version < 1.6 --- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 58 +++++++++++++++++-- ...es.ll => legalize-lifetimes-valver-1.5.ll} | 7 ++- .../DirectX/legalize-lifetimes-valver-1.6.ll | 30 ++++++++++ 3 files changed, 87 insertions(+), 8 deletions(-) rename llvm/test/CodeGen/DirectX/{legalize-lifetimes.ll => legalize-lifetimes-valver-1.5.ll} (77%) create mode 100644 llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 995120309a938..c574c48125b6e 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -39,11 +39,13 @@ class OpLowerer { DXILOpBuilder OpBuilder; DXILResourceMap &DRM; DXILResourceTypeMap &DRTM; + const ModuleMetadataInfo &MMDI; SmallVector CleanupCasts; public: - OpLowerer(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM) - : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM) {} + OpLowerer(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM, + const ModuleMetadataInfo &MMDI) + : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {} /// Replace every call to \c F using \c ReplaceCall, and then erase \c F. If /// there is an error replacing a call, we emit a diagnostic and return true. @@ -745,6 +747,37 @@ class OpLowerer { }); } + [[nodiscard]] bool lowerLifetimeIntrinsic(Function &F) { + IRBuilder<> &IRB = OpBuilder.getIRB(); + return replaceFunction(F, [&](CallInst *CI) -> Error { + IRB.SetInsertPoint(CI); + Value *Ptr = CI->getArgOperand(1); + assert(Ptr->getType()->isPointerTy() && + "Expected operand of lifetime intrinsic to be a pointer"); + + auto ZeroOrUndef = [&](Type *Ty) { + return MMDI.ValidatorVersion < VersionTuple(1, 6) + ? Constant::getNullValue(Ty) + : UndefValue::get(Ty); + }; + + Value *Val = nullptr; + if (auto *GV = dyn_cast(Ptr)) { + if (GV->hasInitializer() || GV->isExternallyInitialized()) + return Error::success(); + Val = ZeroOrUndef(GV->getValueType()); + } else if (auto *AI = dyn_cast(Ptr)) + Val = ZeroOrUndef(AI->getAllocatedType()); + + assert(Val && "Expected operand of lifetime intrinsic to be a global " + "variable or alloca instruction"); + IRB.CreateStore(Val, Ptr, false); + + CI->eraseFromParent(); + return Error::success(); + }); + } + [[nodiscard]] bool lowerIsFPClass(Function &F) { IRBuilder<> &IRB = OpBuilder.getIRB(); Type *RetTy = IRB.getInt1Ty(); @@ -803,8 +836,6 @@ class OpLowerer { case Intrinsic::dx_resource_casthandle: // NOTE: llvm.dbg.value is supported as is in DXIL. case Intrinsic::dbg_value: - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: case Intrinsic::not_intrinsic: if (F.use_empty()) F.eraseFromParent(); @@ -855,6 +886,17 @@ class OpLowerer { case Intrinsic::ctpop: HasErrors |= lowerCtpopToCountBits(F); break; + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + if (F.use_empty()) + F.eraseFromParent(); + else { + if (MMDI.DXILVersion < VersionTuple(1, 6)) + HasErrors |= lowerLifetimeIntrinsic(F); + else + continue; + } + break; case Intrinsic::is_fpclass: HasErrors |= lowerIsFPClass(F); break; @@ -872,8 +914,9 @@ class OpLowerer { PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) { DXILResourceMap &DRM = MAM.getResult(M); DXILResourceTypeMap &DRTM = MAM.getResult(M); + const ModuleMetadataInfo MMDI = MAM.getResult(M); - bool MadeChanges = OpLowerer(M, DRM, DRTM).lowerIntrinsics(); + bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); if (!MadeChanges) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -891,8 +934,10 @@ class DXILOpLoweringLegacy : public ModulePass { getAnalysis().getResourceMap(); DXILResourceTypeMap &DRTM = getAnalysis().getResourceTypeMap(); + const ModuleMetadataInfo MMDI = + getAnalysis().getModuleMetadata(); - return OpLowerer(M, DRM, DRTM).lowerIntrinsics(); + return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); } StringRef getPassName() const override { return "DXIL Op Lowering"; } DXILOpLoweringLegacy() : ModulePass(ID) {} @@ -901,6 +946,7 @@ class DXILOpLoweringLegacy : public ModulePass { void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); diff --git a/llvm/test/CodeGen/DirectX/legalize-lifetimes.ll b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll similarity index 77% rename from llvm/test/CodeGen/DirectX/legalize-lifetimes.ll rename to llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll index 44b2419a05d64..1119421dc2071 100644 --- a/llvm/test/CodeGen/DirectX/legalize-lifetimes.ll +++ b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll @@ -3,9 +3,9 @@ ; CHECK-LABEL: define void @test_legal_lifetime() { ; CHECK-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4 ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]]) +; CHECK-NEXT: store [1 x i32] zeroinitializer, ptr [[ACCUM_I_FLAT]], align 4 ; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4 -; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]]) +; CHECK-NEXT: store [1 x i32] zeroinitializer, ptr [[ACCUM_I_FLAT]], align 4 ; CHECK-NEXT: ret void ; define void @test_legal_lifetime() { @@ -16,3 +16,6 @@ define void @test_legal_lifetime() { call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %accum.i.flat) ret void } + +!dx.valver = !{!0} +!0 = !{i32 1, i32 5} diff --git a/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll new file mode 100644 index 0000000000000..22502456bc0e3 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll @@ -0,0 +1,30 @@ +; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM63 +; RUN: opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.6-library %s | FileCheck %s --check-prefixes=CHECK,CHECK-SM66 + +; CHECK-LABEL: define void @test_legal_lifetime() { +; +; CHECK-SM63-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4 +; CHECK-SM63-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0 +; CHECK-SM63-NEXT: store [1 x i32] undef, ptr [[ACCUM_I_FLAT]], align 4 +; CHECK-SM63-NEXT: store i32 0, ptr [[GEP]], align 4 +; CHECK-SM63-NEXT: store [1 x i32] undef, ptr [[ACCUM_I_FLAT]], align 4 +; +; CHECK-SM66-NEXT: [[ACCUM_I_FLAT:%.*]] = alloca [1 x i32], align 4 +; CHECK-SM66-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[ACCUM_I_FLAT]], i32 0 +; CHECK-SM66-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]]) +; CHECK-SM66-NEXT: store i32 0, ptr [[GEP]], align 4 +; CHECK-SM66-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[ACCUM_I_FLAT]]) +; +; CHECK-NEXT: ret void +; +define void @test_legal_lifetime() { + %accum.i.flat = alloca [1 x i32], align 4 + %gep = getelementptr i32, ptr %accum.i.flat, i32 0 + call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %accum.i.flat) + store i32 0, ptr %gep, align 4 + call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %accum.i.flat) + ret void +} + +!dx.valver = !{!0} +!0 = !{i32 1, i32 6} From 92d39672de6dd807192841f8c113417ea52775c5 Mon Sep 17 00:00:00 2001 From: Icohedron Date: Tue, 8 Jul 2025 00:08:10 +0000 Subject: [PATCH 2/5] Apply clang-format --- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index c574c48125b6e..438a81b4e1bbb 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -934,8 +934,8 @@ class DXILOpLoweringLegacy : public ModulePass { getAnalysis().getResourceMap(); DXILResourceTypeMap &DRTM = getAnalysis().getResourceTypeMap(); - const ModuleMetadataInfo MMDI = - getAnalysis().getModuleMetadata(); + const ModuleMetadataInfo MMDI = + getAnalysis().getModuleMetadata(); return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); } From e532ec1b1aa875d1fb06e309e36229b3d46b19c5 Mon Sep 17 00:00:00 2001 From: Icohedron Date: Tue, 8 Jul 2025 16:35:47 +0000 Subject: [PATCH 3/5] Add comment about how validator version is set --- llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll | 1 + llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll | 1 + 2 files changed, 2 insertions(+) diff --git a/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll index 1119421dc2071..e485fa20ddfce 100644 --- a/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll +++ b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll @@ -17,5 +17,6 @@ define void @test_legal_lifetime() { ret void } +; Set the validator version to 1.5 !dx.valver = !{!0} !0 = !{i32 1, i32 5} diff --git a/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll index 22502456bc0e3..6552ccddddab4 100644 --- a/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll +++ b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll @@ -26,5 +26,6 @@ define void @test_legal_lifetime() { ret void } +; Set the validator version to 1.6 !dx.valver = !{!0} !0 = !{i32 1, i32 6} From 231a9c2a6163da55cd11704a0825a72b96d025b2 Mon Sep 17 00:00:00 2001 From: Icohedron Date: Tue, 8 Jul 2025 16:37:44 +0000 Subject: [PATCH 4/5] Make DXIL version checking consistent across the file --- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 438a81b4e1bbb..8070651d7c97d 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -318,8 +318,7 @@ class OpLowerer { /// model and taking into account binding information from /// DXILResourceAnalysis. bool lowerHandleFromBinding(Function &F) { - const Triple &TT = M.getTargetTriple(); - if (TT.getDXILVersion() < VersionTuple(1, 6)) + if (MMDI.DXILVersion < VersionTuple(1, 6)) return lowerToCreateHandle(F); return lowerToBindAndAnnotateHandle(F); } @@ -488,8 +487,6 @@ class OpLowerer { } [[nodiscard]] bool lowerRawBufferLoad(Function &F) { - const Triple &TT = M.getTargetTriple(); - VersionTuple DXILVersion = TT.getDXILVersion(); const DataLayout &DL = F.getDataLayout(); IRBuilder<> &IRB = OpBuilder.getIRB(); Type *Int8Ty = IRB.getInt8Ty(); @@ -513,7 +510,7 @@ class OpLowerer { ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value()); Expected OpCall = - DXILVersion >= VersionTuple(1, 2) + MMDI.DXILVersion >= VersionTuple(1, 2) ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad, {Handle, Index0, Index1, Mask, Align}, CI->getName(), NewRetTy) @@ -588,8 +585,6 @@ class OpLowerer { } [[nodiscard]] bool lowerBufferStore(Function &F, bool IsRaw) { - const Triple &TT = M.getTargetTriple(); - VersionTuple DXILVersion = TT.getDXILVersion(); const DataLayout &DL = F.getDataLayout(); IRBuilder<> &IRB = OpBuilder.getIRB(); Type *Int8Ty = IRB.getInt8Ty(); @@ -656,7 +651,7 @@ class OpLowerer { SmallVector Args{ Handle, Index0, Index1, DataElements[0], DataElements[1], DataElements[2], DataElements[3], Mask}; - if (IsRaw && DXILVersion >= VersionTuple(1, 2)) { + if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) { Op = OpCode::RawBufferStore; // RawBufferStore requires the alignment Args.push_back( From cd1140819415b969aab130f9d8a6a5094964a993 Mon Sep 17 00:00:00 2001 From: Icohedron Date: Tue, 8 Jul 2025 17:14:07 +0000 Subject: [PATCH 5/5] Add const qualifier to MadeChanges --- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 8070651d7c97d..0ec15a629d0a2 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -911,7 +911,7 @@ PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) { DXILResourceTypeMap &DRTM = MAM.getResult(M); const ModuleMetadataInfo MMDI = MAM.getResult(M); - bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); + const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); if (!MadeChanges) return PreservedAnalyses::all(); PreservedAnalyses PA;