Skip to content

Commit db279c7

Browse files
authored
[HLSL] Change default linkage of HLSL functions to internal (llvm#95331)
An HLSL function has internal linkage by default unless it is: 1. shader entry point function 2. marked with the `export` keyword (llvm#92812) 3. patch constant function (not implemented yet) This PR adds a link-time pass `DXILFinalizeLinkage` that updates the linkage of functions to make sure only shader entry points and exported functions are visible from the module (have _program linkage_). All other functions will be updated to have internal linkage. Related spec update: microsoft/hlsl-specs#295 Fixes #llvm#92071
1 parent fbef911 commit db279c7

File tree

8 files changed

+178
-5
lines changed

8 files changed

+178
-5
lines changed

llvm/lib/Target/DirectX/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_llvm_target(DirectXCodeGen
1919
DirectXSubtarget.cpp
2020
DirectXTargetMachine.cpp
2121
DXContainerGlobals.cpp
22+
DXILFinalizeLinkage.cpp
2223
DXILIntrinsicExpansion.cpp
2324
DXILMetadata.cpp
2425
DXILOpBuilder.cpp
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===- DXILFinalizeLinkage.cpp - Finalize linkage of functions ------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DXILFinalizeLinkage.h"
10+
#include "DirectX.h"
11+
#include "llvm/IR/Function.h"
12+
#include "llvm/IR/GlobalValue.h"
13+
#include "llvm/IR/Metadata.h"
14+
#include "llvm/IR/Module.h"
15+
16+
#define DEBUG_TYPE "dxil-finalize-linkage"
17+
18+
using namespace llvm;
19+
20+
static bool finalizeLinkage(Module &M) {
21+
SmallPtrSet<Function *, 8> EntriesAndExports;
22+
23+
// Find all entry points and export functions
24+
for (Function &EF : M.functions()) {
25+
if (!EF.hasFnAttribute("hlsl.shader") && !EF.hasFnAttribute("hlsl.export"))
26+
continue;
27+
EntriesAndExports.insert(&EF);
28+
}
29+
30+
for (Function &F : M.functions()) {
31+
if (F.getLinkage() == GlobalValue::ExternalLinkage &&
32+
!EntriesAndExports.contains(&F)) {
33+
F.setLinkage(GlobalValue::InternalLinkage);
34+
}
35+
}
36+
37+
return false;
38+
}
39+
40+
PreservedAnalyses DXILFinalizeLinkage::run(Module &M,
41+
ModuleAnalysisManager &AM) {
42+
if (finalizeLinkage(M))
43+
return PreservedAnalyses::none();
44+
return PreservedAnalyses::all();
45+
}
46+
47+
bool DXILFinalizeLinkageLegacy::runOnModule(Module &M) {
48+
return finalizeLinkage(M);
49+
}
50+
51+
char DXILFinalizeLinkageLegacy::ID = 0;
52+
53+
INITIALIZE_PASS_BEGIN(DXILFinalizeLinkageLegacy, DEBUG_TYPE,
54+
"DXIL Finalize Linkage", false, false)
55+
INITIALIZE_PASS_END(DXILFinalizeLinkageLegacy, DEBUG_TYPE,
56+
"DXIL Finalize Linkage", false, false)
57+
58+
ModulePass *llvm::createDXILFinalizeLinkageLegacyPass() {
59+
return new DXILFinalizeLinkageLegacy();
60+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===- DXILFinalizeLinkage.h - Finalize linkage of functions --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// DXILFinalizeLinkage pass updates the linkage of functions to make sure only
10+
/// shader entry points and exported functions are visible from the module (have
11+
/// program linkage). All other functions will be updated to have internal
12+
/// linkage.
13+
///
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_TARGET_DIRECTX_DXILFINALIZELINKAGE_H
17+
#define LLVM_TARGET_DIRECTX_DXILFINALIZELINKAGE_H
18+
19+
#include "llvm/IR/PassManager.h"
20+
#include "llvm/Pass.h"
21+
22+
namespace llvm {
23+
24+
class DXILFinalizeLinkage : public PassInfoMixin<DXILFinalizeLinkage> {
25+
public:
26+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
27+
static bool isRequired() { return true; }
28+
};
29+
30+
class DXILFinalizeLinkageLegacy : public ModulePass {
31+
public:
32+
DXILFinalizeLinkageLegacy() : ModulePass(ID) {}
33+
bool runOnModule(Module &M) override;
34+
35+
static char ID; // Pass identification.
36+
};
37+
} // namespace llvm
38+
39+
#endif // LLVM_TARGET_DIRECTX_DXILFINALIZELINKAGE_H

llvm/lib/Target/DirectX/DirectX.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ void initializeDXContainerGlobalsPass(PassRegistry &);
6363

6464
/// Pass for generating DXContainer part globals.
6565
ModulePass *createDXContainerGlobalsPass();
66+
67+
/// Initializer for DXILFinalizeLinkage pass.
68+
void initializeDXILFinalizeLinkageLegacyPass(PassRegistry &);
69+
70+
/// Pass to finalize linkage of functions.
71+
ModulePass *createDXILFinalizeLinkageLegacyPass();
72+
6673
} // namespace llvm
6774

6875
#endif // LLVM_LIB_TARGET_DIRECTX_DIRECTX_H

llvm/lib/Target/DirectX/DirectXTargetMachine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() {
4848
initializeDXILTranslateMetadataPass(*PR);
4949
initializeDXILResourceMDWrapperPass(*PR);
5050
initializeShaderFlagsAnalysisWrapperPass(*PR);
51+
initializeDXILFinalizeLinkageLegacyPass(*PR);
5152
}
5253

5354
class DXILTargetObjectFile : public TargetLoweringObjectFile {
@@ -79,6 +80,7 @@ class DirectXPassConfig : public TargetPassConfig {
7980
void addCodeGenPrepare() override {
8081
addPass(createDXILIntrinsicExpansionLegacyPass());
8182
addPass(createDXILOpLoweringLegacyPass());
83+
addPass(createDXILFinalizeLinkageLegacyPass());
8284
addPass(createDXILTranslateMetadataPass());
8385
addPass(createDXILPrepareModulePass());
8486
}

llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ define i64 @test(ptr %p) {
77
ret i64 %v
88
}
99

10-
; CHECK: define i64 @test(ptr %p) {
10+
; CHECK: define internal i64 @test(ptr %p) {
1111
; CHECK-NEXT: %1 = bitcast ptr %p to ptr
1212
; CHECK-NEXT: store i32 0, ptr %1, align 4
1313
; CHECK-NEXT: %2 = bitcast ptr %p to ptr
@@ -19,7 +19,7 @@ define i64 @testGEP(ptr %p) {
1919
ret i64 %val
2020
}
2121

22-
; CHECK: define i64 @testGEP(ptr %p) {
22+
; CHECK: define internal i64 @testGEP(ptr %p) {
2323
; CHECK-NEXT: %1 = bitcast ptr %p to ptr
2424
; CHECK-NEXT: %ptr = getelementptr i32, ptr %1, i32 4
2525
; CHECK-NEXT: %2 = bitcast ptr %p to ptr
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
; RUN: opt -S -dxil-finalize-linkage -mtriple=dxil-unknown-shadermodel6.5-compute %s | FileCheck %s
2+
; RUN: llc %s --filetype=asm -o - | FileCheck %s --check-prefixes=CHECK-LLC
3+
4+
target triple = "dxilv1.5-pc-shadermodel6.5-compute"
5+
6+
; DXILFinalizeLinkage changes linkage of all functions that are not
7+
; entry points or exported function to internal.
8+
9+
; CHECK: define internal void @"?f1@@YAXXZ"()
10+
define void @"?f1@@YAXXZ"() #0 {
11+
entry:
12+
ret void
13+
}
14+
15+
; CHECK: define internal void @"?f2@@YAXXZ"()
16+
define void @"?f2@@YAXXZ"() #0 {
17+
entry:
18+
ret void
19+
}
20+
21+
; CHECK: define internal void @"?f3@@YAXXZ"()
22+
define void @"?f3@@YAXXZ"() #0 {
23+
entry:
24+
ret void
25+
}
26+
27+
; CHECK: define internal void @"?foo@@YAXXZ"()
28+
define void @"?foo@@YAXXZ"() #0 {
29+
entry:
30+
call void @"?f2@@YAXXZ"() #3
31+
ret void
32+
}
33+
34+
; Exported function - do not change linkage
35+
; CHECK: define void @"?bar@@YAXXZ"()
36+
define void @"?bar@@YAXXZ"() #1 {
37+
entry:
38+
call void @"?f3@@YAXXZ"() #3
39+
ret void
40+
}
41+
42+
; CHECK: define internal void @"?main@@YAXXZ"() #0
43+
define internal void @"?main@@YAXXZ"() #0 {
44+
entry:
45+
call void @"?foo@@YAXXZ"() #3
46+
call void @"?bar@@YAXXZ"() #3
47+
ret void
48+
}
49+
50+
; Entry point function - do not change linkage
51+
; CHECK: define void @main() #2
52+
define void @main() #2 {
53+
entry:
54+
call void @"?main@@YAXXZ"()
55+
ret void
56+
}
57+
58+
attributes #0 = { convergent noinline nounwind optnone}
59+
attributes #1 = { convergent noinline nounwind optnone "hlsl.export"}
60+
attributes #2 = { convergent "hlsl.numthreads"="4,1,1" "hlsl.shader"="compute"}
61+
attributes #3 = { convergent }
62+
63+
; Make sure "hlsl.export" attribute is stripped by llc
64+
; CHECK-LLC-NOT: "hlsl.export"

llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ define i64 @test(ptr %p) {
66
ret i64 %v
77
}
88

9-
; CHECK: define i64 @test(ptr %p) {
9+
; CHECK: define internal i64 @test(ptr %p) {
1010
; CHECK-NEXT: %v = load i64, ptr %p, align 8
1111
; CHECK-NEXT: ret i64 %v
1212

@@ -16,7 +16,7 @@ define i64 @test2(ptr %p) {
1616
ret i64 %v
1717
}
1818

19-
; CHECK: define i64 @test2(ptr %p) {
19+
; CHECK: define internal i64 @test2(ptr %p) {
2020
; CHECK-NEXT: store i64 0, ptr %p
2121
; CHECK-NEXT: %v = load i64, ptr %p, align 8
2222
; CHECK-NEXT: ret i64 %v
@@ -27,6 +27,6 @@ define i32 @test3(ptr %0) {
2727
ret i32 %3
2828
}
2929

30-
; CHECK: define i32 @test3(ptr %0) {
30+
; CHECK: define internal i32 @test3(ptr %0) {
3131
; CHECK-NEXT: %2 = getelementptr i32, ptr %0, i32 4
3232
; CHECK-NEXT: %3 = load i32, ptr %2

0 commit comments

Comments
 (0)