[clang] [llvm] [DirectX] Remove trivially dead functions at linkage finalize (PR #106146)

Greg Roth via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 11 12:42:46 PDT 2024


https://github.com/pow2clk updated https://github.com/llvm/llvm-project/pull/106146

>From 40224473a7b43bc4ffe2024ab51196c2130bedc7 Mon Sep 17 00:00:00 2001
From: Greg Roth <grroth at microsoft.com>
Date: Sun, 25 Aug 2024 12:00:03 -0600
Subject: [PATCH 1/5] [DirectX] Remove trivially dead functions at linkage
 finalize

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 #106139
---
 .../CodeGenHLSL/remove-internal-unused.hlsl   | 47 +++++++++++
 .../Target/DirectX/DXILFinalizeLinkage.cpp    | 16 ++--
 .../DirectX/finalize-linkage-remove-dead.ll   | 80 +++++++++++++++++++
 3 files changed, 135 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/remove-internal-unused.hlsl
 create mode 100644 llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll

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 }

>From 2335e8c5fb13001f6db86074e9bd3327dfbccb12 Mon Sep 17 00:00:00 2001
From: Greg Roth <grroth at microsoft.com>
Date: Thu, 19 Sep 2024 21:01:31 -0600
Subject: [PATCH 2/5] correct run lines

---
 clang/test/CodeGenHLSL/remove-internal-unused.hlsl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
index 85c114618a1e0e..e13b57158ba034 100644
--- a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
+++ b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
@@ -1,5 +1,5 @@
-// 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
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -S -o - %s | FileCheck %s
 
 // Verify that internal linkage unused functions are removed
 

>From 8320509a5dcb4bd25601f21cb2549c9212ebdc4c Mon Sep 17 00:00:00 2001
From: Greg Roth <grroth at microsoft.com>
Date: Fri, 20 Sep 2024 12:57:11 -0600
Subject: [PATCH 3/5] Remove test requiring DirectX backend

---
 .../CodeGenHLSL/remove-internal-unused.hlsl   | 47 -------------------
 1 file changed, 47 deletions(-)
 delete mode 100644 clang/test/CodeGenHLSL/remove-internal-unused.hlsl

diff --git a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl b/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
deleted file mode 100644
index e13b57158ba034..00000000000000
--- a/clang/test/CodeGenHLSL/remove-internal-unused.hlsl
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple 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

>From 416b5c0a16a059e6e2808658dc6805a086320d38 Mon Sep 17 00:00:00 2001
From: Greg Roth <grroth at microsoft.com>
Date: Sat, 21 Sep 2024 02:34:40 -0600
Subject: [PATCH 4/5] Eliminate trivially dead functions regardless of inline
 status

The consensus of the reviewers agreed with this approach

Adds better testing too
---
 .../Target/DirectX/DXILFinalizeLinkage.cpp    |   4 +-
 .../DirectX/ShaderFlags/double-extensions.ll  |   3 +-
 .../CodeGen/DirectX/ShaderFlags/doubles.ll    |   4 +-
 .../DirectX/conflicting-bitcast-insert.ll     |  10 +-
 .../DirectX/finalize-linkage-remove-dead.ll   | 212 +++++++++++++++---
 llvm/test/CodeGen/DirectX/finalize_linkage.ll |   2 +-
 llvm/test/CodeGen/DirectX/fneg-conversion.ll  |   6 +-
 .../CodeGen/DirectX/omit-bitcast-insert.ll    |  14 +-
 llvm/test/CodeGen/DirectX/scalar-store.ll     |   4 +-
 .../CodeGen/DirectX/scalarize-two-calls.ll    |   4 +-
 llvm/test/CodeGen/DirectX/strip-fn-attrs.ll   |   2 +-
 11 files changed, 210 insertions(+), 55 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
index 59b30f965bf951..49fd70d1a1a76d 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
@@ -21,7 +21,7 @@ using namespace llvm;
 static bool finalizeLinkage(Module &M) {
   SmallPtrSet<Function *, 8> Funcs;
 
-  // Find all entry points and export functions
+  // Collect non-entry and non-exported functions to set to internal linkage.
   for (Function &EF : M.functions()) {
     if (EF.hasFnAttribute("hlsl.shader") || EF.hasFnAttribute("hlsl.export"))
       continue;
@@ -31,7 +31,7 @@ static bool finalizeLinkage(Module &M) {
   for (Function *F : Funcs) {
     if (F->getLinkage() == GlobalValue::ExternalLinkage)
       F->setLinkage(GlobalValue::InternalLinkage);
-    if (F->hasFnAttribute(Attribute::AlwaysInline) && F->isDefTriviallyDead())
+    if (F->isDefTriviallyDead())
       M.getFunctionList().erase(F);
   }
 
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll
index d027216e4213d5..a8d5f9c78f0b43 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll
@@ -9,11 +9,12 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ; CHECK-NEXT: ;       Double-precision extensions for 11.1
 ; CHECK-NEXT: ; Note: extra DXIL module flags:
 ; CHECK-NEXT: {{^;$}}
-define double @div(double %a, double %b) {
+define double @div(double %a, double %b) #0 {
   %res = fdiv double %a, %b
   ret double %res
 }
 
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
 
 ; DXC: - Name:            SFI0
 ; DXC-NEXT:     Size:            8
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll
index c1a4c219a16951..e9b44240e10b9b 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll
@@ -9,11 +9,13 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ; CHECK-NEXT: ; Note: extra DXIL module flags:
 ; CHECK-NEXT: {{^;$}}
 
-define double @add(double %a, double %b) {
+define double @add(double %a, double %b) #0 {
   %sum = fadd double %a, %b
   ret double %sum
 }
 
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
+
 ; DXC: - Name:            SFI0
 ; DXC-NEXT:     Size:            8
 ; DXC-NEXT:     Flags:
diff --git a/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll b/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll
index 8f5d3ae8641717..39e21daceea81a 100644
--- a/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll
+++ b/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll
@@ -1,25 +1,27 @@
 ; RUN: llc --filetype=asm %s -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
-define i64 @test(ptr %p) {
+define i64 @test(ptr %p) #0 {
   store i32 0, ptr %p
   %v = load i64, ptr %p
   ret i64 %v
 }
 
-; CHECK: define internal i64 @test(ptr %p) {
+; CHECK: define i64 @test(ptr %p) #0 {
 ; CHECK-NEXT: %1 = bitcast ptr %p to ptr
 ; CHECK-NEXT: store i32 0, ptr %1, align 4
 ; CHECK-NEXT: %2 = bitcast ptr %p to ptr
 ; CHECK-NEXT: %3 = load i64, ptr %2, align 8
 
-define i64 @testGEP(ptr %p) {
+define i64 @testGEP(ptr %p) #0 {
   %ptr = getelementptr i32, ptr %p, i32 4
   %val = load i64, ptr %p
   ret i64 %val
 }
 
-; CHECK: define internal i64 @testGEP(ptr %p) {
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
+
+; CHECK: define i64 @testGEP(ptr %p) #0 {
 ; CHECK-NEXT:   %1 = bitcast ptr %p to ptr
 ; CHECK-NEXT:   %ptr = getelementptr i32, ptr %1, i32 4
 ; CHECK-NEXT:   %2 = bitcast ptr %p to ptr
diff --git a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
index df5934355664d1..15e82672495d89 100644
--- a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
+++ b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
@@ -5,76 +5,218 @@ 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.
+; is not explicitly marked 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 {
+; Has no specified inlining/linking behavior and is uncalled, this should be removed.
+; CHECK-NOT: define {{.*}}doNothingUncalled
+define void @"?doNothingUncalled@@YAXXZ"() #2 {
 entry:
   ret void
 }
 
-; Marked internal, this should be removed.
-; CHECK-NOT: define {{.*}}doNothingInternally
-define internal void @"?doNothingInternally@@YAXXZ"() #0 {
+; Alwaysinline and uncalled, this should be removed.
+; CHECK-NOT: define {{.*}}doAlwaysInlineUncalled
+define void @"?doAlwaysInlineUncalled@@YAXXZ"() #0 {
 entry:
   ret void
 }
 
-; Marked external, which should become internal and be removed.
-; CHECK-NOT: define {{.*}}doNothingExternally
-define external void @"?doNothingExternally@@YAXXZ"() #0 {
+; Noinline and uncalled, this should be removed.
+; CHECK-NOT: define {{.*}}doNoinlineUncalled
+define void @"?doNoinlineUncalled@@YAXXZ"() #4 {
 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 {
+; No inlining attribute, internal, and uncalled; this should be removed.
+; CHECK-NOT: define {{.*}}doInternalUncalled
+define internal void @"?doInternalUncalled@@YAXXZ"() #2 {
 entry:
   ret void
 }
 
-; Marked internal, this should be removed.
-; CHECK: define internal void @"?doSomethingInternally@@YAXXZ"() #0
-define internal void @"?doSomethingInternally@@YAXXZ"() #0 {
+; Alwaysinline, internal, and uncalled; this should be removed.
+; CHECK-NOT: define {{.*}}doAlwaysInlineInternalUncalled
+define internal void @"?doAlwaysInlineInternalUncalled@@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 {
+; Noinline, internal, and uncalled; this should be removed.
+; CHECK-NOT: define {{.*}}doNoinlineInternalUncalled
+define internal void @"?doNoinlineInternalUncalled@@YAXXZ"() #4 {
 entry:
   ret void
 }
 
-; Lacks alwaysinline attribute. Should remain.
-; CHECK: define internal void @"?doNothingDefault@@YAXXZ"() #1
-define void @"?doNothingDefault@@YAXXZ"() #1 {
+; Marked external and uncalled, this should become internal and be removed.
+; CHECK-NOT: define {{.*}}doExternalUncalled
+define external void @"?doExternalUncalled@@YAXXZ"() #2 {
 entry:
   ret void
 }
 
-; Has noinline attribute. Should remain.
-; CHECK: define {{.*}}doNothingNoinline
-define void @"?doNothingNoinline@@YAXXZ"() #2 {
+; Alwaysinline, external and uncalled, this should become internal and be removed.
+; CHECK-NOT: define {{.*}}doAlwaysInlineExternalUncalled
+define external void @"?doAlwaysInlineExternalUncalled@@YAXXZ"() #0 {
 entry:
   ret void
 }
 
-; Entry point function should stay.
-; CHECK: define void @main() #3
-define void @main() #3 {
+; Noinline, external and uncalled, this should become internal and be removed.
+; CHECK-NOT: define {{.*}}doNoinlineExternalUncalled
+define external void @"?doNoinlineExternalUncalled@@YAXXZ"() #4 {
 entry:
-  call void @"?doSomethingSomething@@YAXXZ"() #4
-  call void @"?doSomethingInternally@@YAXXZ"() #4
-  call void @"?doSomethingExternally@@YAXXZ"() #4
+  ret void
+}
+
+; No inlining attribute and called, this should stay.
+; CHECK: define {{.*}}doNothingCalled
+define void @"?doNothingCalled@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Alwaysinline and called, this should stay.
+; CHECK: define {{.*}}doAlwaysInlineCalled
+define void @"?doAlwaysInlineCalled@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Noinline and called, this should stay.
+; CHECK: define {{.*}}doNoinlineCalled
+define void @"?doNoinlineCalled@@YAXXZ"() #4 {
+entry:
+  ret void
+}
+
+; No inlining attribute, internal, and called; this should stay.
+; CHECK: define {{.*}}doInternalCalled
+define internal void @"?doInternalCalled@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Alwaysinline, internal, and called; this should stay.
+; CHECK: define {{.*}}doAlwaysInlineInternalCalled
+define internal void @"?doAlwaysInlineInternalCalled@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Noinline, internal, and called; this should stay.
+; CHECK: define {{.*}}doNoinlineInternalCalled
+define internal void @"?doNoinlineInternalCalled@@YAXXZ"() #4 {
+entry:
+  ret void
+}
+
+; Marked external and called, this should become internal and stay.
+; CHECK: define {{.*}}doExternalCalled
+define external void @"?doExternalCalled@@YAXXZ"() #2 {
+entry:
+  ret void
+}
+
+; Always inlined, external and called, this should become internal and stay.
+; CHECK: define {{.*}}doAlwaysInlineExternalCalled
+define external void @"?doAlwaysInlineExternalCalled@@YAXXZ"() #0 {
+entry:
+  ret void
+}
+
+; Noinline, external and called, this should become internal and stay.
+; CHECK: define {{.*}}doNoinlineExternalCalled
+define external void @"?doNoinlineExternalCalled@@YAXXZ"() #4 {
+entry:
+  ret void
+}
+
+; No inlining attribute and exported, this should stay.
+; CHECK: define {{.*}}doNothingExported
+define void @"?doNothingExported@@YAXXZ"() #3 {
+entry:
+  ret void
+}
+
+; Alwaysinline and exported, this should stay.
+; CHECK: define {{.*}}doAlwaysInlineExported
+define void @"?doAlwaysInlineExported@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Noinline attribute and exported, this should stay.
+; CHECK: define {{.*}}doNoinlineExported
+define void @"?doNoinlineExported@@YAXXZ"() #5 {
+entry:
+  ret void
+}
+
+; No inlining attribute, internal, and exported; this should stay.
+; CHECK: define {{.*}}doInternalExported
+define internal void @"?doInternalExported@@YAXXZ"() #3 {
+entry:
+  ret void
+}
+
+; Alwaysinline, internal, and exported; this should stay.
+; CHECK: define {{.*}}doAlwaysInlineInternalExported
+define internal void @"?doAlwaysInlineInternalExported@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Noinline, internal, and exported; this should stay.
+; CHECK: define {{.*}}doNoinlineInternalExported
+define internal void @"?doNoinlineInternalExported@@YAXXZ"() #5 {
+entry:
+  ret void
+}
+
+; Marked external and exported, this should stay.
+; CHECK: define {{.*}}doExternalExported
+define external void @"?doExternalExported@@YAXXZ"() #3 {
+entry:
+  ret void
+}
+
+; Alwaysinline, external and exported, this should stay.
+; CHECK: define {{.*}}doAlwaysInlineExternalExported
+define external void @"?doAlwaysInlineExternalExported@@YAXXZ"() #1 {
+entry:
+  ret void
+}
+
+; Noinline, external and exported, this should stay.
+; CHECK: define {{.*}}doNoinlineExternalExported
+define external void @"?doNoinlineExternalExported@@YAXXZ"() #5 {
+entry:
+  ret void
+}
+
+; Entry point function, this should stay.
+; CHECK: define void @main()
+define void @main() #6 {
+entry:
+  call void @"?doNothingCalled@@YAXXZ"() #7
+  call void @"?doAlwaysInlineCalled@@YAXXZ"() #7
+  call void @"?doNoinlineCalled@@YAXXZ"() #7
+  call void @"?doInternalCalled@@YAXXZ"() #7
+  call void @"?doAlwaysInlineInternalCalled@@YAXXZ"() #7
+  call void @"?doNoinlineInternalCalled@@YAXXZ"() #7
+  call void @"?doExternalCalled@@YAXXZ"() #7
+  call void @"?doAlwaysInlineExternalCalled@@YAXXZ"() #7
+  call void @"?doNoinlineExternalCalled@@YAXXZ"() #7
   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 }
+attributes #1 = { alwaysinline convergent norecurse nounwind "hlsl.export"}
+attributes #2 = { convergent norecurse nounwind }
+attributes #3 = { convergent norecurse nounwind "hlsl.export"}
+attributes #4 = { convergent noinline norecurse nounwind }
+attributes #5 = { convergent noinline norecurse nounwind "hlsl.export"}
+attributes #6 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #7 = { convergent }
diff --git a/llvm/test/CodeGen/DirectX/finalize_linkage.ll b/llvm/test/CodeGen/DirectX/finalize_linkage.ll
index 0ee8a5f44593ba..efee53b907aa69 100644
--- a/llvm/test/CodeGen/DirectX/finalize_linkage.ll
+++ b/llvm/test/CodeGen/DirectX/finalize_linkage.ll
@@ -6,7 +6,7 @@ target triple = "dxilv1.5-pc-shadermodel6.5-compute"
 ; DXILFinalizeLinkage changes linkage of all functions that are not
 ; entry points or exported function to internal.
 
-; CHECK: define internal void @"?f1@@YAXXZ"()
+; CHECK-NOT: define internal void @"?f1@@YAXXZ"()
 define void @"?f1@@YAXXZ"() #0 {
 entry:
   ret void
diff --git a/llvm/test/CodeGen/DirectX/fneg-conversion.ll b/llvm/test/CodeGen/DirectX/fneg-conversion.ll
index a397c18398c5f7..3acf4790de4b10 100644
--- a/llvm/test/CodeGen/DirectX/fneg-conversion.ll
+++ b/llvm/test/CodeGen/DirectX/fneg-conversion.ll
@@ -1,14 +1,16 @@
 ; RUN: llc %s --filetype=asm -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
-define float @negateF(float %0) {
+define float @negateF(float %0) #0 {
 ; CHECK:  %2 = fsub float -0.000000e+00, %0
   %2 = fneg float %0
   ret float %2
 }
 
-define double @negateD(double %0) {
+define double @negateD(double %0) #0 {
 ; CHECK: %2 = fsub double -0.000000e+00, %0
   %2 = fneg double %0
   ret double %2
 }
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll b/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll
index 6066a0033e45de..734ff1b4dd2d57 100644
--- a/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll
+++ b/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll
@@ -1,32 +1,34 @@
 ; RUN: llc --filetype=asm %s -o - | FileCheck %s
 target triple = "dxil-unknown-shadermodel6.7-library"
 
-define i64 @test(ptr %p) {
+define i64 @test(ptr %p) #0 {
   %v = load i64, ptr %p
   ret i64 %v
 }
 
-; CHECK: define internal i64 @test(ptr %p) {
+; CHECK: define i64 @test(ptr %p) #0 {
 ; CHECK-NEXT: %v = load i64, ptr %p, align 8
 ; CHECK-NEXT: ret i64 %v
 
-define i64 @test2(ptr %p) {
+define i64 @test2(ptr %p) #0 {
   store i64 0, ptr %p
   %v = load i64, ptr %p
   ret i64 %v
 }
 
-; CHECK: define internal i64 @test2(ptr %p) {
+; CHECK: define i64 @test2(ptr %p) #0 {
 ; CHECK-NEXT: store i64 0, ptr %p
 ; CHECK-NEXT: %v = load i64, ptr %p, align 8
 ; CHECK-NEXT: ret i64 %v
 
-define i32 @test3(ptr %0)  {
+define i32 @test3(ptr %0) #0 {
   %2 = getelementptr i32, ptr %0, i32 4
   %3 = load i32, ptr %2
   ret i32 %3
 }
 
-; CHECK: define internal i32 @test3(ptr %0)  {
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
+
+; CHECK: define i32 @test3(ptr %0) #0 {
 ; CHECK-NEXT: %2 = getelementptr i32, ptr %0, i32 4
 ; CHECK-NEXT: %3 = load i32, ptr %2
diff --git a/llvm/test/CodeGen/DirectX/scalar-store.ll b/llvm/test/CodeGen/DirectX/scalar-store.ll
index b970a2842e5a8b..af5bba985ce24e 100644
--- a/llvm/test/CodeGen/DirectX/scalar-store.ll
+++ b/llvm/test/CodeGen/DirectX/scalar-store.ll
@@ -3,7 +3,7 @@
 
 @"sharedData" = local_unnamed_addr addrspace(3) global [2 x <3 x float>] zeroinitializer, align 16 
 ; CHECK-LABEL: store_test
-define void @store_test () local_unnamed_addr {
+define void @store_test () local_unnamed_addr #0 {
     ; CHECK: store float 1.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} 
     ; CHECK: store float 2.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}}
     ; CHECK: store float 3.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} 
@@ -15,3 +15,5 @@ define void @store_test () local_unnamed_addr {
     store <3 x float> <float 2.000000e+00, float 4.000000e+00, float 6.000000e+00>, ptr addrspace(3)   getelementptr inbounds (i8, ptr addrspace(3) @"sharedData", i32 16), align 16 
     ret void
  } 
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/scalarize-two-calls.ll b/llvm/test/CodeGen/DirectX/scalarize-two-calls.ll
index a14c1de5cc4205..0546a5505416f1 100644
--- a/llvm/test/CodeGen/DirectX/scalarize-two-calls.ll
+++ b/llvm/test/CodeGen/DirectX/scalarize-two-calls.ll
@@ -2,7 +2,7 @@
 
 ; CHECK: target triple = "dxilv1.3-pc-shadermodel6.3-library"
 ; CHECK-LABEL: cos_sin_float_test
-define noundef <4 x float> @cos_sin_float_test(<4 x float> noundef %a) {
+define noundef <4 x float> @cos_sin_float_test(<4 x float> noundef %a) #0 {
     ; CHECK: [[ee0:%.*]] = extractelement <4 x float> %a, i64 0
     ; CHECK: [[ie0:%.*]] = call float @dx.op.unary.f32(i32 13, float [[ee0]])
     ; CHECK: [[ee1:%.*]] = extractelement <4 x float> %a, i64 1
@@ -23,3 +23,5 @@ define noundef <4 x float> @cos_sin_float_test(<4 x float> noundef %a) {
     %3 = tail call <4 x float> @llvm.cos.v4f32(<4 x float> %2) 
     ret <4 x float> %3 
 } 
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll b/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll
index b0dd89cf90f2b2..4223c909431945 100644
--- a/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll
+++ b/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll
@@ -12,4 +12,4 @@ define dso_local float @fma(float %0, float %1, float %2) local_unnamed_addr #0
 ; CHECK: attributes #0 = { nounwind memory(none) }
 ; CHECK-NOT: attributes #
 
-attributes #0 = { norecurse nounwind readnone willreturn }
+attributes #0 = { norecurse nounwind readnone willreturn "hlsl.export"}

>From 21cfc89985540676de67669924887a9f492a7771 Mon Sep 17 00:00:00 2001
From: Greg Roth <grroth at microsoft.com>
Date: Fri, 11 Oct 2024 13:36:51 -0600
Subject: [PATCH 5/5] Add library DX codegen test

---
 llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
index 15e82672495d89..ecc3af2704f04e 100644
--- a/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
+++ b/llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead.ll
@@ -1,4 +1,5 @@
 ; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-compute %s | FileCheck %s
+; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-library %s | FileCheck %s
 ; RUN: llc %s --filetype=asm -o - | FileCheck %s
 
 target triple = "dxilv1.5-pc-shadermodel6.5-compute"



More information about the cfe-commits mailing list