[llvm] [DirectX] Make dx.RawBuffer an op that can't be replaced (PR #154620)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 28 14:17:39 PDT 2025
https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/154620
>From d298727d1e7a7d4dd6918638b8230ab9afcf25a1 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 20 Aug 2025 17:11:37 -0400
Subject: [PATCH 01/12] [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 }>
+
+ at .str = internal unnamed_addr constant [2 x i8] c"a\00", align 1
+ at d.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 12)) poison
+ at e = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+
+ at 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 0517bb98e6d1d702dfaec2adc7c0e7483e636f23 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 21 Aug 2025 11:00:13 -0400
Subject: [PATCH 02/12] 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 34cc46f532da3ad470366c5df515776ba1e2e382 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 21 Aug 2025 12:06:10 -0400
Subject: [PATCH 03/12] 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 daeff36511660cb4b77cd5c135994fcaf74fa256 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 26 Aug 2025 17:07:14 -0400
Subject: [PATCH 04/12] 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 40dbd439682ee368b88743dad5136e21889d57f6 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 27 Aug 2025 15:31:23 -0400
Subject: [PATCH 05/12] 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 11cf139d9e2cc8868b7acd9b31fde6b0410c1b4c Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 27 Aug 2025 15:55:00 -0400
Subject: [PATCH 06/12] 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 98ae80936409b4762d45cc01d911e6f98eb418b5 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 27 Aug 2025 16:28:21 -0400
Subject: [PATCH 07/12] 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 176a1293d30924cdbf410c89ea400c108eff5a1b Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 28 Aug 2025 12:23:02 -0400
Subject: [PATCH 08/12] 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 2ae995ccf80197c9236755c1df6dafd87e71b7c0 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 28 Aug 2025 13:14:28 -0400
Subject: [PATCH 09/12] 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 69cf03d2b731026a3e9672695f7c9d2678f918cc Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 28 Aug 2025 14:30:40 -0400
Subject: [PATCH 10/12] 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 }
+ at CBV = external constant %"$Globals"
+ at .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 2dc03eebf24cd555bed2551c2d854fe889203b3a Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 28 Aug 2025 16:00:45 -0400
Subject: [PATCH 11/12] 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 6468a2864d225adea64beafcf5f696937a58676c Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 28 Aug 2025 17:17:17 -0400
Subject: [PATCH 12/12] 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 9fda08645e118..dd6f7203ab0e6 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3006,7 +3006,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);
@@ -3020,7 +3020,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);
@@ -3634,7 +3634,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.
@@ -3839,14 +3839,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 }
+ at CBV = external constant %"$Globals"
+ at .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!
More information about the llvm-commits
mailing list