https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/154620
>From b51b68d7b5e7019687f2b8617178f2a8d9932278 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Wed, 20 Aug 2025 17:11:37 -0400 Subject: [PATCH 01/14] [DirectX] Make dx.RawBuffer an op that can't be replaced fixes #152348 SimplifyCFG collapses raw buffer store from a if\else load into a select. This change prevents the TargetExtType dx.Rawbuffer from being replace thus preserving the if\else blocks. A further change was needed to eliminate the phi node before we process Intrinsic::dx_resource_getpointer in DXILResourceAccess.cpp --- .../lib/Target/DirectX/DXILResourceAccess.cpp | 106 +++++++++++++++++- llvm/lib/Transforms/Utils/Local.cpp | 4 + llvm/test/CodeGen/DirectX/issue-152348.ll | 73 ++++++++++++ 3 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 llvm/test/CodeGen/DirectX/issue-152348.ll diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index c33ec0efd73ca..59e49d6f24201 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -9,13 +9,17 @@ #include "DXILResourceAccess.h" #include "DirectX.h" #include "llvm/Analysis/DXILResource.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsDirectX.h" +#include "llvm/IR/User.h" #include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/ValueMapper.h" #define DEBUG_TYPE "dxil-resource-access" @@ -198,6 +202,98 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset, llvm_unreachable("Unhandled case in switch"); } +static void collectBlockUseDef(Instruction *Start, + SmallVectorImpl<Instruction *> &Out) { + SmallPtrSet<Instruction *, 32> Visited; + SmallVector<Instruction *, 32> Worklist; + auto *BB = Start->getParent(); + + // Seed with direct users in this block. + for (User *U : Start->users()) { + if (auto *I = dyn_cast<Instruction>(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<Instruction>(U)) { + if (J->getParent() == BB) + Worklist.push_back(J); + } + } + for (Use &V : I->operands()) { + if (auto *J = dyn_cast<Instruction>(V)) { + if (J->getParent() == BB && V != Start) + Worklist.push_back(J); + } + } + } + + // Order results in program order. + DenseMap<const Instruction *, unsigned> 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); + }); +} + +static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, + IRBuilder<> &Builder, + SmallVector<Instruction *> &UsesInBlock) { + + ValueToValueMapTy VMap; + Value *Val = Phi->getIncomingValueForBlock(BB); + VMap[Phi] = Val; + Builder.SetInsertPoint(llvm::dyn_cast<Instruction>(Val)->getNextNode()); + for (Instruction *I : UsesInBlock) { + Instruction *ThenClone = I->clone(); + RemapInstruction(ThenClone, VMap, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + Builder.Insert(ThenClone); + VMap[I] = ThenClone; + } +} + +static void phiNodeReplacement(IntrinsicInst *II) { + SmallVector<Instruction *> DeadInsts; + for (User *U : II->users()) { + if (auto *Phi = dyn_cast<PHINode>(U)) { + + auto *ThenBB = Phi->getIncomingBlock(0); + auto *ElseBB = Phi->getIncomingBlock(1); + IRBuilder<> Builder(Phi); + + SmallVector<Instruction *> UsesInBlock; + collectBlockUseDef(Phi, UsesInBlock); + + phiNodeRemapHelper(Phi, ThenBB, Builder, UsesInBlock); + phiNodeRemapHelper(Phi, ElseBB, Builder, UsesInBlock); + + DeadInsts.push_back(Phi); + + for (Instruction *I : UsesInBlock) { + DeadInsts.push_back(I); + } + } + } + + // Traverse the now-dead instructions in RPO and remove them. + for (Instruction *Dead : llvm::reverse(DeadInsts)) + Dead->eraseFromParent(); + DeadInsts.clear(); +} + static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { // Process users keeping track of indexing accumulated from GEPs. struct AccessAndOffset { @@ -229,7 +325,6 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { } else if (auto *LI = dyn_cast<LoadInst>(Current.Access)) { createLoadIntrinsic(II, LI, Current.Offset, RTI); DeadInsts.push_back(LI); - } else llvm_unreachable("Unhandled instruction - pointer escaped?"); } @@ -242,13 +337,19 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) { SmallVector<std::pair<IntrinsicInst *, dxil::ResourceTypeInfo>> Resources; - for (BasicBlock &BB : F) + for (BasicBlock &BB : F) { + for (Instruction &I : make_early_inc_range(BB)) + if (auto *II = dyn_cast<IntrinsicInst>(&I)) + if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) + phiNodeReplacement(II); + for (Instruction &I : BB) if (auto *II = dyn_cast<IntrinsicInst>(&I)) if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) { auto *HandleTy = cast<TargetExtType>(II->getArgOperand(0)->getType()); Resources.emplace_back(II, DRTM[HandleTy]); } + } for (auto &[II, RI] : Resources) replaceAccess(II, RI); @@ -279,7 +380,6 @@ class DXILResourceAccessLegacy : public FunctionPass { bool runOnFunction(Function &F) override { DXILResourceTypeMap &DRTM = getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); - return transformResourcePointers(F, DRTM); } StringRef getPassName() const override { return "DXIL Resource Access"; } diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 9d759bc244e3d..1faf6f0ae5993 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3852,6 +3852,10 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { if (I->isLifetimeStartOrEnd()) return false; + if (auto *TT = dyn_cast<TargetExtType>(Op->getType()); + TT && TT->getName() == "dx.RawBuffer") + return false; + // Early exit. if (!isa<Constant, InlineAsm>(Op)) return true; diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll new file mode 100644 index 0000000000000..508a1681d1258 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/issue-152348.ll @@ -0,0 +1,73 @@ +; 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 + +%__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: [[D_CB_H_I_I:%.*]] = 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, i1 false, ptr nonnull @d.str) +; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4 +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP0]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] +; CHECK: [[IF_THEN_I]]: +; CHECK-NEXT: [[TMP2:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP4:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP5:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP2]], i32 [[TMP3]], i32 0) +; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { half, i1 } [[TMP5]], 0 +; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP4]], i32 [[TMP1]], i32 0, half [[TMP6]]) +; CHECK-NEXT: br label %[[_Z6CSMAINV_EXIT:.*]] +; CHECK: [[IF_ELSE_I]]: +; CHECK-NEXT: [[TMP7:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP9:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP10:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP7]], i32 [[TMP8]], i32 0) +; CHECK-NEXT: [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0 +; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP9]], i32 [[TMP1]], i32 0, half [[TMP11]]) +; CHECK-NEXT: br label %[[_Z6CSMAINV_EXIT]] +; CHECK: [[_Z6CSMAINV_EXIT]]: +; CHECK-NEXT: ret void +; +entry: + %d.cb_h.i.i = 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, i1 false, ptr nonnull @d.str) + store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %d.cb_h.i.i, ptr @d.cb, align 4 + %0 = load i32, ptr addrspace(2) @e, align 4 + %tobool.not.i = icmp eq i32 %0, 0 + %1 = load i32, ptr addrspace(2) @e, align 4 + br i1 %tobool.not.i, label %if.else.i, label %if.then.i + +if.then.i: ; preds = %entry + %2 = 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, i1 false, ptr nonnull @.str) + %3 = load i32, ptr addrspace(2) @e, align 4 + %4 = 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) %2, i32 %3) + br label %_Z6CSMainv.exit + +if.else.i: ; preds = %entry + %5 = 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, i1 false, ptr nonnull @.str) + %6 = load i32, ptr addrspace(2) @e, align 4 + %7 = 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) %5, i32 %6) + br label %_Z6CSMainv.exit + +_Z6CSMainv.exit: ; preds = %if.then.i, %if.else.i + %.sink1 = phi ptr [ %4, %if.then.i ], [ %7, %if.else.i ] + %8 = 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, i1 false, ptr nonnull @.str) + %9 = 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) %8, i32 %1) + %10 = load half, ptr %.sink1, align 2 + store half %10, ptr %9, align 2 + ret void + +; uselistorder directives + uselistorder label %_Z6CSMainv.exit, { 1, 0 } +} + +; uselistorder directives +uselistorder ptr @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t, { 1, 2, 0 } >From c7d44abef414110dda945298d58f7ff339416d76 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 21 Aug 2025 11:00:13 -0400 Subject: [PATCH 02/14] update to handle multiple phi nodes --- .../lib/Target/DirectX/DXILResourceAccess.cpp | 24 +++--- llvm/test/CodeGen/DirectX/issue-152348.ll | 82 +++++++++++++++++-- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index 59e49d6f24201..e09e71b679031 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -255,13 +255,18 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, ValueToValueMapTy VMap; Value *Val = Phi->getIncomingValueForBlock(BB); VMap[Phi] = Val; - Builder.SetInsertPoint(llvm::dyn_cast<Instruction>(Val)->getNextNode()); + Builder.SetInsertPoint(&BB->back()); for (Instruction *I : UsesInBlock) { - Instruction *ThenClone = I->clone(); - RemapInstruction(ThenClone, VMap, + // don't clone over the Phi just remap them + if (auto *PhiNested = dyn_cast<PHINode>(I)) { + VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB); + continue; + } + Instruction *Clone = I->clone(); + RemapInstruction(Clone, VMap, RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); - Builder.Insert(ThenClone); - VMap[I] = ThenClone; + Builder.Insert(Clone); + VMap[I] = Clone; } } @@ -270,15 +275,14 @@ static void phiNodeReplacement(IntrinsicInst *II) { for (User *U : II->users()) { if (auto *Phi = dyn_cast<PHINode>(U)) { - auto *ThenBB = Phi->getIncomingBlock(0); - auto *ElseBB = Phi->getIncomingBlock(1); IRBuilder<> Builder(Phi); - SmallVector<Instruction *> UsesInBlock; collectBlockUseDef(Phi, UsesInBlock); - phiNodeRemapHelper(Phi, ThenBB, Builder, UsesInBlock); - phiNodeRemapHelper(Phi, ElseBB, Builder, UsesInBlock); + for (uint I = 0; I < Phi->getNumIncomingValues(); I++) { + auto *CurrIncomingBB = Phi->getIncomingBlock(I); + phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock); + } DeadInsts.push_back(Phi); diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll index 508a1681d1258..693f01457bdc6 100644 --- a/llvm/test/CodeGen/DirectX/issue-152348.ll +++ b/llvm/test/CodeGen/DirectX/issue-152348.ll @@ -6,7 +6,6 @@ @.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 { @@ -64,10 +63,81 @@ _Z6CSMainv.exit: ; preds = %if.then.i, %if.else %10 = load half, ptr %.sink1, align 2 store half %10, ptr %9, align 2 ret void - -; uselistorder directives - uselistorder label %_Z6CSMainv.exit, { 1, 0 } } -; uselistorder directives -uselistorder ptr @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t, { 1, 2, 0 } +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", half, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 0, i32 1, i32 0, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP1:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[D_CB_H_I_I:%.*]] = 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, i1 false, ptr nonnull @d.str) +; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4 +; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP2]], 0 +; CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label %[[IF_THEN_I:.*]] +; CHECK: [[IF_THEN_I]]: +; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP5:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP6:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP1]], i32 [[TMP3]], i32 0) +; CHECK-NEXT: [[TMP7:%.*]] = extractvalue { half, i1 } [[TMP6]], 0 +; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP5]], i32 [[TMP4]], i32 0, half [[TMP7]]) +; CHECK-NEXT: br label %[[_Z6MAINV_EXIT:.*]] +; CHECK: [[IF_ELSE_I]]: +; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label %[[IF_ELSE6_I:.*]] +; CHECK: [[IF_THEN2_I]]: +; CHECK-NEXT: [[TMP9:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP10:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP1]], i32 0, i32 0) +; CHECK-NEXT: [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0 +; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP9]], i32 0, i32 0, half [[TMP11]]) +; CHECK-NEXT: br label %[[_Z6MAINV_EXIT]] +; CHECK: [[IF_ELSE6_I]]: +; CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; CHECK-NEXT: [[TMP13:%.*]] = 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, i1 false, ptr nonnull @.str) +; CHECK-NEXT: [[TMP14:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP0]], i32 [[TMP12]], i32 0) +; CHECK-NEXT: [[TMP15:%.*]] = extractvalue { half, i1 } [[TMP14]], 0 +; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP13]], i32 [[TMP8]], i32 0, half [[TMP15]]) +; CHECK-NEXT: br label %[[_Z6MAINV_EXIT]] +; CHECK: [[_Z6MAINV_EXIT]]: +; CHECK-NEXT: ret void +; +entry: + %0 = 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, i1 false, ptr nonnull @.str) + %1 = 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, i1 false, ptr nonnull @.str) + %d.cb_h.i.i = 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, i1 false, ptr nonnull @d.str) + store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %d.cb_h.i.i, ptr @d.cb, align 4 + %2 = load i32, ptr addrspace(2) @e, align 4 + %tobool.not.i = icmp eq i32 %2, 0 + br i1 %tobool.not.i, label %if.else.i, label %if.then.i + +if.then.i: ; preds = %entry + %3 = load i32, ptr addrspace(2) @e, align 4 + %4 = 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) %1, i32 %3) + %5 = load i32, ptr addrspace(2) @e, align 4 + br label %_Z6Mainv.exit + +if.else.i: ; preds = %entry + %6 = load i32, ptr addrspace(2) @e, align 4 + %cmp.i = icmp eq i32 %6, 0 + br i1 %cmp.i, label %if.then2.i, label %if.else6.i + +if.then2.i: ; preds = %if.else.i + %7 = 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) %1, i32 0) + br label %_Z6Mainv.exit + +if.else6.i: ; preds = %if.else.i + %8 = load i32, ptr addrspace(2) @e, align 4 + %9 = 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) %0, i32 %8) + br label %_Z6Mainv.exit + +_Z6Mainv.exit: ; preds = %if.then.i, %if.then2.i, %if.else6.i + %.sink2 = phi i32 [ %5, %if.then.i ], [ 0, %if.then2.i ], [ %6, %if.else6.i ] + %.sink.in = phi ptr [ %4, %if.then.i ], [ %7, %if.then2.i ], [ %9, %if.else6.i ] + %10 = 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, i1 false, ptr nonnull @.str) + %.sink = load half, ptr %.sink.in, align 2 + %11 = 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) %10, i32 %.sink2) + store half %.sink, ptr %11, align 2 + ret void +} >From 4853d0ec2e911190011abd0c54871c00f2173d57 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 21 Aug 2025 12:06:10 -0400 Subject: [PATCH 03/14] create new NoReplacement property --- llvm/include/llvm/IR/DerivedTypes.h | 2 ++ llvm/lib/IR/Type.cpp | 3 ++- llvm/lib/Transforms/Utils/Local.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h index fa62bc09b61a3..7810be22d1e99 100644 --- a/llvm/include/llvm/IR/DerivedTypes.h +++ b/llvm/include/llvm/IR/DerivedTypes.h @@ -847,6 +847,8 @@ class TargetExtType : public Type { CanBeLocal = 1U << 2, // This type may be used as an element in a vector. CanBeVectorElement = 1U << 3, + // This type can not be replaced in an optimization pass. + NoReplacement = 1U << 4, }; /// Returns true if the target extension type contains the given property. diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index 9c34662340352..7513debc2ed3a 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -1036,7 +1036,8 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) { // DirectX resources if (Name.starts_with("dx.")) return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal, - TargetExtType::CanBeLocal); + TargetExtType::CanBeLocal, + TargetExtType::NoReplacement); // Opaque types in the AMDGPU name space. if (Name == "amdgcn.named.barrier") { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 1faf6f0ae5993..b5917058c6559 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3853,7 +3853,7 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { return false; if (auto *TT = dyn_cast<TargetExtType>(Op->getType()); - TT && TT->getName() == "dx.RawBuffer") + TT && TT->hasProperty(TargetExtType::Property::NoReplacement)) return false; // Early exit. >From 90847c2ebb67ef3b28428bf726bdfe01aa3212c8 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Tue, 26 Aug 2025 17:07:14 -0400 Subject: [PATCH 04/14] address PR comments --- .../lib/Target/DirectX/DXILResourceAccess.cpp | 25 ++++++++++--------- llvm/test/CodeGen/DirectX/issue-152348.ll | 23 +++++++++++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index e09e71b679031..cbd2514716c0f 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -273,22 +273,23 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, static void phiNodeReplacement(IntrinsicInst *II) { SmallVector<Instruction *> DeadInsts; for (User *U : II->users()) { - if (auto *Phi = dyn_cast<PHINode>(U)) { + auto *Phi = dyn_cast<PHINode>(U); + if (!Phi) + continue; - IRBuilder<> Builder(Phi); - SmallVector<Instruction *> UsesInBlock; - collectBlockUseDef(Phi, UsesInBlock); + IRBuilder<> Builder(Phi); + SmallVector<Instruction *> UsesInBlock; + collectBlockUseDef(Phi, UsesInBlock); - for (uint I = 0; I < Phi->getNumIncomingValues(); I++) { - auto *CurrIncomingBB = Phi->getIncomingBlock(I); - phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock); - } + for (uint I = 0; I < Phi->getNumIncomingValues(); I++) { + auto *CurrIncomingBB = Phi->getIncomingBlock(I); + phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock); + } - DeadInsts.push_back(Phi); + DeadInsts.push_back(Phi); - for (Instruction *I : UsesInBlock) { - DeadInsts.push_back(I); - } + for (Instruction *I : UsesInBlock) { + DeadInsts.push_back(I); } } diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll index 693f01457bdc6..8bbe131563221 100644 --- a/llvm/test/CodeGen/DirectX/issue-152348.ll +++ b/llvm/test/CodeGen/DirectX/issue-152348.ll @@ -1,6 +1,29 @@ ; 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<float16_t> a; +; RWStructuredBuffer<float16_t> b; +; RWStructuredBuffer<float16_t> 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 >From 2ead86b7765ab43ec081dac6fbb6d3503c16ea3f Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Wed, 27 Aug 2025 15:31:23 -0400 Subject: [PATCH 05/14] address partial pr comments --- .../lib/Target/DirectX/DXILResourceAccess.cpp | 2 +- llvm/test/CodeGen/DirectX/issue-152348.ll | 146 +++++++++--------- llvm/unittests/Transforms/Utils/LocalTest.cpp | 8 + 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index cbd2514716c0f..c569ab8adfcf0 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -281,7 +281,7 @@ static void phiNodeReplacement(IntrinsicInst *II) { SmallVector<Instruction *> UsesInBlock; collectBlockUseDef(Phi, UsesInBlock); - for (uint I = 0; I < Phi->getNumIncomingValues(); I++) { + for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) { auto *CurrIncomingBB = Phi->getIncomingBlock(I); phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock); } diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll index 8bbe131563221..66aeafb7785e3 100644 --- a/llvm/test/CodeGen/DirectX/issue-152348.ll +++ b/llvm/test/CodeGen/DirectX/issue-152348.ll @@ -34,133 +34,125 @@ define void @CSMain() local_unnamed_addr { ; CHECK-LABEL: define void @CSMain() local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[D_CB_H_I_I:%.*]] = 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, i1 false, ptr nonnull @d.str) -; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4 -; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP0]], 0 -; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(2) @e, align 4 +; 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, i1 false, 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: [[TMP2:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP4:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP5:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP2]], i32 [[TMP3]], i32 0) -; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { half, i1 } [[TMP5]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP4]], i32 [[TMP1]], i32 0, half [[TMP6]]) +; 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, i1 false, 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, i1 false, 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: [[TMP7:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP9:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP10:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP7]], i32 [[TMP8]], i32 0) -; CHECK-NEXT: [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP9]], i32 [[TMP1]], i32 0, half [[TMP11]]) +; 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, i1 false, 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, i1 false, 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: - %d.cb_h.i.i = 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, i1 false, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %d.cb_h.i.i, ptr @d.cb, align 4 - %0 = load i32, ptr addrspace(2) @e, align 4 - %tobool.not.i = icmp eq i32 %0, 0 - %1 = load i32, ptr addrspace(2) @e, align 4 + %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, i1 false, ptr nonnull @d.str) + store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callRawBufferBinding, 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 - %2 = 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, i1 false, ptr nonnull @.str) - %3 = load i32, ptr addrspace(2) @e, align 4 - %4 = 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) %2, i32 %3) + %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, i1 false, 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 - %5 = 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, i1 false, ptr nonnull @.str) - %6 = load i32, ptr addrspace(2) @e, align 4 - %7 = 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) %5, i32 %6) + %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, i1 false, 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.then.i, %if.else.i - %.sink1 = phi ptr [ %4, %if.then.i ], [ %7, %if.else.i ] - %8 = 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, i1 false, ptr nonnull @.str) - %9 = 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) %8, i32 %1) - %10 = load half, ptr %.sink1, align 2 - store half %10, ptr %9, align 2 +_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, i1 false, 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: [[TMP0:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP1:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[D_CB_H_I_I:%.*]] = 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, i1 false, ptr nonnull @d.str) -; CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", [[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4 -; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP2]], 0 +; 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, i1 false, 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, i1 false, 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, i1 false, 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: [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP5:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP6:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP1]], i32 [[TMP3]], i32 0) -; CHECK-NEXT: [[TMP7:%.*]] = extractvalue { half, i1 } [[TMP6]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP5]], i32 [[TMP4]], i32 0, half [[TMP7]]) +; 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, i1 false, 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: [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i32 [[TMP8]], 0 +; 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: [[TMP9:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP10:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP1]], i32 0, i32 0) -; CHECK-NEXT: [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP9]], i32 0, i32 0, half [[TMP11]]) +; 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, i1 false, 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: [[TMP12:%.*]] = load i32, ptr addrspace(2) @e, align 4 -; CHECK-NEXT: [[TMP13:%.*]] = 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, i1 false, ptr nonnull @.str) -; CHECK-NEXT: [[TMP14:%.*]] = call { half, i1 } @llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", half, 1, 0) [[TMP0]], i32 [[TMP12]], i32 0) -; CHECK-NEXT: [[TMP15:%.*]] = extractvalue { half, i1 } [[TMP14]], 0 -; CHECK-NEXT: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer", half, 1, 0) [[TMP13]], i32 [[TMP8]], i32 0, half [[TMP15]]) +; 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, i1 false, 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: - %0 = 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, i1 false, ptr nonnull @.str) - %1 = 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, i1 false, ptr nonnull @.str) - %d.cb_h.i.i = 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, i1 false, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %d.cb_h.i.i, ptr @d.cb, align 4 - %2 = load i32, ptr addrspace(2) @e, align 4 - %tobool.not.i = icmp eq i32 %2, 0 + %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, i1 false, 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, i1 false, ptr nonnull @.str) + %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, i1 false, ptr nonnull @d.str) + store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callRawBufferBinding, 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 - %3 = load i32, ptr addrspace(2) @e, align 4 - %4 = 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) %1, i32 %3) - %5 = load i32, ptr addrspace(2) @e, align 4 + %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 - %6 = load i32, ptr addrspace(2) @e, align 4 - %cmp.i = icmp eq i32 %6, 0 + %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 - %7 = 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) %1, i32 0) + %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 - %8 = load i32, ptr addrspace(2) @e, align 4 - %9 = 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) %0, i32 %8) + %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.then.i, %if.then2.i, %if.else6.i - %.sink2 = phi i32 [ %5, %if.then.i ], [ 0, %if.then2.i ], [ %6, %if.else6.i ] - %.sink.in = phi ptr [ %4, %if.then.i ], [ %7, %if.then2.i ], [ %9, %if.else6.i ] - %10 = 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, i1 false, ptr nonnull @.str) +_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, i1 false, ptr nonnull @.str) %.sink = load half, ptr %.sink.in, align 2 - %11 = 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) %10, i32 %.sink2) - store half %.sink, ptr %11, 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/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp index 0c70feb64e7e4..194684d86558f 100644 --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -1057,6 +1057,14 @@ TEST(Local, SimplifyCFGWithNullAC) { RequireAndPreserveDomTree ? &DTU : nullptr, Options)); } +TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) { + LLVMContext Ctx; + SmallVector<unsigned, 3> Ints = {}; + auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints); + + EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::NoReplacement)); +} + TEST(Local, CanReplaceOperandWithVariable) { LLVMContext Ctx; Module M("test_module", Ctx); >From e6af51390e1929e5ea8f4258442935d4ad705ad6 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Wed, 27 Aug 2025 15:55:00 -0400 Subject: [PATCH 06/14] address more pr feedback --- llvm/include/llvm/IR/DerivedTypes.h | 6 +++--- llvm/lib/IR/Type.cpp | 2 +- llvm/lib/Transforms/Utils/Local.cpp | 2 +- llvm/unittests/Transforms/Utils/LocalTest.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h index 7810be22d1e99..5db79b82ac61d 100644 --- a/llvm/include/llvm/IR/DerivedTypes.h +++ b/llvm/include/llvm/IR/DerivedTypes.h @@ -845,10 +845,10 @@ class TargetExtType : public Type { /// This type may be allocated on the stack, either as the allocated type /// of an alloca instruction or as a byval function parameter. CanBeLocal = 1U << 2, - // This type may be used as an element in a vector. + /// This type may be used as an element in a vector. CanBeVectorElement = 1U << 3, - // This type can not be replaced in an optimization pass. - NoReplacement = 1U << 4, + /// All uses of this type must not attempt to introspect or obscure it. + IsTokenLike = 1U << 4, }; /// Returns true if the target extension type contains the given property. diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index 7513debc2ed3a..d3aec2610e068 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -1037,7 +1037,7 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) { if (Name.starts_with("dx.")) return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal, TargetExtType::CanBeLocal, - TargetExtType::NoReplacement); + TargetExtType::IsTokenLike); // Opaque types in the AMDGPU name space. if (Name == "amdgcn.named.barrier") { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index b5917058c6559..81e4551d78806 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3853,7 +3853,7 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { return false; if (auto *TT = dyn_cast<TargetExtType>(Op->getType()); - TT && TT->hasProperty(TargetExtType::Property::NoReplacement)) + TT && TT->hasProperty(TargetExtType::Property::IsTokenLike)) return false; // Early exit. diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp index 194684d86558f..4b53cc3d6e516 100644 --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -1061,8 +1061,8 @@ TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) { LLVMContext Ctx; SmallVector<unsigned, 3> Ints = {}; auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints); - - EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::NoReplacement)); + + EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::IsTokenLike)); } TEST(Local, CanReplaceOperandWithVariable) { >From 533dc4f09ebb0309532f01edcb3e443be4f84a3e Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Wed, 27 Aug 2025 16:28:21 -0400 Subject: [PATCH 07/14] make an is isTokenLikeTy() helper --- llvm/include/llvm/IR/Type.h | 9 +++++++++ llvm/lib/Transforms/Utils/Local.cpp | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 74dd490729741..8fc7a8198e80c 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -15,6 +15,7 @@ #define LLVM_IR_TYPE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -233,6 +234,14 @@ class Type { /// Return true if this is 'token'. bool isTokenTy() const { return getTypeID() == TokenTyID; } + // Returns true if this is 'token' or 'token-like'. + bool isTokenLikeTy() const { + if (isTokenTy()) + return true; + if (auto *TT = dyn_cast<TargetExtType>(this)) + return TT->hasProperty(TargetExtType::Property::IsTokenLike); + } + /// True if this is an instance of IntegerType. bool isIntegerTy() const { return getTypeID() == IntegerTyID; } diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 81e4551d78806..0eb92470045ea 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3852,8 +3852,7 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { if (I->isLifetimeStartOrEnd()) return false; - if (auto *TT = dyn_cast<TargetExtType>(Op->getType()); - TT && TT->hasProperty(TargetExtType::Property::IsTokenLike)) + if (Op->getType()->isTokenLikeTy()) return false; // Early exit. >From 74a568f7d03f698b9eb45e72d67bb3b24518a6d0 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 12:23:02 -0400 Subject: [PATCH 08/14] fix isTokenLikeTy implementation --- llvm/include/llvm/IR/Type.h | 11 ++--------- llvm/lib/IR/Type.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 8fc7a8198e80c..0c8f960966cd5 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -15,7 +15,6 @@ #define LLVM_IR_TYPE_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/IR/DerivedTypes.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -26,7 +25,6 @@ #include <iterator> namespace llvm { - class IntegerType; struct fltSemantics; class LLVMContext; @@ -234,13 +232,8 @@ class Type { /// Return true if this is 'token'. bool isTokenTy() const { return getTypeID() == TokenTyID; } - // Returns true if this is 'token' or 'token-like'. - bool isTokenLikeTy() const { - if (isTokenTy()) - return true; - if (auto *TT = dyn_cast<TargetExtType>(this)) - return TT->hasProperty(TargetExtType::Property::IsTokenLike); - } + /// Returns true if this is 'token' or 'token-like'. + bool isTokenLikeTy() const; /// True if this is an instance of IntegerType. bool isIntegerTy() const { return getTypeID() == IntegerTyID; } diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index d3aec2610e068..9db48e8f6a96b 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -1055,6 +1055,14 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) { return TargetTypeInfo(Type::getVoidTy(C)); } +bool Type::isTokenLikeTy() const { + if (isTokenTy()) + return true; + if (auto *TT = dyn_cast<TargetExtType>(this)) + return TT->hasProperty(TargetExtType::Property::IsTokenLike); + return false; +} + Type *TargetExtType::getLayoutType() const { return getTargetTypeInfo(this).LayoutType; } >From 65f6d7a3ebfd3e24e0e9cb8c061f5e2cc5115993 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 13:14:28 -0400 Subject: [PATCH 09/14] PR #155332 changed the handlefromimplicitbinding intrinsic signature. test needed to be updated --- llvm/test/CodeGen/DirectX/issue-152348.ll | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll b/llvm/test/CodeGen/DirectX/issue-152348.ll index 66aeafb7785e3..aa0179d82b09e 100644 --- a/llvm/test/CodeGen/DirectX/issue-152348.ll +++ b/llvm/test/CodeGen/DirectX/issue-152348.ll @@ -34,21 +34,21 @@ 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, i1 false, ptr nonnull @d.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: [[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, i1 false, 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, i1 false, ptr nonnull @.str) +; 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, i1 false, 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, i1 false, ptr nonnull @.str) +; 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]]) @@ -57,25 +57,25 @@ define void @CSMain() local_unnamed_addr { ; CHECK-NEXT: ret void ; entry: - %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, i1 false, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callRawBufferBinding, ptr @d.cb, align 4 + %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, i1 false, ptr nonnull @.str) + %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, i1 false, ptr nonnull @.str) + %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, i1 false, ptr nonnull @.str) + %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 @@ -85,16 +85,16 @@ _Z6CSMainv.exit: ; preds = %if.else.i, %if.then 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, i1 false, 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, i1 false, 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, i1 false, ptr nonnull @d.str) +; 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, i1 false, 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) [[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]]) @@ -104,14 +104,14 @@ define void @Main() local_unnamed_addr { ; 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, i1 false, 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) [[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, i1 false, ptr nonnull @.str) +; 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]]) @@ -120,10 +120,10 @@ define void @Main() local_unnamed_addr { ; 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, i1 false, 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, i1 false, ptr nonnull @.str) - %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, i1 false, ptr nonnull @d.str) - store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) %callRawBufferBinding, ptr @d.cb, align 4 + %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 @@ -150,7 +150,7 @@ if.else6.i: ; preds = %if.else.i _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, i1 false, ptr nonnull @.str) + %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 >From 93ff6d262453f01a51ec42d12c3f3f4c2f885ba8 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 14:30:40 -0400 Subject: [PATCH 10/14] fix for hoisting non void returns --- llvm/include/llvm/IR/Type.h | 1 + .../lib/Target/DirectX/DXILResourceAccess.cpp | 35 ++++++++++++---- .../CodeGen/DirectX/phi-node-replacement.ll | 42 +++++++++++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 llvm/test/CodeGen/DirectX/phi-node-replacement.ll diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 0c8f960966cd5..17d5f5aaf1a1e 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -25,6 +25,7 @@ #include <iterator> namespace llvm { + class IntegerType; struct fltSemantics; class LLVMContext; diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index c569ab8adfcf0..7e27850e00f91 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -8,6 +8,7 @@ #include "DXILResourceAccess.h" #include "DirectX.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Analysis/DXILResource.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Dominators.h" @@ -270,8 +271,10 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, } } -static void phiNodeReplacement(IntrinsicInst *II) { - SmallVector<Instruction *> DeadInsts; +static void phiNodeReplacement(IntrinsicInst *II, + SmallVector<Instruction *> &PrevBBDeadInsts, + SetVector<BasicBlock *> &DeadBB) { + SmallVector<Instruction *> CurrBBDeadInsts; for (User *U : II->users()) { auto *Phi = dyn_cast<PHINode>(U); if (!Phi) @@ -280,23 +283,29 @@ static void phiNodeReplacement(IntrinsicInst *II) { IRBuilder<> Builder(Phi); SmallVector<Instruction *> UsesInBlock; collectBlockUseDef(Phi, UsesInBlock); + bool HasReturnUse = isa<ReturnInst>(UsesInBlock[UsesInBlock.size() - 1]); 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()); } - DeadInsts.push_back(Phi); + CurrBBDeadInsts.push_back(Phi); for (Instruction *I : UsesInBlock) { - DeadInsts.push_back(I); + 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(DeadInsts)) + for (Instruction *Dead : llvm::reverse(CurrBBDeadInsts)) Dead->eraseFromParent(); - DeadInsts.clear(); + CurrBBDeadInsts.clear(); } static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { @@ -342,11 +351,13 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) { static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) { SmallVector<std::pair<IntrinsicInst *, dxil::ResourceTypeInfo>> Resources; - for (BasicBlock &BB : F) { + SetVector<BasicBlock *> DeadBB; + SmallVector<Instruction *> PrevBBDeadInsts; + for (BasicBlock &BB : make_early_inc_range(F)) { for (Instruction &I : make_early_inc_range(BB)) if (auto *II = dyn_cast<IntrinsicInst>(&I)) if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) - phiNodeReplacement(II); + phiNodeReplacement(II, PrevBBDeadInsts, DeadBB); for (Instruction &I : BB) if (auto *II = dyn_cast<IntrinsicInst>(&I)) @@ -355,6 +366,12 @@ static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) { 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/phi-node-replacement.ll b/llvm/test/CodeGen/DirectX/phi-node-replacement.ll new file mode 100644 index 0000000000000..6aef126cb5ecd --- /dev/null +++ b/llvm/test/CodeGen/DirectX/phi-node-replacement.ll @@ -0,0 +1,42 @@ +; 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 +} >From 5121bc1084507af3c1f26d9436af32dff759283b Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 16:00:45 -0400 Subject: [PATCH 11/14] pr comments --- llvm/include/llvm/IR/DerivedTypes.h | 3 ++- llvm/include/llvm/IR/Type.h | 2 +- llvm/lib/Target/DirectX/DXILResourceAccess.cpp | 13 +++++++------ llvm/lib/Transforms/Utils/Local.cpp | 5 +---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h index 5db79b82ac61d..29b34cfe33964 100644 --- a/llvm/include/llvm/IR/DerivedTypes.h +++ b/llvm/include/llvm/IR/DerivedTypes.h @@ -847,7 +847,8 @@ class TargetExtType : public Type { CanBeLocal = 1U << 2, /// This type may be used as an element in a vector. CanBeVectorElement = 1U << 3, - /// All uses of this type must not attempt to introspect or obscure it. + // This type can only be used in intrinsic arguments and return values. + /// In particular, it cannot be used in select and phi instructions. IsTokenLike = 1U << 4, }; diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 17d5f5aaf1a1e..1c042500ba8ec 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -233,7 +233,7 @@ class Type { /// Return true if this is 'token'. bool isTokenTy() const { return getTypeID() == TokenTyID; } - /// Returns true if this is 'token' or 'token-like'. + /// Returns true if this is 'token' or a token-like target type.s bool isTokenLikeTy() const; /// True if this is an instance of IntegerType. diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp index 7e27850e00f91..6579d3405cf39 100644 --- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp +++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp @@ -203,10 +203,10 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset, llvm_unreachable("Unhandled case in switch"); } -static void collectBlockUseDef(Instruction *Start, - SmallVectorImpl<Instruction *> &Out) { +static SmallVector<Instruction *> collectBlockUseDef(Instruction *Start) { SmallPtrSet<Instruction *, 32> Visited; SmallVector<Instruction *, 32> Worklist; + SmallVector<Instruction *> Out; auto *BB = Start->getParent(); // Seed with direct users in this block. @@ -247,6 +247,8 @@ static void collectBlockUseDef(Instruction *Start, llvm::sort(Out, [&](Instruction *A, Instruction *B) { return Ord.lookup(A) < Ord.lookup(B); }); + + return Out; } static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, @@ -272,7 +274,7 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, } static void phiNodeReplacement(IntrinsicInst *II, - SmallVector<Instruction *> &PrevBBDeadInsts, + SmallVectorImpl<Instruction *> &PrevBBDeadInsts, SetVector<BasicBlock *> &DeadBB) { SmallVector<Instruction *> CurrBBDeadInsts; for (User *U : II->users()) { @@ -281,9 +283,8 @@ static void phiNodeReplacement(IntrinsicInst *II, continue; IRBuilder<> Builder(Phi); - SmallVector<Instruction *> UsesInBlock; - collectBlockUseDef(Phi, UsesInBlock); - bool HasReturnUse = isa<ReturnInst>(UsesInBlock[UsesInBlock.size() - 1]); + SmallVector<Instruction *> UsesInBlock = collectBlockUseDef(Phi); + bool HasReturnUse = isa<ReturnInst>(UsesInBlock.back()); for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) { auto *CurrIncomingBB = Phi->getIncomingBlock(I); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 0eb92470045ea..b94ed7db91580 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3839,7 +3839,7 @@ void llvm::maybeMarkSanitizerLibraryCallNoBuiltin( bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { const auto *Op = I->getOperand(OpIdx); // We can't have a PHI with a metadata or token type. - if (Op->getType()->isMetadataTy() || Op->getType()->isTokenTy()) + if (Op->getType()->isMetadataTy() || Op->getType()->isTokenLikeTy()) return false; // swifterror pointers can only be used by a load, store, or as a swifterror @@ -3852,9 +3852,6 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { if (I->isLifetimeStartOrEnd()) return false; - if (Op->getType()->isTokenLikeTy()) - return false; - // Early exit. if (!isa<Constant, InlineAsm>(Op)) return true; >From e4215bb8feaaa6a73cf2db61e922afa772f6dff9 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 17:17:17 -0400 Subject: [PATCH 12/14] add verifer and simplifyCFG tests --- llvm/lib/IR/Verifier.cpp | 10 ++-- .../Transforms/SimplifyCFG/token_like_type.ll | 46 +++++++++++++++++++ llvm/test/Verifier/tokenlike1-with-asserts.ll | 12 +++++ .../Verifier/tokenlike1-without-asserts.ll | 12 +++++ llvm/test/Verifier/tokenlike5.ll | 7 +++ llvm/test/Verifier/tokenlike6.ll | 7 +++ llvm/test/Verifier/tokenlike7.ll | 8 ++++ 7 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Transforms/SimplifyCFG/token_like_type.ll create mode 100644 llvm/test/Verifier/tokenlike1-with-asserts.ll create mode 100644 llvm/test/Verifier/tokenlike1-without-asserts.ll create mode 100644 llvm/test/Verifier/tokenlike5.ll create mode 100644 llvm/test/Verifier/tokenlike6.ll create mode 100644 llvm/test/Verifier/tokenlike7.ll diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 6e11d6a77cbf7..da05ff166122f 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3008,7 +3008,7 @@ void Verifier::visitFunction(const Function &F) { if (!IsIntrinsic) { Check(!Arg.getType()->isMetadataTy(), "Function takes metadata but isn't an intrinsic", &Arg, &F); - Check(!Arg.getType()->isTokenTy(), + Check(!Arg.getType()->isTokenLikeTy(), "Function takes token but isn't an intrinsic", &Arg, &F); Check(!Arg.getType()->isX86_AMXTy(), "Function takes x86_amx but isn't an intrinsic", &Arg, &F); @@ -3022,7 +3022,7 @@ void Verifier::visitFunction(const Function &F) { } if (!IsIntrinsic) { - Check(!F.getReturnType()->isTokenTy(), + Check(!F.getReturnType()->isTokenLikeTy(), "Function returns a token but isn't an intrinsic", &F); Check(!F.getReturnType()->isX86_AMXTy(), "Function returns a x86_amx but isn't an intrinsic", &F); @@ -3636,7 +3636,7 @@ void Verifier::visitPHINode(PHINode &PN) { "PHI nodes not grouped at top of basic block!", &PN, PN.getParent()); // Check that a PHI doesn't yield a Token. - Check(!PN.getType()->isTokenTy(), "PHI nodes cannot have token type!"); + Check(!PN.getType()->isTokenLikeTy(), "PHI nodes cannot have token type!"); // Check that all of the values of the PHI node have the same type as the // result. @@ -3841,14 +3841,14 @@ void Verifier::visitCallBase(CallBase &Call) { for (Type *ParamTy : FTy->params()) { Check(!ParamTy->isMetadataTy(), "Function has metadata parameter but isn't an intrinsic", Call); - Check(!ParamTy->isTokenTy(), + Check(!ParamTy->isTokenLikeTy(), "Function has token parameter but isn't an intrinsic", Call); } } // Verify that indirect calls don't return tokens. if (!Call.getCalledFunction()) { - Check(!FTy->getReturnType()->isTokenTy(), + Check(!FTy->getReturnType()->isTokenLikeTy(), "Return type cannot be token for indirect call!"); Check(!FTy->getReturnType()->isX86_AMXTy(), "Return type cannot be x86_amx for indirect call!"); diff --git a/llvm/test/Transforms/SimplifyCFG/token_like_type.ll b/llvm/test/Transforms/SimplifyCFG/token_like_type.ll new file mode 100644 index 0000000000000..21a14ccebed86 --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/token_like_type.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -S -passes=simplifycfg %s | FileCheck %s + +; NOTE: The Check lines should exactly match the IR. + +%"$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: [[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]]) +; 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: [[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]]) +; CHECK-NEXT: br label %[[_Z6CSMAINV_EXIT]] +; CHECK: [[_Z6CSMAINV_EXIT]]: +; CHECK-NEXT: [[DOTSINK1:%.*]] = phi ptr [ [[IFSTMTCALLRESOURCEGEP]], %[[IF_THEN_I]] ], [ [[ELSESTMTCALLRESOURCEGEP]], %[[IF_ELSE_I]] ] +; CHECK-NEXT: [[LOADSINK:%.*]] = load half, ptr [[DOTSINK1]], align 2 +; CHECK-NEXT: ret half [[LOADSINK]] +; + %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/Verifier/tokenlike1-with-asserts.ll b/llvm/test/Verifier/tokenlike1-with-asserts.ll new file mode 100644 index 0000000000000..19bdd805cfc91 --- /dev/null +++ b/llvm/test/Verifier/tokenlike1-with-asserts.ll @@ -0,0 +1,12 @@ +; REQUIRES: asserts +; RUN: not --crash llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", half, 1, 0) %B) { +entry: + br label %bb + +bb: + %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry] +; CHECK: PHI nodes cannot have token type! + br label %bb +} diff --git a/llvm/test/Verifier/tokenlike1-without-asserts.ll b/llvm/test/Verifier/tokenlike1-without-asserts.ll new file mode 100644 index 0000000000000..ef7ac00576251 --- /dev/null +++ b/llvm/test/Verifier/tokenlike1-without-asserts.ll @@ -0,0 +1,12 @@ +; REQUIRES: !asserts +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", half, 1, 0) %B) { +entry: + br label %bb + +bb: + %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry] +; CHECK: PHI nodes cannot have token type! + br label %bb +} diff --git a/llvm/test/Verifier/tokenlike5.ll b/llvm/test/Verifier/tokenlike5.ll new file mode 100644 index 0000000000000..ea36f37b547ca --- /dev/null +++ b/llvm/test/Verifier/tokenlike5.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void @f(target("dx.RawBuffer", half, 1, 0) %A) { +entry: + ret void +} +; CHECK: Function takes token but isn't an intrinsic diff --git a/llvm/test/Verifier/tokenlike6.ll b/llvm/test/Verifier/tokenlike6.ll new file mode 100644 index 0000000000000..3322b52b82c2c --- /dev/null +++ b/llvm/test/Verifier/tokenlike6.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define target("dx.RawBuffer", half, 1, 0) @f() { +entry: + ret target("dx.RawBuffer", half, 1, 0) undef +} +; CHECK: Function returns a token but isn't an intrinsic diff --git a/llvm/test/Verifier/tokenlike7.ll b/llvm/test/Verifier/tokenlike7.ll new file mode 100644 index 0000000000000..03cf68e44a206 --- /dev/null +++ b/llvm/test/Verifier/tokenlike7.ll @@ -0,0 +1,8 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void @f() { +entry: + call target("dx.RawBuffer", half, 1, 0) () undef () + ret void +} +; CHECK: Return type cannot be token for indirect call! >From b520011f6654b5297b99b9ce2f9c450c6da04816 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 28 Aug 2025 17:26:49 -0400 Subject: [PATCH 13/14] remove undef --- llvm/test/Verifier/tokenlike6.ll | 2 +- llvm/test/Verifier/tokenlike7.ll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/Verifier/tokenlike6.ll b/llvm/test/Verifier/tokenlike6.ll index 3322b52b82c2c..f24a9427eb8cb 100644 --- a/llvm/test/Verifier/tokenlike6.ll +++ b/llvm/test/Verifier/tokenlike6.ll @@ -2,6 +2,6 @@ define target("dx.RawBuffer", half, 1, 0) @f() { entry: - ret target("dx.RawBuffer", half, 1, 0) undef + ret target("dx.RawBuffer", half, 1, 0) poison } ; CHECK: Function returns a token but isn't an intrinsic diff --git a/llvm/test/Verifier/tokenlike7.ll b/llvm/test/Verifier/tokenlike7.ll index 03cf68e44a206..c7454937bb7ef 100644 --- a/llvm/test/Verifier/tokenlike7.ll +++ b/llvm/test/Verifier/tokenlike7.ll @@ -2,7 +2,7 @@ define void @f() { entry: - call target("dx.RawBuffer", half, 1, 0) () undef () + call target("dx.RawBuffer", half, 1, 0) () poison () ret void } ; CHECK: Return type cannot be token for indirect call! >From 1546848844c5e5bc4a2dc041a1a85c6001ec9a03 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Fri, 29 Aug 2025 09:34:00 -0400 Subject: [PATCH 14/14] fix test to comply with the new token like verifier changes --- .../CodeGenHLSL/builtins/hlsl_resource_t.hlsl | 21 ++++++++++++------- llvm/test/Verifier/tokenlike1-with-asserts.ll | 12 ----------- 2 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 llvm/test/Verifier/tokenlike1-with-asserts.ll diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl index 24114b11c7602..75d9fb8582b3d 100644 --- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl +++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl @@ -2,23 +2,28 @@ using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]]; +struct CustomResource { + handle_float_t h; +}; + +// CHECK: %struct.CustomResource = type { target("dx.TypedBuffer", float, 1, 0, 0) } // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0) // CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct, 0, 0) // CHECK: %struct.MyStruct = type <{ <4 x float>, <2 x i32> }> -// CHECK: define hidden void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) -// CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0) -// CHECK: declare hidden void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0)) +// CHECK: define hidden void @_Z2fa14CustomResource(ptr noundef byval(%struct.CustomResource) align 1 %a) +// CHECK: call void @_Z4foo114CustomResource(ptr noundef byval(%struct.CustomResource) align 1 %agg.tmp) +// CHECK: declare hidden void @_Z4foo114CustomResource(ptr noundef byval(%struct.CustomResource) align 1) -void foo1(handle_float_t res); +void foo1(CustomResource res); -void fa(handle_float_t a) { +void fa(CustomResource a) { foo1(a); } -// CHECK: define hidden void @_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) -void fb(handle_float_t a) { - handle_float_t b = a; +// CHECK: define hidden void @_Z2fb14CustomResource(ptr noundef byval(%struct.CustomResource) align 1 %a) +void fb(CustomResource a) { + CustomResource b = a; } // CHECK: define hidden void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %a) diff --git a/llvm/test/Verifier/tokenlike1-with-asserts.ll b/llvm/test/Verifier/tokenlike1-with-asserts.ll deleted file mode 100644 index 19bdd805cfc91..0000000000000 --- a/llvm/test/Verifier/tokenlike1-with-asserts.ll +++ /dev/null @@ -1,12 +0,0 @@ -; REQUIRES: asserts -; RUN: not --crash llvm-as %s -o /dev/null 2>&1 | FileCheck %s - -define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", half, 1, 0) %B) { -entry: - br label %bb - -bb: - %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry] -; CHECK: PHI nodes cannot have token type! - br label %bb -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits