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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
// 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"))
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->isDefTriviallyDead())
M.getFunctionList().erase(F);
}

return false;
Expand Down
3 changes: 2 additions & 1 deletion llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 6 additions & 4 deletions llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll
Original file line number Diff line number Diff line change
@@ -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
Expand Down
222 changes: 222 additions & 0 deletions llvm/test/CodeGen/DirectX/finalize-linkage-remove-dead-lib.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
; 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"

; 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 export and is not an entry point.

; 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
}

; Alwaysinline and uncalled, this should be removed.
; CHECK-NOT: define {{.*}}doAlwaysInlineUncalled
define void @"?doAlwaysInlineUncalled@@YAXXZ"() #0 {
entry:
ret void
}

; Noinline and uncalled, this should be removed.
; CHECK-NOT: define {{.*}}doNoinlineUncalled
define void @"?doNoinlineUncalled@@YAXXZ"() #4 {
entry:
ret void
}

; No inlining attribute, internal, and uncalled; this should be removed.
; CHECK-NOT: define {{.*}}doInternalUncalled
define internal void @"?doInternalUncalled@@YAXXZ"() #2 {
entry:
ret void
}

; Alwaysinline, internal, and uncalled; this should be removed.
; CHECK-NOT: define {{.*}}doAlwaysInlineInternalUncalled
define internal void @"?doAlwaysInlineInternalUncalled@@YAXXZ"() #0 {
entry:
ret void
}

; Noinline, internal, and uncalled; this should be removed.
; CHECK-NOT: define {{.*}}doNoinlineInternalUncalled
define internal void @"?doNoinlineInternalUncalled@@YAXXZ"() #4 {
entry:
ret void
}

; Marked external and uncalled, this should become internal and be removed.
; CHECK-NOT: define {{.*}}doExternalUncalled
define external void @"?doExternalUncalled@@YAXXZ"() #2 {
entry:
ret void
}

; Alwaysinline, external and uncalled, this should become internal and be removed.
; CHECK-NOT: define {{.*}}doAlwaysInlineExternalUncalled
define external void @"?doAlwaysInlineExternalUncalled@@YAXXZ"() #0 {
entry:
ret void
}

; Noinline, external and uncalled, this should become internal and be removed.
; CHECK-NOT: define {{.*}}doNoinlineExternalUncalled
define external void @"?doNoinlineExternalUncalled@@YAXXZ"() #4 {
entry:
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 = { 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 }
Loading