diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 5bf8a785d528c..79f1586d12ead 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -38,7 +38,7 @@ def int_dx_resource_handlefromimplicitbinding def int_dx_resource_getpointer : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty], - [IntrNoMem]>; + [IntrConvergent, IntrNoMem]>; def int_dx_resource_nonuniformindex : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index 3d75d7455101f..50b657aab79fb 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -419,112 +419,6 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, llvm_unreachable("Unhandled case in switch"); } -static SmallVector collectBlockUseDef(Instruction *Start) { - SmallPtrSet Visited; - SmallVector Worklist; - SmallVector Out; - auto *BB = Start->getParent(); - - // Seed with direct users in this block. - for (User *U : Start->users()) { - if (auto *I = dyn_cast(U)) { - if (I->getParent() == BB) - Worklist.push_back(I); - } - } - - // BFS over transitive users, constrained to the same block. - while (!Worklist.empty()) { - Instruction *I = Worklist.pop_back_val(); - if (!Visited.insert(I).second) - continue; - Out.push_back(I); - - for (User *U : I->users()) { - if (auto *J = dyn_cast(U)) { - if (J->getParent() == BB) - Worklist.push_back(J); - } - } - for (Use &V : I->operands()) { - if (auto *J = dyn_cast(V)) { - if (J->getParent() == BB && V != Start) - Worklist.push_back(J); - } - } - } - - // Order results in program order. - DenseMap Ord; - unsigned Idx = 0; - for (Instruction &I : *BB) - Ord[&I] = Idx++; - - llvm::sort(Out, [&](Instruction *A, Instruction *B) { - return Ord.lookup(A) < Ord.lookup(B); - }); - - return Out; -} - -static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, - IRBuilder<> &Builder, - SmallVector &UsesInBlock) { - - ValueToValueMapTy VMap; - Value *Val = Phi->getIncomingValueForBlock(BB); - VMap[Phi] = Val; - Builder.SetInsertPoint(&BB->back()); - for (Instruction *I : UsesInBlock) { - // don't clone over the Phi just remap them - if (auto *PhiNested = dyn_cast(I)) { - VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB); - continue; - } - Instruction *Clone = I->clone(); - RemapInstruction(Clone, VMap, - RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); - Builder.Insert(Clone); - VMap[I] = Clone; - } -} - -static void phiNodeReplacement(IntrinsicInst *II, - SmallVectorImpl &PrevBBDeadInsts, - SetVector &DeadBB) { - SmallVector CurrBBDeadInsts; - for (User *U : II->users()) { - auto *Phi = dyn_cast(U); - if (!Phi) - continue; - - IRBuilder<> Builder(Phi); - SmallVector UsesInBlock = collectBlockUseDef(Phi); - bool HasReturnUse = isa(UsesInBlock.back()); - - for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) { - auto *CurrIncomingBB = Phi->getIncomingBlock(I); - phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock); - if (HasReturnUse) - PrevBBDeadInsts.push_back(&CurrIncomingBB->back()); - } - - CurrBBDeadInsts.push_back(Phi); - - for (Instruction *I : UsesInBlock) { - CurrBBDeadInsts.push_back(I); - } - if (HasReturnUse) { - BasicBlock *PhiBB = Phi->getParent(); - DeadBB.insert(PhiBB); - } - } - // Traverse the now-dead instructions in RPO and remove them. - for (Instruction *Dead : llvm::reverse(CurrBBDeadInsts)) - Dead->eraseFromParent(); - CurrBBDeadInsts.clear(); -} - static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { SmallVector Worklist; for (User *U : II->users()) @@ -560,27 +454,13 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) { SmallVector> Resources; - SetVector DeadBB; - SmallVector PrevBBDeadInsts; - for (BasicBlock &BB : make_early_inc_range(F)) { - for (Instruction &I : make_early_inc_range(BB)) - if (auto *II = dyn_cast(&I)) - if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) - phiNodeReplacement(II, PrevBBDeadInsts, DeadBB); - + for (BasicBlock &BB : make_early_inc_range(F)) for (Instruction &I : BB) if (auto *II = dyn_cast(&I)) if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) { auto *HandleTy = cast(II->getArgOperand(0)->getType()); Resources.emplace_back(II, DRTM[HandleTy]); } - } - for (auto *Dead : PrevBBDeadInsts) - Dead->eraseFromParent(); - PrevBBDeadInsts.clear(); - for (auto *Dead : DeadBB) - Dead->eraseFromParent(); - DeadBB.clear(); for (auto &[II, RI] : Resources) replaceAccess(II, RI); diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll deleted file mode 100644 index aa0179d82b09e..0000000000000 --- a/llvm/test/CodeGen/DirectX/issue-152348.ll +++ /dev/null @@ -1,158 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -S -dxil-resource-type -dxil-resource-access -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s - -; NOTE: The two LLVM IR functions below are simplified versions of this HLSL -; RWStructuredBuffer a; -; RWStructuredBuffer b; -; RWStructuredBuffer c; -; cbuffer d { -; uint e; -; uint f; -; uint g; -; uint h; -; } -; [numthreads(6, 8, 1)] void CSMain() { -; if (h) { -; float16_t i = b[f]; -; c[g] = i; -; } else if(h == g) { -; float16_t i = b[g]; -; c[h] = i; -; } else { -; float16_t i = a[e]; -; c[g] = i; -; } -; } - -%__cblayout_d = type <{ i32, i32, i32, i32 }> - -@.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1 -@d.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) poison -@e = external hidden local_unnamed_addr addrspace(2) global i32, align 4 -@d.str = internal unnamed_addr constant [2 x i8] c"d\00", align 1 - -define void @CSMain() local_unnamed_addr { -; CHECK-LABEL: define void @CSMain() local_unnamed_addr { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32 3, i32 0, i32 1, i32 0, ptr nonnull @d.str) -; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4 -; CHECK-NEXT: [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0 -; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] -; CHECK: [[IF_THEN_I]]: -; CHECK-NEXT: [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP1:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADE]], i32 0) -; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP0]], i32 [[LOADE]], i32 0, half [[TMP2]]) -; CHECK-NEXT: br label %[[_Z6CSMAINV_EXIT:.*]] -; CHECK: [[IF_ELSE_I]]: -; CHECK-NEXT: [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP4:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADE]], i32 0) -; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP3]], i32 [[LOADE]], i32 0, half [[TMP5]]) -; CHECK-NEXT: br label %[[_Z6CSMAINV_EXIT]] -; CHECK: [[_Z6CSMAINV_EXIT]]: -; CHECK-NEXT: ret void -; -entry: - %callCBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32 3, i32 0, i32 1, i32 0, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callCBufferBinding, ptr @d.cb, align 4 - %loadE = load i32, ptr addrspace(2) @e, align 4 - %tobool.not.i = icmp eq i32 %loadE, 0 - br i1 %tobool.not.i, label %if.else.i, label %if.then.i - -if.then.i: ; preds = %entry - %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) - %ifStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadE) - br label %_Z6CSMainv.exit - -if.else.i: ; preds = %entry - %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) - %elseStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %call2ndRawBufferBinding, i32 %loadE) - br label %_Z6CSMainv.exit - -_Z6CSMainv.exit: ; preds = %if.else.i, %if.then.i - %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ %elseStmtCallResourceGEP, %if.else.i ] - %call3rdRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) - %sinkCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %call3rdRawBufferBinding, i32 %loadE) - %loadSink = load half, ptr %.sink1, align 2 - store half %loadSink, ptr %sinkCallResourceGEP, align 2 - ret void -} - -define void @Main() local_unnamed_addr { -; CHECK-LABEL: define void @Main() local_unnamed_addr { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CALLRAWBUFFERBINDING1:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[CALLRAWBUFFERBINDING0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32 3, i32 0, i32 1, i32 0, ptr nonnull @d.str) -; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4 -; CHECK-NEXT: [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0 -; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] -; CHECK: [[IF_THEN_I]]: -; CHECK-NEXT: [[IFSTMTLOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP1:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 [[LOADE]], i32 0) -; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP0]], i32 [[IFSTMTLOADE]], i32 0, half [[TMP2]]) -; CHECK-NEXT: br label %[[_Z6MAINV_EXIT:.*]] -; CHECK: [[IF_ELSE_I]]: -; CHECK-NEXT: [[ELSESTMTLOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i32 [[ELSESTMTLOADE]], 0 -; CHECK-NEXT: br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label %[[IF_ELSE6_I:.*]] -; CHECK: [[IF_THEN2_I]]: -; CHECK-NEXT: [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP4:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 0, i32 0) -; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP3]], i32 0, i32 0, half [[TMP5]]) -; CHECK-NEXT: br label %[[_Z6MAINV_EXIT]] -; CHECK: [[IF_ELSE6_I]]: -; CHECK-NEXT: [[ELSESTMTLOADE2:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP6:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP7:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[CALLRAWBUFFERBINDING1]], i32 [[ELSESTMTLOADE2]], i32 0) -; CHECK-NEXT: [[TMP8:%.*]] = extractvalue { half, i1 } [[TMP7]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP6]], i32 [[ELSESTMTLOADE]], i32 0, half [[TMP8]]) -; CHECK-NEXT: br label %[[_Z6MAINV_EXIT]] -; CHECK: [[_Z6MAINV_EXIT]]: -; CHECK-NEXT: ret void -; -entry: - %callRawBufferBinding1 = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) - %callRawBufferBinding0 = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) - %callCBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32 3, i32 0, i32 1, i32 0, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callCBufferBinding, ptr @d.cb, align 4 - %loadE = load i32, ptr addrspace(2) @e, align 4 - %tobool.not.i = icmp eq i32 %loadE, 0 - br i1 %tobool.not.i, label %if.else.i, label %if.then.i - -if.then.i: ; preds = %entry - %ifStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %callRawBufferBinding0, i32 %loadE) - %ifStmtLoadE = load i32, ptr addrspace(2) @e, align 4 - br label %_Z6Mainv.exit - -if.else.i: ; preds = %entry - %elseStmtLoadE = load i32, ptr addrspace(2) @e, align 4 - %cmp.i = icmp eq i32 %elseStmtLoadE, 0 - br i1 %cmp.i, label %if.then2.i, label %if.else6.i - -if.then2.i: ; preds = %if.else.i - %elseifStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %callRawBufferBinding0, i32 0) - br label %_Z6Mainv.exit - -if.else6.i: ; preds = %if.else.i - %elseStmtLoadE2 = load i32, ptr addrspace(2) @e, align 4 - %elseStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %callRawBufferBinding1, i32 %elseStmtLoadE2) - br label %_Z6Mainv.exit - -_Z6Mainv.exit: ; preds = %if.else6.i, %if.then2.i, %if.then.i - %.sink2 = phi i32 [ %ifStmtLoadE, %if.then.i ], [ 0, %if.then2.i ], [ %elseStmtLoadE, %if.else6.i ] - %.sink.in = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ %elseifStmtCallResourceGEP, %if.then2.i ], [ %elseStmtCallResourceGEP, %if.else6.i ] - %callRawBufferBindingSink = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str) - %.sink = load half, ptr %.sink.in, align 2 - %i11 = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %callRawBufferBindingSink, i32 %.sink2) - store half %.sink, ptr %i11, align 2 - ret void -} diff --git a/llvm/test/CodeGen/DirectX/phi-node-replacement.ll b/llvm/test/CodeGen/DirectX/phi-node-replacement.ll deleted file mode 100644 index 6aef126cb5ecd..0000000000000 --- a/llvm/test/CodeGen/DirectX/phi-node-replacement.ll +++ /dev/null @@ -1,42 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -S -dxil-resource-type -dxil-resource-access -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s - -%"$Globals" = type { i32 } -@CBV = external constant %"$Globals" -@.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1 - -define half @CSMain() local_unnamed_addr { -; CHECK-LABEL: define half @CSMain() local_unnamed_addr { -; CHECK-NEXT: [[LOADGLOBAL:%.*]] = load i32, ptr @CBV, align 4 -; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADGLOBAL]], 0 -; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] -; CHECK: [[IF_THEN_I]]: -; CHECK-NEXT: [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP1:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADGLOBAL]], i32 0) -; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0 -; CHECK-NEXT: ret half [[TMP2]] -; CHECK: [[IF_ELSE_I]]: -; CHECK-NEXT: [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) -; CHECK-NEXT: [[TMP3:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADGLOBAL]], i32 0) -; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { half, i1 } [[TMP3]], 0 -; CHECK-NEXT: ret half [[TMP4]] -; - %loadGlobal = load i32, ptr @CBV, align 4 - %tobool.not.i = icmp eq i32 %loadGlobal, 0 - br i1 %tobool.not.i, label %if.else.i, label %if.then.i - - if.then.i: ; preds = %entry - %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str) - %ifStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadGlobal) - br label %_Z6CSMainv.exit - - if.else.i: ; preds = %entry - %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) - %elseStmtCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) %call2ndRawBufferBinding, i32 %loadGlobal) - br label %_Z6CSMainv.exit - - _Z6CSMainv.exit: ; preds = %if.else.i, %if.then.i - %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ %elseStmtCallResourceGEP, %if.else.i ] - %loadSink = load half, ptr %.sink1, align 2 - ret half %loadSink -} diff --git a/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll b/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll new file mode 100644 index 0000000000000..b1af3f6bd0846 --- /dev/null +++ b/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll @@ -0,0 +1,100 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -passes=gvn -passes=instnamer -S %s | FileCheck %s + +; This test ensures that given dx.resource.getpointer is marked convergent, the +; GVN pass is prevented from sinking these intrinsics. +; +; NOTE: The following ir represents case F and G from: +; https://godbolt.org/z/cK4xh1P49. + +%"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", i32, 1, 0, 1) } +%"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", i32, 1, 0), target("dx.RawBuffer", i32, 1, 0) } +%__cblayout_c = type <{ i32 }> + +@In = internal global %"class.hlsl::RWBuffer" poison, align 4 +@.str = private unnamed_addr constant [3 x i8] c"In\00", align 1 +@Out0 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +@.str.2 = private unnamed_addr constant [5 x i8] c"Out0\00", align 1 +@Out1 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +@.str.4 = private unnamed_addr constant [5 x i8] c"Out1\00", align 1 +@c.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_c) poison +@cond = external hidden local_unnamed_addr addrspace(2) global i32, align 4 +@c.str = private unnamed_addr constant [2 x i8] c"c\00", align 1 + +define void @main() local_unnamed_addr { +; CHECK-LABEL: define void @main() local_unnamed_addr { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = tail call target("dx.TypedBuffer", i32, 1, 0, 1) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_1_0_1t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) +; CHECK-NEXT: store target("dx.TypedBuffer", i32, 1, 0, 1) [[TMP0]], ptr @In, align 4 +; CHECK-NEXT: [[TMP1:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 1, i32 1, i32 0, ptr nonnull @.str.2) +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP1]], ptr @Out0, align 4 +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP1]], ptr getelementptr inbounds nuw (i8, ptr @Out0, i32 4), align 4 +; CHECK-NEXT: [[TMP2:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 2, i32 1, i32 0, ptr nonnull @.str.4) +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP2]], ptr @Out1, align 4 +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP2]], ptr getelementptr inbounds nuw (i8, ptr @Out1, i32 4), align 4 +; CHECK-NEXT: [[C_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", [[__CBLAYOUT_C:%.*]]) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_cst(i32 4, i32 0, i32 1, i32 0, ptr nonnull @c.str) +; CHECK-NEXT: store target("dx.CBuffer", [[__CBLAYOUT_C]]) [[C_CB_H_I_I]], ptr @c.cb, align 4 +; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @llvm.dx.flattened.thread.id.in.group() +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(2) @cond, align 4 +; CHECK-NEXT: [[LOADEDV_I:%.*]] = trunc nuw i32 [[TMP4]] to i1 +; CHECK-NEXT: br i1 [[LOADEDV_I]], label %[[IF_THEN_I:.*]], label %[[IF_ELSE_I:.*]] +; CHECK: [[IF_THEN_I]]: +; CHECK-NEXT: [[TMP5:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) [[TMP0]], i32 [[TMP3]]) +; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4 +; CHECK-NEXT: [[HLSL_WAVE_ACTIVE_SUM_I:%.*]] = tail call i32 @llvm.dx.wave.reduce.sum.i32(i32 [[TMP6]]) +; CHECK-NEXT: [[TMP7:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP1]], i32 [[TMP3]]) +; CHECK-NEXT: store i32 [[HLSL_WAVE_ACTIVE_SUM_I]], ptr [[TMP7]], align 4 +; CHECK-NEXT: br label %[[MAIN_EXIT:.*]] +; CHECK: [[IF_ELSE_I]]: +; CHECK-NEXT: [[TMP8:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) [[TMP0]], i32 [[TMP3]]) +; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4 +; CHECK-NEXT: [[TMP10:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP1]], i32 0) +; CHECK-NEXT: store i32 [[TMP9]], ptr [[TMP10]], align 4 +; CHECK-NEXT: br label %[[MAIN_EXIT]] +; CHECK: [[MAIN_EXIT]]: +; CHECK-NEXT: [[TMP11:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) [[TMP0]], i32 [[TMP3]]) +; CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4 +; CHECK-NEXT: [[HLSL_WAVE_ACTIVE_SUM5_I:%.*]] = tail call i32 @llvm.dx.wave.reduce.sum.i32(i32 [[TMP12]]) +; CHECK-NEXT: [[TMP13:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP1]], i32 [[TMP3]]) +; CHECK-NEXT: store i32 [[HLSL_WAVE_ACTIVE_SUM5_I]], ptr [[TMP13]], align 4 +; CHECK-NEXT: ret void +; +entry: + %0 = tail call target("dx.TypedBuffer", i32, 1, 0, 1) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_1_0_1t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) + store target("dx.TypedBuffer", i32, 1, 0, 1) %0, ptr @In, align 4 + %1 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 1, i32 1, i32 0, ptr nonnull @.str.2) + store target("dx.RawBuffer", i32, 1, 0) %1, ptr @Out0, align 4 + store target("dx.RawBuffer", i32, 1, 0) %1, ptr getelementptr inbounds nuw (i8, ptr @Out0, i32 4), align 4 + %2 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 2, i32 1, i32 0, ptr nonnull @.str.4) + store target("dx.RawBuffer", i32, 1, 0) %2, ptr @Out1, align 4 + store target("dx.RawBuffer", i32, 1, 0) %2, ptr getelementptr inbounds nuw (i8, ptr @Out1, i32 4), align 4 + %c.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_c) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_cst(i32 4, i32 0, i32 1, i32 0, ptr nonnull @c.str) + store target("dx.CBuffer", %__cblayout_c) %c.cb_h.i.i, ptr @c.cb, align 4 + %3 = tail call i32 @llvm.dx.flattened.thread.id.in.group() + %4 = load i32, ptr addrspace(2) @cond, align 4 + %loadedv.i = trunc nuw i32 %4 to i1 + br i1 %loadedv.i, label %if.then.i, label %if.else.i + +if.then.i: ; preds = %entry + %5 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %0, i32 %3) + %6 = load i32, ptr %5, align 4 + %hlsl.wave.active.sum.i = tail call i32 @llvm.dx.wave.reduce.sum.i32(i32 %6) + %7 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %1, i32 %3) + store i32 %hlsl.wave.active.sum.i, ptr %7, align 4 + br label %main.exit + +if.else.i: ; preds = %entry + %8 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %0, i32 %3) + %9 = load i32, ptr %8, align 4 + %10 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %1, i32 0) + store i32 %9, ptr %10, align 4 + br label %main.exit + +main.exit: ; preds = %if.then.i, %if.else.i + %11 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %0, i32 %3) + %12 = load i32, ptr %11, align 4 + %hlsl.wave.active.sum5.i = tail call i32 @llvm.dx.wave.reduce.sum.i32(i32 %12) + %13 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %1, i32 %3) + store i32 %hlsl.wave.active.sum5.i, ptr %13, align 4 + ret void +} diff --git a/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll b/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll new file mode 100644 index 0000000000000..4cc8a7e7f5012 --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll @@ -0,0 +1,131 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -passes=simplifycfg -passes=instnamer -S %s | FileCheck %s + +; This test ensures that given dx.resource.getpointer is marked convergent, the +; SimplifyCFG pass will be prevented from moving these intrinsics into the +; branches required for sinking handle retrieve before resource access. +; +; NOTE: The following test ir is generated from: +; https://godbolt.org/z/1EdGTbscE. + +%"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", i32, 1, 0), target("dx.RawBuffer", i32, 1, 0) } +%__cblayout_d = type <{ i32, i32, i32, i32 }> + +@a = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +@.str = private unnamed_addr constant [2 x i8] c"a\00", align 1 +@b = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +@.str.2 = private unnamed_addr constant [2 x i8] c"b\00", align 1 +@c = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +@.str.4 = private unnamed_addr constant [2 x i8] c"c\00", align 1 +@d.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_d) poison +@e = external hidden local_unnamed_addr addrspace(2) global i32, align 4 +@f = external hidden local_unnamed_addr addrspace(2) global i32, align 4 +@g = external hidden local_unnamed_addr addrspace(2) global i32, align 4 +@h = external hidden local_unnamed_addr addrspace(2) global i32, align 4 +@d.str = private unnamed_addr constant [2 x i8] c"d\00", align 1 + +define void @main() local_unnamed_addr { +; CHECK-LABEL: define void @main() local_unnamed_addr { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP0]], ptr @a, align 4 +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP0]], ptr getelementptr inbounds nuw (i8, ptr @a, i32 4), align 4 +; CHECK-NEXT: [[TMP1:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str.2) +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP1]], ptr @b, align 4 +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP1]], ptr getelementptr inbounds nuw (i8, ptr @b, i32 4), align 4 +; CHECK-NEXT: [[TMP2:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 4, i32 0, i32 1, i32 0, ptr nonnull @.str.4) +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP2]], ptr @c, align 4 +; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP2]], ptr getelementptr inbounds nuw (i8, ptr @c, i32 4), align 4 +; CHECK-NEXT: [[D_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", [[__CBLAYOUT_D:%.*]]) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_dst(i32 6, i32 0, i32 1, i32 0, ptr nonnull @d.str) +; CHECK-NEXT: store target("dx.CBuffer", [[__CBLAYOUT_D]]) [[D_CB_H_I_I]], ptr @d.cb, align 4 +; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(2) @h, align 4 +; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] +; CHECK: [[IF_THEN_I]]: +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(2) @f, align 4 +; CHECK-NEXT: [[TMP5:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP1]], i32 [[TMP4]]) +; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4 +; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr addrspace(2) @g, align 4 +; CHECK-NEXT: [[TMP8:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP2]], i32 [[TMP7]]) +; CHECK-NEXT: store i32 [[TMP6]], ptr [[TMP8]], align 4 +; CHECK-NEXT: br label %[[MAIN_EXIT:.*]] +; CHECK: [[IF_ELSE_I]]: +; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr addrspace(2) @g, align 4 +; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i32 [[TMP9]], 0 +; CHECK-NEXT: br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label %[[IF_ELSE6_I:.*]] +; CHECK: [[IF_THEN2_I]]: +; CHECK-NEXT: [[TMP10:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP1]], i32 0) +; CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4 +; CHECK-NEXT: [[TMP12:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP2]], i32 0) +; CHECK-NEXT: store i32 [[TMP11]], ptr [[TMP12]], align 4 +; CHECK-NEXT: br label %[[MAIN_EXIT]] +; CHECK: [[IF_ELSE6_I]]: +; CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP14:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP0]], i32 [[TMP13]]) +; CHECK-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4 +; CHECK-NEXT: [[TMP16:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP2]], i32 [[TMP9]]) +; CHECK-NEXT: store i32 [[TMP15]], ptr [[TMP16]], align 4 +; CHECK-NEXT: br label %[[MAIN_EXIT]] +; CHECK: [[MAIN_EXIT]]: +; CHECK-NEXT: [[TMP17:%.*]] = load i32, ptr addrspace(2) @f, align 4 +; CHECK-NEXT: [[TMP18:%.*]] = load i32, ptr addrspace(2) @g, align 4 +; CHECK-NEXT: [[TMP19:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP2]], i32 [[TMP18]]) +; CHECK-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4 +; CHECK-NEXT: [[ADD_I:%.*]] = add i32 [[TMP20]], [[TMP17]] +; CHECK-NEXT: store i32 [[ADD_I]], ptr [[TMP19]], align 4 +; CHECK-NEXT: ret void +; +entry: + %0 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str) + store target("dx.RawBuffer", i32, 1, 0) %0, ptr @a, align 4 + store target("dx.RawBuffer", i32, 1, 0) %0, ptr getelementptr inbounds nuw (i8, ptr @a, i32 4), align 4 + %1 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 2, i32 0, i32 1, i32 0, ptr nonnull @.str.2) + store target("dx.RawBuffer", i32, 1, 0) %1, ptr @b, align 4 + store target("dx.RawBuffer", i32, 1, 0) %1, ptr getelementptr inbounds nuw (i8, ptr @b, i32 4), align 4 + %2 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i32_1_0t(i32 4, i32 0, i32 1, i32 0, ptr nonnull @.str.4) + store target("dx.RawBuffer", i32, 1, 0) %2, ptr @c, align 4 + store target("dx.RawBuffer", i32, 1, 0) %2, ptr getelementptr inbounds nuw (i8, ptr @c, i32 4), align 4 + %d.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_d) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_dst(i32 6, i32 0, i32 1, i32 0, ptr nonnull @d.str) + store target("dx.CBuffer", %__cblayout_d) %d.cb_h.i.i, ptr @d.cb, align 4 + %3 = load i32, ptr addrspace(2) @h, align 4 + %tobool.not.i = icmp eq i32 %3, 0 + br i1 %tobool.not.i, label %if.else.i, label %if.then.i + +if.then.i: ; preds = %entry + %4 = load i32, ptr addrspace(2) @f, align 4 + %5 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %1, i32 %4) + %6 = load i32, ptr %5, align 4 + %7 = load i32, ptr addrspace(2) @g, align 4 + %8 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %2, i32 %7) + store i32 %6, ptr %8, align 4 + br label %main.exit + +if.else.i: ; preds = %entry + %9 = load i32, ptr addrspace(2) @g, align 4 + %cmp.i = icmp eq i32 %9, 0 + br i1 %cmp.i, label %if.then2.i, label %if.else6.i + +if.then2.i: ; preds = %if.else.i + %10 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %1, i32 0) + %11 = load i32, ptr %10, align 4 + %12 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %2, i32 0) + store i32 %11, ptr %12, align 4 + br label %main.exit + +if.else6.i: ; preds = %if.else.i + %13 = load i32, ptr addrspace(2) @e, align 4 + %14 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %0, i32 %13) + %15 = load i32, ptr %14, align 4 + %16 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %2, i32 %9) + store i32 %15, ptr %16, align 4 + br label %main.exit + +main.exit: ; preds = %if.then.i, %if.then2.i, %if.else6.i + %17 = load i32, ptr addrspace(2) @f, align 4 + %18 = load i32, ptr addrspace(2) @g, align 4 + %19 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %2, i32 %18) + %20 = load i32, ptr %19, align 4 + %add.i = add i32 %20, %17 + store i32 %add.i, ptr %19, align 4 + ret void +}