Skip to content

[DirectX] Remove trivially dead functions at linkage finalize #106146

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 11 commits into from
Oct 17, 2024

Conversation

pow2clk
Copy link
Contributor

@pow2clk pow2clk commented Aug 26, 2024

Functions are not removed even when made internal by DXILFinalizeLinkage. The removal code is called from alwaysinliner and globalopt, which are invoked too early to remove functions made internal by this pass.

This adds a check similar to that in alwaysinliner that removes trivially dead functions after being marked internal. It refactors that code a bit to make it simpler including reversing what is stored int he work queue.

Tests both the pass in isolation and the full i0nlining, linkage finalization and function removal steps.

Fixes #106139

@pow2clk pow2clk force-pushed the hlsl_remove_internal branch from 20bf1f8 to 6cf9e80 Compare August 26, 2024 21:38
@pow2clk
Copy link
Contributor Author

pow2clk commented Aug 26, 2024

I'd like to add a test that verifies this removal of used functions that get alwaysinlined, but that requires the inlining fix for #89282

Copy link

github-actions bot commented Aug 26, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@pow2clk pow2clk force-pushed the hlsl_remove_internal branch from 6cf9e80 to e0d9fa7 Compare August 26, 2024 21:55
@pow2clk pow2clk force-pushed the hlsl_remove_internal branch 2 times, most recently from 1e39029 to 70d4b5d Compare September 19, 2024 22:14
Functions are not removed even when made internal by DXILFinalizeLinkage
The removal code is called from alwaysinliner and globalopt, which are
invoked too early to remove functions made internal by this pass.

This adds a check similar to that in alwaysinliner that removes
trivially dead functions after being marked internal. It refactors
that code a bit to make it simpler including reversing what is
stored in the work queue.

Tests both the pass in isolation and the full inlining, linkage
finalization, and function removal process.

Fixes llvm#106139
@pow2clk pow2clk force-pushed the hlsl_remove_internal branch from 70d4b5d to 4022447 Compare September 19, 2024 23:25
@pow2clk pow2clk marked this pull request as ready for review September 19, 2024 23:26
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:DirectX HLSL HLSL Language Support labels Sep 19, 2024
@pow2clk pow2clk changed the title Tentative fix for not removing newly internal functions [DirectX] Remove trivially dead functions at linkage finalize Sep 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 19, 2024

@llvm/pr-subscribers-clang

Author: Greg Roth (pow2clk)

Changes

Functions are not removed even when made internal by DXILFinalizeLinkage The removal code is called from alwaysinliner and globalopt, which are invoked too early to remove functions made internal by this pass.

This adds a check similar to that in alwaysinliner that removes trivially dead functions after being marked internal. It refactors that code a bit to make it simpler including reversing what is stored in the work queue.

Not sure how to test this. To test all the interactions between alwaysinliner, DXILfinalizelinkage and any other optimization passes, it kinda needs to be end-to-end.

Fixes #106139


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

3 Files Affected:

  • (added) clang/test/CodeGenHLSL/remove-internal-unused.hlsl (+47)
  • (modified) llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp (+8-8)
  • (added) llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll (+80)
diff --git a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
new file mode 100644
index 00000000000000..85c114618a1e0e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
@@ -0,0 +1,47 @@
+// RUN: %clang -target dxil-pc-shadermodel6.0-compute -S -o - %s | FileCheck %s
+// RUN: %clang -target dxil-pc-shadermodel6.3-library -S -o - %s | FileCheck %s
+
+// Verify that internal linkage unused functions are removed
+
+RWBuffer<unsigned> buf;
+
+// Never called functions should be removed.
+// CHECK-NOT: define{{.*}}uncalledFor
+void uncalledFor() {
+     buf[1] = 1;
+}
+
+// Never called but exported functions should remain.
+// CHECK: define void @"?exported@@YAXXZ"()
+export void exported() {
+     buf[1] = 1;
+}
+
+// Never called but noinlined functions should remain.
+// CHECK: define internal void @"?noinlined@@YAXXZ"()
+__attribute__((noinline)) void noinlined() {
+     buf[1] = 1;
+}
+
+// Called functions marked noinline should remain.
+// CHECK: define internal void @"?calledAndNoinlined@@YAXXZ"()
+__attribute__((noinline)) void calledAndNoinlined() {
+     buf[1] = 1;
+}
+
+// Called functions that get inlined by default should be removed.
+// CHECK-NOT: define{{.*}}calledAndInlined
+void calledAndInlined() {
+     buf[1] = 1;
+}
+
+
+// Entry point functions should remain.
+// CHECK: define{{.*}}main
+[numthreads(1,1,1)]
+[shader("compute")]
+void main() {
+     calledAndInlined();
+     calledAndNoinlined();
+     buf[0] = 0;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
index d315d9bd16f439..59b30f965bf951 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
@@ -19,20 +19,20 @@
 using namespace llvm;
 
 static bool finalizeLinkage(Module &M) {
-  SmallPtrSet<Function *, 8> EntriesAndExports;
+  SmallPtrSet<Function *, 8> Funcs;
 
   // Find all entry points and export functions
   for (Function &EF : M.functions()) {
-    if (!EF.hasFnAttribute("hlsl.shader") && !EF.hasFnAttribute("hlsl.export"))
+    if (EF.hasFnAttribute("hlsl.shader") || EF.hasFnAttribute("hlsl.export"))
       continue;
-    EntriesAndExports.insert(&EF);
+    Funcs.insert(&EF);
   }
 
-  for (Function &F : M.functions()) {
-    if (F.getLinkage() == GlobalValue::ExternalLinkage &&
-        !EntriesAndExports.contains(&F)) {
-      F.setLinkage(GlobalValue::InternalLinkage);
-    }
+  for (Function *F : Funcs) {
+    if (F->getLinkage() == GlobalValue::ExternalLinkage)
+      F->setLinkage(GlobalValue::InternalLinkage);
+    if (F->hasFnAttribute(Attribute::AlwaysInline) && F->isDefTriviallyDead())
+      M.getFunctionList().erase(F);
   }
 
   return false;
diff --git a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
new file mode 100644
index 00000000000000..df5934355664d1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
@@ -0,0 +1,80 @@
+; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-compute %s | FileCheck %s
+; RUN: llc %s --filetype=asm -o - | FileCheck %s
+
+target triple = "dxilv1.5-pc-shadermodel6.5-compute"
+
+; Confirm that DXILFinalizeLinkage will remove functions that have compatible
+; linkage and are not called from anywhere. This should be any function that
+; is not explicitly marked noinline or export and is not an entry point.
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK-NOT: define {{.*}}doNothingNothing
+define void @"?doNothingNothing@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK-NOT: define {{.*}}doNothingInternally
+define internal void @"?doNothingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK-NOT: define {{.*}}doNothingExternally
+define external void @"?doNothingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK: define internal void @"?doSomethingSomething@@YAXXZ"() #0
+define void @"?doSomethingSomething@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK: define internal void @"?doSomethingInternally@@YAXXZ"() #0
+define internal void @"?doSomethingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK: define internal void @"?doSomethingExternally@@YAXXZ"() #0
+define external void @"?doSomethingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Lacks alwaysinline attribute. Should remain.
+; CHECK: define internal void @"?doNothingDefault@@YAXXZ"() #1
+define void @"?doNothingDefault@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Has noinline attribute. Should remain.
+; CHECK: define {{.*}}doNothingNoinline
+define void @"?doNothingNoinline@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Entry point function should stay.
+; CHECK: define void @main() #3
+define void @main() #3 {
+entry:
+  call void @"?doSomethingSomething@@YAXXZ"() #4
+  call void @"?doSomethingInternally@@YAXXZ"() #4
+  call void @"?doSomethingExternally@@YAXXZ"() #4
+  ret void
+}
+
+attributes #0 = { alwaysinline convergent norecurse nounwind }
+attributes #1 = { convergent norecurse nounwind }
+attributes #2 = { convergent noinline norecurse nounwind }
+attributes #3 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #4 = { convergent }

@llvmbot
Copy link
Member

llvmbot commented Sep 19, 2024

@llvm/pr-subscribers-backend-directx

Author: Greg Roth (pow2clk)

Changes

Functions are not removed even when made internal by DXILFinalizeLinkage The removal code is called from alwaysinliner and globalopt, which are invoked too early to remove functions made internal by this pass.

This adds a check similar to that in alwaysinliner that removes trivially dead functions after being marked internal. It refactors that code a bit to make it simpler including reversing what is stored in the work queue.

Not sure how to test this. To test all the interactions between alwaysinliner, DXILfinalizelinkage and any other optimization passes, it kinda needs to be end-to-end.

Fixes #106139


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

3 Files Affected:

  • (added) clang/test/CodeGenHLSL/remove-internal-unused.hlsl (+47)
  • (modified) llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp (+8-8)
  • (added) llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll (+80)
diff --git a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
new file mode 100644
index 00000000000000..85c114618a1e0e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
@@ -0,0 +1,47 @@
+// RUN: %clang -target dxil-pc-shadermodel6.0-compute -S -o - %s | FileCheck %s
+// RUN: %clang -target dxil-pc-shadermodel6.3-library -S -o - %s | FileCheck %s
+
+// Verify that internal linkage unused functions are removed
+
+RWBuffer<unsigned> buf;
+
+// Never called functions should be removed.
+// CHECK-NOT: define{{.*}}uncalledFor
+void uncalledFor() {
+     buf[1] = 1;
+}
+
+// Never called but exported functions should remain.
+// CHECK: define void @"?exported@@YAXXZ"()
+export void exported() {
+     buf[1] = 1;
+}
+
+// Never called but noinlined functions should remain.
+// CHECK: define internal void @"?noinlined@@YAXXZ"()
+__attribute__((noinline)) void noinlined() {
+     buf[1] = 1;
+}
+
+// Called functions marked noinline should remain.
+// CHECK: define internal void @"?calledAndNoinlined@@YAXXZ"()
+__attribute__((noinline)) void calledAndNoinlined() {
+     buf[1] = 1;
+}
+
+// Called functions that get inlined by default should be removed.
+// CHECK-NOT: define{{.*}}calledAndInlined
+void calledAndInlined() {
+     buf[1] = 1;
+}
+
+
+// Entry point functions should remain.
+// CHECK: define{{.*}}main
+[numthreads(1,1,1)]
+[shader("compute")]
+void main() {
+     calledAndInlined();
+     calledAndNoinlined();
+     buf[0] = 0;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
index d315d9bd16f439..59b30f965bf951 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
@@ -19,20 +19,20 @@
 using namespace llvm;
 
 static bool finalizeLinkage(Module &M) {
-  SmallPtrSet<Function *, 8> EntriesAndExports;
+  SmallPtrSet<Function *, 8> Funcs;
 
   // Find all entry points and export functions
   for (Function &EF : M.functions()) {
-    if (!EF.hasFnAttribute("hlsl.shader") && !EF.hasFnAttribute("hlsl.export"))
+    if (EF.hasFnAttribute("hlsl.shader") || EF.hasFnAttribute("hlsl.export"))
       continue;
-    EntriesAndExports.insert(&EF);
+    Funcs.insert(&EF);
   }
 
-  for (Function &F : M.functions()) {
-    if (F.getLinkage() == GlobalValue::ExternalLinkage &&
-        !EntriesAndExports.contains(&F)) {
-      F.setLinkage(GlobalValue::InternalLinkage);
-    }
+  for (Function *F : Funcs) {
+    if (F->getLinkage() == GlobalValue::ExternalLinkage)
+      F->setLinkage(GlobalValue::InternalLinkage);
+    if (F->hasFnAttribute(Attribute::AlwaysInline) && F->isDefTriviallyDead())
+      M.getFunctionList().erase(F);
   }
 
   return false;
diff --git a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
new file mode 100644
index 00000000000000..df5934355664d1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
@@ -0,0 +1,80 @@
+; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-compute %s | FileCheck %s
+; RUN: llc %s --filetype=asm -o - | FileCheck %s
+
+target triple = "dxilv1.5-pc-shadermodel6.5-compute"
+
+; Confirm that DXILFinalizeLinkage will remove functions that have compatible
+; linkage and are not called from anywhere. This should be any function that
+; is not explicitly marked noinline or export and is not an entry point.
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK-NOT: define {{.*}}doNothingNothing
+define void @"?doNothingNothing@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK-NOT: define {{.*}}doNothingInternally
+define internal void @"?doNothingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK-NOT: define {{.*}}doNothingExternally
+define external void @"?doNothingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK: define internal void @"?doSomethingSomething@@YAXXZ"() #0
+define void @"?doSomethingSomething@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK: define internal void @"?doSomethingInternally@@YAXXZ"() #0
+define internal void @"?doSomethingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK: define internal void @"?doSomethingExternally@@YAXXZ"() #0
+define external void @"?doSomethingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Lacks alwaysinline attribute. Should remain.
+; CHECK: define internal void @"?doNothingDefault@@YAXXZ"() #1
+define void @"?doNothingDefault@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Has noinline attribute. Should remain.
+; CHECK: define {{.*}}doNothingNoinline
+define void @"?doNothingNoinline@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Entry point function should stay.
+; CHECK: define void @main() #3
+define void @main() #3 {
+entry:
+  call void @"?doSomethingSomething@@YAXXZ"() #4
+  call void @"?doSomethingInternally@@YAXXZ"() #4
+  call void @"?doSomethingExternally@@YAXXZ"() #4
+  ret void
+}
+
+attributes #0 = { alwaysinline convergent norecurse nounwind }
+attributes #1 = { convergent norecurse nounwind }
+attributes #2 = { convergent noinline norecurse nounwind }
+attributes #3 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #4 = { convergent }

@llvmbot
Copy link
Member

llvmbot commented Sep 19, 2024

@llvm/pr-subscribers-hlsl

Author: Greg Roth (pow2clk)

Changes

Functions are not removed even when made internal by DXILFinalizeLinkage The removal code is called from alwaysinliner and globalopt, which are invoked too early to remove functions made internal by this pass.

This adds a check similar to that in alwaysinliner that removes trivially dead functions after being marked internal. It refactors that code a bit to make it simpler including reversing what is stored in the work queue.

Not sure how to test this. To test all the interactions between alwaysinliner, DXILfinalizelinkage and any other optimization passes, it kinda needs to be end-to-end.

Fixes #106139


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

3 Files Affected:

  • (added) clang/test/CodeGenHLSL/remove-internal-unused.hlsl (+47)
  • (modified) llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp (+8-8)
  • (added) llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll (+80)
diff --git a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
new file mode 100644
index 00000000000000..85c114618a1e0e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
@@ -0,0 +1,47 @@
+// RUN: %clang -target dxil-pc-shadermodel6.0-compute -S -o - %s | FileCheck %s
+// RUN: %clang -target dxil-pc-shadermodel6.3-library -S -o - %s | FileCheck %s
+
+// Verify that internal linkage unused functions are removed
+
+RWBuffer<unsigned> buf;
+
+// Never called functions should be removed.
+// CHECK-NOT: define{{.*}}uncalledFor
+void uncalledFor() {
+     buf[1] = 1;
+}
+
+// Never called but exported functions should remain.
+// CHECK: define void @"?exported@@YAXXZ"()
+export void exported() {
+     buf[1] = 1;
+}
+
+// Never called but noinlined functions should remain.
+// CHECK: define internal void @"?noinlined@@YAXXZ"()
+__attribute__((noinline)) void noinlined() {
+     buf[1] = 1;
+}
+
+// Called functions marked noinline should remain.
+// CHECK: define internal void @"?calledAndNoinlined@@YAXXZ"()
+__attribute__((noinline)) void calledAndNoinlined() {
+     buf[1] = 1;
+}
+
+// Called functions that get inlined by default should be removed.
+// CHECK-NOT: define{{.*}}calledAndInlined
+void calledAndInlined() {
+     buf[1] = 1;
+}
+
+
+// Entry point functions should remain.
+// CHECK: define{{.*}}main
+[numthreads(1,1,1)]
+[shader("compute")]
+void main() {
+     calledAndInlined();
+     calledAndNoinlined();
+     buf[0] = 0;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
index d315d9bd16f439..59b30f965bf951 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
@@ -19,20 +19,20 @@
 using namespace llvm;
 
 static bool finalizeLinkage(Module &M) {
-  SmallPtrSet<Function *, 8> EntriesAndExports;
+  SmallPtrSet<Function *, 8> Funcs;
 
   // Find all entry points and export functions
   for (Function &EF : M.functions()) {
-    if (!EF.hasFnAttribute("hlsl.shader") && !EF.hasFnAttribute("hlsl.export"))
+    if (EF.hasFnAttribute("hlsl.shader") || EF.hasFnAttribute("hlsl.export"))
       continue;
-    EntriesAndExports.insert(&EF);
+    Funcs.insert(&EF);
   }
 
-  for (Function &F : M.functions()) {
-    if (F.getLinkage() == GlobalValue::ExternalLinkage &&
-        !EntriesAndExports.contains(&F)) {
-      F.setLinkage(GlobalValue::InternalLinkage);
-    }
+  for (Function *F : Funcs) {
+    if (F->getLinkage() == GlobalValue::ExternalLinkage)
+      F->setLinkage(GlobalValue::InternalLinkage);
+    if (F->hasFnAttribute(Attribute::AlwaysInline) && F->isDefTriviallyDead())
+      M.getFunctionList().erase(F);
   }
 
   return false;
diff --git a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
new file mode 100644
index 00000000000000..df5934355664d1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
@@ -0,0 +1,80 @@
+; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-compute %s | FileCheck %s
+; RUN: llc %s --filetype=asm -o - | FileCheck %s
+
+target triple = "dxilv1.5-pc-shadermodel6.5-compute"
+
+; Confirm that DXILFinalizeLinkage will remove functions that have compatible
+; linkage and are not called from anywhere. This should be any function that
+; is not explicitly marked noinline or export and is not an entry point.
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK-NOT: define {{.*}}doNothingNothing
+define void @"?doNothingNothing@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK-NOT: define {{.*}}doNothingInternally
+define internal void @"?doNothingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK-NOT: define {{.*}}doNothingExternally
+define external void @"?doNothingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Not called nor marked with any linking or inlining attributes.
+; CHECK: define internal void @"?doSomethingSomething@@YAXXZ"() #0
+define void @"?doSomethingSomething@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked internal, this should be removed.
+; CHECK: define internal void @"?doSomethingInternally@@YAXXZ"() #0
+define internal void @"?doSomethingInternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Marked external, which should become internal and be removed.
+; CHECK: define internal void @"?doSomethingExternally@@YAXXZ"() #0
+define external void @"?doSomethingExternally@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Lacks alwaysinline attribute. Should remain.
+; CHECK: define internal void @"?doNothingDefault@@YAXXZ"() #1
+define void @"?doNothingDefault@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Has noinline attribute. Should remain.
+; CHECK: define {{.*}}doNothingNoinline
+define void @"?doNothingNoinline@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Entry point function should stay.
+; CHECK: define void @main() #3
+define void @main() #3 {
+entry:
+  call void @"?doSomethingSomething@@YAXXZ"() #4
+  call void @"?doSomethingInternally@@YAXXZ"() #4
+  call void @"?doSomethingExternally@@YAXXZ"() #4
+  ret void
+}
+
+attributes #0 = { alwaysinline convergent norecurse nounwind }
+attributes #1 = { convergent norecurse nounwind }
+attributes #2 = { convergent noinline norecurse nounwind }
+attributes #3 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #4 = { convergent }

calledAndInlined();
calledAndNoinlined();
buf[0] = 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

new line at EOF

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

@@ -19,20 +19,20 @@
using namespace llvm;

static bool finalizeLinkage(Module &M) {
SmallPtrSet<Function *, 8> EntriesAndExports;
SmallPtrSet<Function *, 8> Funcs;

// Find all entry points and export functions
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment may be better updated to something like:
Collect all non-entry point and non-exported functions to possibly set to internal linkage later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

; CHECK-COUNT-8: load i32, ptr addrspace(3) {{(.*@groushared2dArrayofVectors.scalarized.*|%.*)}}, align 4
; CHECK-NOT: load i32, ptr addrspace(3) {{.*}}, align 4
%1 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([3 x [3 x <4 x i32>]], [3 x [3 x <4 x i32>]] addrspace(3)* @"groushared2dArrayofVectors", i32 0, i32 0, i32 0), align 4
%2 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([3 x [3 x <4 x i32>]], [3 x [3 x <4 x i32>]] addrspace(3)* @"groushared2dArrayofVectors", i32 0, i32 1, i32 1), align 4
%3 = add <4 x i32> %1, %2
ret <4 x i32> %3
}

attributes #0 = { convergent norecurse nounwind "hlsl.export"}
Copy link
Member

Choose a reason for hiding this comment

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

Why are we add attributes we don't test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With this change, any functions lacking this attribute will be removed because they are not called. The attribute is aded so they don't get removed and cause this and other tests to fail.

Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

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

LGTM!

@pow2clk pow2clk merged commit ab75180 into llvm:main Oct 17, 2024
8 checks passed
@pow2clk pow2clk deleted the hlsl_remove_internal branch October 17, 2024 18:55
bogner added a commit that referenced this pull request Nov 4, 2024
In ab75180 "[DirectX] Remove trivially dead functions at linkage
finalize (#106146)" we updated the compiler to remove DXIL functions
that aren't marked with the "hlsl.export" attribute, but it seems we
forgot to add this attribute to the tests in `tools/dxil-dis`.
PhilippRados pushed a commit to PhilippRados/llvm-project that referenced this pull request Nov 6, 2024
In ab75180 "[DirectX] Remove trivially dead functions at linkage
finalize (llvm#106146)" we updated the compiler to remove DXIL functions
that aren't marked with the "hlsl.export" attribute, but it seems we
forgot to add this attribute to the tests in `tools/dxil-dis`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[DXIL] trivially dead functions marked internal by DXILFinalizeLinkage don't get removed
6 participants