Skip to content

[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

Merged
merged 4 commits into from
Aug 13, 2024

Conversation

hekota
Copy link
Member

@hekota hekota commented Aug 7, 2024

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

…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.
Copy link

github-actions bot commented Aug 7, 2024

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

@hekota hekota changed the title [HLSL] Add list of exported functions as named metadata node 'dx.exports` [HLSL] Add list of exported functions as named metadata node dx.exports Aug 7, 2024
@hekota hekota marked this pull request as ready for review August 7, 2024 07:40
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support labels Aug 7, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 7, 2024

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-clang-codegen

Author: Helena Kotas (hekota)

Changes

Adds 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 dx.exports.

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 dx.exports metadata node will be removed.


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

8 Files Affected:

  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+8)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+1-1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+7-3)
  • (modified) clang/test/CodeGenHLSL/export.hlsl (+6-4)
  • (modified) llvm/lib/Target/DirectX/DXILMetadata.cpp (+20)
  • (modified) llvm/lib/Target/DirectX/DXILMetadata.h (+1)
  • (modified) llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp (+1)
  • (added) llvm/test/CodeGen/DirectX/Metadata/exports.ll (+19)
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"}

@llvmbot
Copy link
Member

llvmbot commented Aug 7, 2024

@llvm/pr-subscribers-backend-directx

Author: Helena Kotas (hekota)

Changes

Adds 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 dx.exports.

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 dx.exports metadata node will be removed.


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

8 Files Affected:

  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+8)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+1-1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+7-3)
  • (modified) clang/test/CodeGenHLSL/export.hlsl (+6-4)
  • (modified) llvm/lib/Target/DirectX/DXILMetadata.cpp (+20)
  • (modified) llvm/lib/Target/DirectX/DXILMetadata.h (+1)
  • (modified) llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp (+1)
  • (added) llvm/test/CodeGen/DirectX/Metadata/exports.ll (+19)
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"}

@python3kgae
Copy link
Contributor

Could this be an analysis pass which collect the list as a SmallVector<Function*> instead of creating the list in 'dx.exports' metadata?

@hekota
Copy link
Member Author

hekota commented Aug 7, 2024

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?

@python3kgae
Copy link
Contributor

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.

@hekota
Copy link
Member Author

hekota commented Aug 7, 2024

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.

@hekota hekota changed the title [HLSL] Add list of exported functions as named metadata node dx.exports [HLSL] Mark exported functions with "hlsl.export" attribute Aug 7, 2024
@hekota hekota merged commit 2c8bd4a into llvm:main Aug 13, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang:codegen IR generation bugs: mangling, exceptions, etc. 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.

5 participants