-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[HLSL] Mark exported functions with "hlsl.export" attribute #102275
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
Conversation
…rts' This information will be used by DXILFinalizeLinkage pass (coming soon) to determine which functions should have internal linkage in the final DXIL code. After this pass is completed the `dx.exports` metadata node will be removed.
✅ With the latest revision this PR passed the C/C++ code formatter. |
dx.exports
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: Helena Kotas (hekota) ChangesAdds list of exported functions as named metadata node 'dx.exports`. During CodeGen each exported functions is marked with an "hlsl.export" attribute. Based on these attributes the DXILTranslateMetadata pass will create a list of all export functions and will add it to the module under This information will be then used by DXILFinalizeLinkage pass (coming soon) to determine which functions should have internal linkage in the final DXIL code. After this pass is completed the Full diff: https://github.com/llvm/llvm-project/pull/102275.diff 8 Files Affected:
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a2c3e76f77b7c..5e59b0f00ebd6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -412,6 +412,14 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
B.CreateRetVoid();
}
+void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl *FD,
+ llvm::Function *Fn) {
+ if (FD->isInExportDeclContext()) {
+ const StringRef ExportAttrKindStr = "hlsl.export";
+ Fn->addFnAttr(ExportAttrKindStr);
+ }
+}
+
static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
bool CtorOrDtor) {
const auto *GV =
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 527e73a0e21fc..590d388c456c4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -124,7 +124,7 @@ class CGHLSLRuntime {
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
- void setHLSLFunctionAttributes(llvm::Function *, const FunctionDecl *);
+ void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index af201554898f3..9e9dd6b9c8e17 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1223,9 +1223,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (getLangOpts().OpenMP && CurCodeDecl)
CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);
- // Handle emitting HLSL entry functions.
- if (D && D->hasAttr<HLSLShaderAttr>())
- CGM.getHLSLRuntime().emitEntryFunction(FD, Fn);
+ if (FD && getLangOpts().HLSL) {
+ // Handle emitting HLSL entry functions.
+ if (FD->hasAttr<HLSLShaderAttr>()) {
+ CGM.getHLSLRuntime().emitEntryFunction(FD, Fn);
+ }
+ CGM.getHLSLRuntime().setHLSLFunctionAttributes(FD, Fn);
+ }
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl
index 53f603739e329..63f9f9066f927 100644
--- a/clang/test/CodeGenHLSL/export.hlsl
+++ b/clang/test/CodeGenHLSL/export.hlsl
@@ -2,19 +2,21 @@
// RUN: dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: define void @"?f1@@YAXXZ"()
+// CHECK: define void @"?f1@@YAXXZ"() [[Attr:\#[0-9]+]]
export void f1() {
}
-// CHECK: define void @"?f2@MyNamespace@@YAXXZ"()
+// CHECK: define void @"?f2@MyNamespace@@YAXXZ"() [[Attr]]
namespace MyNamespace {
export void f2() {
}
}
export {
-// CHECK: define void @"?f3@@YAXXZ"()
-// CHECK: define void @"?f4@@YAXXZ"()
+// CHECK: define void @"?f3@@YAXXZ"() [[Attr]]
+// CHECK: define void @"?f4@@YAXXZ"() [[Attr]]
void f3() {}
void f4() {}
}
+
+// CHECK: attributes [[Attr]] = { {{.*}} "hlsl.export" {{.*}} }
diff --git a/llvm/lib/Target/DirectX/DXILMetadata.cpp b/llvm/lib/Target/DirectX/DXILMetadata.cpp
index ed0434ac98a18..5ec56a2852502 100644
--- a/llvm/lib/Target/DirectX/DXILMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILMetadata.cpp
@@ -328,3 +328,23 @@ void dxil::createEntryMD(Module &M, const uint64_t ShaderFlags) {
for (auto *Entry : Entries)
EntryPointsNamedMD->addOperand(Entry);
}
+
+void dxil::createExportsMD(Module &M) {
+ LLVMContext &Ctx = M.getContext();
+ std::vector<MDNode *> ExportsMDList;
+ for (auto &F : M.functions()) {
+ if (!F.hasFnAttribute("hlsl.export"))
+ continue;
+
+ Metadata *MDVals[2];
+ MDVals[0] = ValueAsMetadata::get(&F);
+ MDVals[1] = MDString::get(Ctx, F.getName());
+ ExportsMDList.emplace_back(MDNode::get(Ctx, MDVals));
+ }
+
+ if (ExportsMDList.size() != 0) {
+ NamedMDNode *ExportsNamedMD = M.getOrInsertNamedMetadata("dx.exports");
+ for (auto *ExpMD : ExportsMDList)
+ ExportsNamedMD->addOperand(ExpMD);
+ }
+}
diff --git a/llvm/lib/Target/DirectX/DXILMetadata.h b/llvm/lib/Target/DirectX/DXILMetadata.h
index e05db8d5370db..cee05661c81ca 100644
--- a/llvm/lib/Target/DirectX/DXILMetadata.h
+++ b/llvm/lib/Target/DirectX/DXILMetadata.h
@@ -36,6 +36,7 @@ class ValidatorVersionMD {
void createShaderModelMD(Module &M);
void createDXILVersionMD(Module &M);
void createEntryMD(Module &M, const uint64_t ShaderFlags);
+void createExportsMD(Module &M);
} // namespace dxil
} // namespace llvm
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 583bce0f50e70..54eebac6a95d1 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -57,6 +57,7 @@ bool DXILTranslateMetadata::runOnModule(Module &M) {
const uint64_t Flags = static_cast<uint64_t>(
getAnalysis<ShaderFlagsAnalysisWrapper>().getShaderFlags());
dxil::createEntryMD(M, Flags);
+ dxil::createExportsMD(M);
return false;
}
diff --git a/llvm/test/CodeGen/DirectX/Metadata/exports.ll b/llvm/test/CodeGen/DirectX/Metadata/exports.ll
new file mode 100644
index 0000000000000..4e84ddc4ce90c
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/exports.ll
@@ -0,0 +1,19 @@
+; RUN: opt -S -dxil-metadata-emit %s | FileCheck %s
+
+target triple = "dxilv1.3-unknown-shadermodel6.3-library"
+
+define void @"?f1@@YAXXZ"() #0 {
+entry:
+ ret void
+}
+
+define void @"?f2@MyNamespace@@YAXXZ"() #0 {
+entry:
+ ret void
+}
+
+attributes #0 = { convergent noinline nounwind optnone "hlsl.export" }
+
+; CHECK: !dx.exports = !{[[Exp1:![0-9]+]], [[Exp2:![0-9]+]]}
+; CHECK: [[Exp1]] = !{ptr @"?f1@@YAXXZ", !"?f1@@YAXXZ"}
+; CHECK: [[Exp2]] = !{ptr @"?f2@MyNamespace@@YAXXZ", !"?f2@MyNamespace@@YAXXZ"}
|
@llvm/pr-subscribers-backend-directx Author: Helena Kotas (hekota) ChangesAdds list of exported functions as named metadata node 'dx.exports`. During CodeGen each exported functions is marked with an "hlsl.export" attribute. Based on these attributes the DXILTranslateMetadata pass will create a list of all export functions and will add it to the module under This information will be then used by DXILFinalizeLinkage pass (coming soon) to determine which functions should have internal linkage in the final DXIL code. After this pass is completed the Full diff: https://github.com/llvm/llvm-project/pull/102275.diff 8 Files Affected:
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a2c3e76f77b7c..5e59b0f00ebd6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -412,6 +412,14 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
B.CreateRetVoid();
}
+void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl *FD,
+ llvm::Function *Fn) {
+ if (FD->isInExportDeclContext()) {
+ const StringRef ExportAttrKindStr = "hlsl.export";
+ Fn->addFnAttr(ExportAttrKindStr);
+ }
+}
+
static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
bool CtorOrDtor) {
const auto *GV =
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 527e73a0e21fc..590d388c456c4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -124,7 +124,7 @@ class CGHLSLRuntime {
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
- void setHLSLFunctionAttributes(llvm::Function *, const FunctionDecl *);
+ void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index af201554898f3..9e9dd6b9c8e17 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1223,9 +1223,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (getLangOpts().OpenMP && CurCodeDecl)
CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);
- // Handle emitting HLSL entry functions.
- if (D && D->hasAttr<HLSLShaderAttr>())
- CGM.getHLSLRuntime().emitEntryFunction(FD, Fn);
+ if (FD && getLangOpts().HLSL) {
+ // Handle emitting HLSL entry functions.
+ if (FD->hasAttr<HLSLShaderAttr>()) {
+ CGM.getHLSLRuntime().emitEntryFunction(FD, Fn);
+ }
+ CGM.getHLSLRuntime().setHLSLFunctionAttributes(FD, Fn);
+ }
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl
index 53f603739e329..63f9f9066f927 100644
--- a/clang/test/CodeGenHLSL/export.hlsl
+++ b/clang/test/CodeGenHLSL/export.hlsl
@@ -2,19 +2,21 @@
// RUN: dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: define void @"?f1@@YAXXZ"()
+// CHECK: define void @"?f1@@YAXXZ"() [[Attr:\#[0-9]+]]
export void f1() {
}
-// CHECK: define void @"?f2@MyNamespace@@YAXXZ"()
+// CHECK: define void @"?f2@MyNamespace@@YAXXZ"() [[Attr]]
namespace MyNamespace {
export void f2() {
}
}
export {
-// CHECK: define void @"?f3@@YAXXZ"()
-// CHECK: define void @"?f4@@YAXXZ"()
+// CHECK: define void @"?f3@@YAXXZ"() [[Attr]]
+// CHECK: define void @"?f4@@YAXXZ"() [[Attr]]
void f3() {}
void f4() {}
}
+
+// CHECK: attributes [[Attr]] = { {{.*}} "hlsl.export" {{.*}} }
diff --git a/llvm/lib/Target/DirectX/DXILMetadata.cpp b/llvm/lib/Target/DirectX/DXILMetadata.cpp
index ed0434ac98a18..5ec56a2852502 100644
--- a/llvm/lib/Target/DirectX/DXILMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILMetadata.cpp
@@ -328,3 +328,23 @@ void dxil::createEntryMD(Module &M, const uint64_t ShaderFlags) {
for (auto *Entry : Entries)
EntryPointsNamedMD->addOperand(Entry);
}
+
+void dxil::createExportsMD(Module &M) {
+ LLVMContext &Ctx = M.getContext();
+ std::vector<MDNode *> ExportsMDList;
+ for (auto &F : M.functions()) {
+ if (!F.hasFnAttribute("hlsl.export"))
+ continue;
+
+ Metadata *MDVals[2];
+ MDVals[0] = ValueAsMetadata::get(&F);
+ MDVals[1] = MDString::get(Ctx, F.getName());
+ ExportsMDList.emplace_back(MDNode::get(Ctx, MDVals));
+ }
+
+ if (ExportsMDList.size() != 0) {
+ NamedMDNode *ExportsNamedMD = M.getOrInsertNamedMetadata("dx.exports");
+ for (auto *ExpMD : ExportsMDList)
+ ExportsNamedMD->addOperand(ExpMD);
+ }
+}
diff --git a/llvm/lib/Target/DirectX/DXILMetadata.h b/llvm/lib/Target/DirectX/DXILMetadata.h
index e05db8d5370db..cee05661c81ca 100644
--- a/llvm/lib/Target/DirectX/DXILMetadata.h
+++ b/llvm/lib/Target/DirectX/DXILMetadata.h
@@ -36,6 +36,7 @@ class ValidatorVersionMD {
void createShaderModelMD(Module &M);
void createDXILVersionMD(Module &M);
void createEntryMD(Module &M, const uint64_t ShaderFlags);
+void createExportsMD(Module &M);
} // namespace dxil
} // namespace llvm
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 583bce0f50e70..54eebac6a95d1 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -57,6 +57,7 @@ bool DXILTranslateMetadata::runOnModule(Module &M) {
const uint64_t Flags = static_cast<uint64_t>(
getAnalysis<ShaderFlagsAnalysisWrapper>().getShaderFlags());
dxil::createEntryMD(M, Flags);
+ dxil::createExportsMD(M);
return false;
}
diff --git a/llvm/test/CodeGen/DirectX/Metadata/exports.ll b/llvm/test/CodeGen/DirectX/Metadata/exports.ll
new file mode 100644
index 0000000000000..4e84ddc4ce90c
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/exports.ll
@@ -0,0 +1,19 @@
+; RUN: opt -S -dxil-metadata-emit %s | FileCheck %s
+
+target triple = "dxilv1.3-unknown-shadermodel6.3-library"
+
+define void @"?f1@@YAXXZ"() #0 {
+entry:
+ ret void
+}
+
+define void @"?f2@MyNamespace@@YAXXZ"() #0 {
+entry:
+ ret void
+}
+
+attributes #0 = { convergent noinline nounwind optnone "hlsl.export" }
+
+; CHECK: !dx.exports = !{[[Exp1:![0-9]+]], [[Exp2:![0-9]+]]}
+; CHECK: [[Exp1]] = !{ptr @"?f1@@YAXXZ", !"?f1@@YAXXZ"}
+; CHECK: [[Exp2]] = !{ptr @"?f2@MyNamespace@@YAXXZ", !"?f2@MyNamespace@@YAXXZ"}
|
Could this be an analysis pass which collect the list as a SmallVector<Function*> instead of creating the list in 'dx.exports' metadata? |
You mean the DXILFinalizeLinkage pass (coming soon) that needs a list of entries and exported functions should get the information from "hlsl.shader" and "hlsl.export" attributes on the functions? Instead of relying on the metadata? |
I mean DXILFinalizeLinkage pass could use an analysis pass to get the list of export functions. The collecting of the list happens in the analysis pass. No need to create a named metadata and remove it later. |
Sounds good. It will probably be easier for the DXILFinalizeLinkage to collect the list of entry and export functions when it runs without creating a separate analysis pass for it since it is the only one that needs it. |
dx.exports
Marks exported functions with
"hlsl.export"
attribute. This information will be later used by DXILFinalizeLinkage pass (coming soon) to determine which functions should have internal linkage in the final DXIL code.Related to ##92071