Skip to content

Adjust bit cast instruction filter for DXIL Prepare pass #142678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 5, 2025

Conversation

bob80905
Copy link
Contributor

@bob80905 bob80905 commented Jun 3, 2025

This PR addresses a specific edge case when deciding whether or not to produce a bitcast instruction.
Specifically, when the given instruction is a global array, the element type of the array wasn't correctly compared to the return type. In this specific case, if the types are equal, a bitcast shouldn't be created, but it was.
This PR checks to see if the element type of the array is the same as the return type, and if it is, it doesn't create a bitcast instruction.

Fixes #139013

@llvmbot
Copy link
Member

llvmbot commented Jun 3, 2025

@llvm/pr-subscribers-backend-directx

Author: Joshua Batista (bob80905)

Changes

This PR addresses a specific edge case when deciding whether or not to produce a bitcast instruction.
Specifically, when the given instruction is a global array, the element type of the array wasn't correctly compared to the return type. In this specific case, if the types are equal, a bitcast shouldn't be created, but it was.
This PR checks to see if the element type of the array is the same as the return type, and if it is, it doesn't create a bitcast instruction.

Fixes #139013


Full diff: https://github.com/llvm/llvm-project/pull/142678.diff

2 Files Affected:

  • (modified) llvm/lib/Target/DirectX/DXILPrepare.cpp (+35-2)
  • (added) llvm/test/CodeGen/DirectX/noop_bitcast_global_array_type.ll (+39)
diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp
index e0068787f5e5a..54e4499830ff0 100644
--- a/llvm/lib/Target/DirectX/DXILPrepare.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp
@@ -148,9 +148,42 @@ class DXILPrepareModule : public ModulePass {
                                      Type *Ty) {
     // Omit bitcasts if the incoming value matches the instruction type.
     auto It = PointerTypes.find(Operand);
-    if (It != PointerTypes.end())
-      if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
+    if (It != PointerTypes.end()) {
+      auto OpTy = cast<TypedPointerType>(It->second)->getElementType();
+      if (OpTy == Ty)
         return nullptr;
+    }
+
+    // Also omit the bitcast for matching global array types
+    if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
+      llvm::Type *ValTy = GlobalVar->getValueType();
+
+      if (auto *ArrTy = llvm::dyn_cast<llvm::ArrayType>(ValTy)) {
+        llvm::Type *ElTy = ArrTy->getElementType();
+        if (ElTy == Ty)
+          return nullptr;
+      }
+    }
+
+    // finally, drill down GEP instructions until we get the array
+    // that is being accessed, and compare element types
+    if (auto *GEPInstr = llvm::dyn_cast<llvm::ConstantExpr>(Operand)) {
+      while (GEPInstr->getOpcode() == llvm::Instruction::GetElementPtr) {
+        llvm::Value *OpArg = GEPInstr->getOperand(0);
+
+        if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(OpArg)) {
+          llvm::Constant *initializer = GlobalVar->getInitializer();
+
+          llvm::Type *ValTy = GlobalVar->getValueType();
+          if (auto *ArrTy = llvm::dyn_cast<llvm::ArrayType>(ValTy)) {
+            llvm::Type *ElTy = ArrTy->getElementType();
+            if (ElTy == Ty)
+              return nullptr;
+          }
+        }
+      }
+    }
+
     // Insert bitcasts where we are removing the instruction.
     Builder.SetInsertPoint(&Inst);
     // This code only gets hit in opaque-pointer mode, so the type of the
diff --git a/llvm/test/CodeGen/DirectX/noop_bitcast_global_array_type.ll b/llvm/test/CodeGen/DirectX/noop_bitcast_global_array_type.ll
new file mode 100644
index 0000000000000..4cca76efcf461
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/noop_bitcast_global_array_type.ll
@@ -0,0 +1,39 @@
+; RUN: opt -S --dxil-prepare %s | FileCheck %s
+
+; Test that global arrays do not get a bitcast instruction
+; after the dxil-prepare pass.
+
+target triple = "dxilv1.2-unknown-shadermodel6.2-compute"
+
+@inputTile.1dim = local_unnamed_addr addrspace(3) global [3 x float] zeroinitializer, align 2
+
+define float @testload() local_unnamed_addr {
+  ; NOTE: this would be "bitcast ptr addrspace(3)..." before the change that introduced this test,
+  ; after the dxil-prepare pass is run
+  ; CHECK: load float, ptr addrspace(3) @inputTile.1dim, align 2
+  %v = load float, ptr addrspace(3) @inputTile.1dim, align 2  
+  
+  ret float %v
+}
+
+define void @teststore() local_unnamed_addr {  
+  ; CHECK: store float 2.000000e+00, ptr addrspace(3) @inputTile.1dim, align 2
+  store float 2.000000e+00, ptr addrspace(3) @inputTile.1dim, align 2  
+  
+  ret void
+}
+
+define float @testGEPConst() local_unnamed_addr {  
+  ; CHECK: load float, ptr addrspace(3) getelementptr (float, ptr addrspace(3) @inputTile.1dim, i32 1), align 4
+  %v = load float, ptr addrspace(3) getelementptr (float, ptr addrspace(3) @inputTile.1dim, i32 1), align 4
+  
+  ret float %v
+}
+
+define float @testGEPNonConst(i32 %i) local_unnamed_addr {  
+  ; CHECK: getelementptr float, ptr addrspace(3) @inputTile.1dim, i32 %i
+  %gep = getelementptr float, ptr addrspace(3) @inputTile.1dim, i32 %i
+  %v = load float, ptr addrspace(3) %gep
+  
+  ret float %v
+}

define float @testload() local_unnamed_addr {
; NOTE: this would be "bitcast ptr addrspace(3)..." before the change that introduced this test,
; after the dxil-prepare pass is run
; CHECK: load float, ptr addrspace(3) @inputTile.1dim, align 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add check labels and since you are doing that mayve theese should all be CHECK-NEXT?

Icohedron
Icohedron previously approved these changes Jun 4, 2025
}

// Also omit the bitcast for matching global array types
if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
Copy link
Member

@farzonl farzonl Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure this is just globals? We can have alloca arrays
should we add if (auto *AI = dyn_cast<AllocaInst>(Operand))?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I think we should add a case for Alloca

}

// Also omit the bitcast for matching global array types
if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand)) {

if (auto *GlobalVar = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
llvm::Type *ValTy = GlobalVar->getValueType();

if (auto *ArrTy = llvm::dyn_cast<llvm::ArrayType>(ValTy)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (auto *ArrTy = llvm::dyn_cast<llvm::ArrayType>(ValTy)) {
if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {

Copy link
Member

@farzonl farzonl Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of commenting on everything single one of these just remove the llvm:: from all these Types and function calls. we have using namespace llvm; defined on line 34.

@bob80905 bob80905 force-pushed the remove_no_op_bitcast_DXIL branch from 2fbbbbe to 3d1ab27 Compare June 5, 2025 00:16
Copy link
Member

@farzonl farzonl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alloca case not handled the way I was expecting.

}

// Also omit the bitcast for alloca instructions
if (auto *AI = dyn_cast<AllocaInst>(Operand)) {
Copy link
Member

@farzonl farzonl Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no what I mean was you see how you are casting ValTy to ArrTy? So before that do

if (auto *AI = dyn_cast<AllocaInst>(Operand)) 
    ValTy = AI->getAllocatedType();

ie

Type *ValTy = Operand->getType();
 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))
      Type *ValTy = GlobalVar->getValueType();
 if (auto *AI = dyn_cast<AllocaInst>(Operand)) 
     ValTy = AI->getAllocatedType();
if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
        Type *ElTy = ArrTy->getElementType();
        if (ElTy == Ty)
          return nullptr;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is pseudo code so adjust it to something that works.

@Icohedron Icohedron dismissed their stale review June 5, 2025 00:24

Will re-review once the Alloca handling is complete

@farzonl farzonl self-requested a review June 5, 2025 02:04
@bob80905 bob80905 force-pushed the remove_no_op_bitcast_DXIL branch from be91577 to b143548 Compare June 5, 2025 19:14
@bob80905 bob80905 merged commit 1d6e8ec into llvm:main Jun 5, 2025
8 of 9 checks passed
farzonl added a commit to farzonl/llvm-project that referenced this pull request Jun 6, 2025
farzonl added a commit that referenced this pull request Jun 6, 2025
…bit cast instruction filter for DXIL Prepare pass (#142678)" (#143043)

- This reverts commit 9ab4c16.
- This reverts commit 1d6e8ec.

Noticed a really weird behavior where release and debug builds have
different codegen for loads with geps after this PR. This is going to
take a minute to debug and figure out why so revert seems to make the
most sense.

```diff
diff --git a/llvm/test/CodeGen/DirectX/flatten-array.ll b/llvm/test/CodeGen/DirectX/flatten-array.ll
index 47d7b50..efa9efeff13a 100644
--- a/llvm/test/CodeGen/DirectX/flatten-array.ll
+++ b/llvm/test/CodeGen/DirectX/flatten-array.ll
@@ -123,7 +123,8 @@ define void @gep_4d_test ()  {
@b = internal global [2 x [3 x [4 x i32]]] zeroinitializer, align 16
define void @global_gep_load() {
-  ; CHECK: load i32, ptr getelementptr inbounds ([24 x i32], ptr @a.1dim, i32 0, i32 6), align 4
+  ; CHECK: %1 = getelementptr inbounds [24 x i32], ptr @a.1dim, i32 0, i32 6
+  ; CHECK-NEXT: %2 = load i32, ptr %1, align 4
   ; CHECK-NEXT:    ret void
   %1 = getelementptr inbounds [2 x [3 x [4 x i32]]], [2 x [3 x [4 x i32]]]* @A, i32 0, i32 0
   %2 = getelementptr inbounds [3 x [4 x i32]], [3 x [4 x i32]]* %1, i32 0, i32 1
@@ -176,7 +177,8 @@ define void @global_incomplete_gep_chain(i32 %row, i32 %col) {
}
define void @global_gep_store() {
-  ; CHECK: store i32 1, ptr getelementptr inbounds ([24 x i32], ptr @b.1dim, i32 0, i32 13), align 4
+  ; CHECK: %1 = getelementptr inbounds [24 x i32], ptr @b.1dim, i32 0, i32 13
+  ; CHECK-NEXT: store i32 1, ptr %1, align 4
   ; CHECK-NEXT:    ret void
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DirectX] Pointer type bitcast must be have same size.
4 participants