diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 995120309a938..0ec15a629d0a2 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. @@ -316,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); } @@ -486,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(); @@ -511,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) @@ -586,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(); @@ -654,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( @@ -745,6 +742,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 +831,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 +881,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 +909,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(); + const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics(); if (!MadeChanges) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -891,8 +929,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 +941,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 74% rename from llvm/test/CodeGen/DirectX/legalize-lifetimes.ll rename to llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.5.ll index 44b2419a05d64..e485fa20ddfce 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,7 @@ define void @test_legal_lifetime() { call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %accum.i.flat) 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 new file mode 100644 index 0000000000000..6552ccddddab4 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/legalize-lifetimes-valver-1.6.ll @@ -0,0 +1,31 @@ +; 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 +} + +; Set the validator version to 1.6 +!dx.valver = !{!0} +!0 = !{i32 1, i32 6}