-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[clang] Add spir_kernel attribute #137882
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
base: main
Are you sure you want to change the base?
Conversation
711a62e
to
20498a3
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-clang Author: Nick Sarnie (sarnex) ChangesSPIR kernels have a specific calling convention, so add an attribute to explicitly specify this calling convention when targetting pure SPIR/SPIRV. Full diff: https://github.com/llvm/llvm-project/pull/137882.diff 14 Files Affected:
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a734eb6658c3d..c3a3db095bb81 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -472,7 +472,9 @@ def TargetRISCV : TargetArch<["riscv32", "riscv64"]>;
def TargetX86 : TargetArch<["x86"]>;
def TargetX86_64 : TargetArch<["x86_64"]>;
def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
+def TargetSPIR : TargetArch<["spir", "spir64"]>;
def TargetSPIRV : TargetArch<["spirv", "spirv32", "spirv64"]>;
+def TargetAnySPIR : TargetArch<!listconcat(TargetSPIR.Arches, TargetSPIRV.Arches)>;
def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>;
def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>;
def TargetWindows : TargetSpec {
@@ -1504,6 +1506,12 @@ def NVPTXKernel : InheritableAttr, TargetSpecificAttr<TargetNVPTX> {
let Documentation = [Undocumented];
}
+def SPIRKernel : InheritableAttr, TargetSpecificAttr<TargetAnySPIR> {
+ let Spellings = [Clang<"spir_kernel">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [Undocumented];
+}
+
def HIPManaged : InheritableAttr {
let Spellings = [GNU<"managed">, Declspec<"__managed__">];
let Subjects = SubjectList<[Var]>;
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 491badcc804e7..f9a72f378490e 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -289,6 +289,7 @@ namespace clang {
CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp")))
CC_IntelOclBicc, // __attribute__((intel_ocl_bicc))
CC_SpirFunction, // default for OpenCL functions on SPIR target
+ CC_SpirKernel, // __attribute__((spir_kernel))
CC_OpenCLKernel, // inferred for OpenCL kernels
CC_Swift, // __attribute__((swiftcall))
CC_SwiftAsync, // __attribute__((swiftasynccall))
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 33a8728728574..c16005ccaf51f 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3532,6 +3532,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
case CC_AMDGPUKernelCall:
case CC_IntelOclBicc:
case CC_SpirFunction:
+ case CC_SpirKernel:
case CC_OpenCLKernel:
case CC_PreserveMost:
case CC_PreserveAll:
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 59369fba2e772..da9ba8e3e971a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3623,6 +3623,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
return "intel_ocl_bicc";
case CC_SpirFunction:
return "spir_function";
+ case CC_SpirKernel:
+ return "spir_kernel";
case CC_OpenCLKernel:
return "opencl_kernel";
case CC_Swift:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index cba1a2d98d660..5aa37ca9ec17f 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1115,6 +1115,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
case CC_OpenCLKernel:
// Do nothing. These CCs are not available as attributes.
break;
+ case CC_SpirKernel:
+ OS << " __attribute__((spir_kernel))";
+ break;
case CC_Swift:
OS << " __attribute__((swiftcall))";
break;
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..43c71a1aeb5d5 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -191,8 +191,10 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
}
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK
- : CCCR_Warning;
+ return (CC == CC_SpirKernel || CC == CC_SpirFunction ||
+ CC == CC_OpenCLKernel)
+ ? CCCR_OK
+ : CCCR_Warning;
}
CallingConv getDefaultCallingConv() const override {
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 83b0e8e965770..a7bbff116b584 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -84,6 +84,8 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
return llvm::CallingConv::AMDGPU_KERNEL;
case CC_SpirFunction:
return llvm::CallingConv::SPIR_FUNC;
+ case CC_SpirKernel:
+ return llvm::CallingConv::SPIR_KERNEL;
case CC_OpenCLKernel:
return CGM.getTargetCodeGenInfo().getOpenCLKernelCallingConv();
case CC_PreserveMost:
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index f3ec498d4064b..10fba7b772486 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1589,6 +1589,8 @@ static unsigned getDwarfCC(CallingConv CC) {
return llvm::dwarf::DW_CC_LLVM_IntelOclBicc;
case CC_SpirFunction:
return llvm::dwarf::DW_CC_LLVM_SpirFunction;
+ case CC_SpirKernel:
+ return llvm::dwarf::DW_CC_LLVM_SpirKernel;
case CC_OpenCLKernel:
case CC_AMDGPUKernelCall:
return llvm::dwarf::DW_CC_LLVM_OpenCLKernel;
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index f35c124f50aa0..29a258e457317 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -60,6 +60,8 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
void
setOCLKernelStubCallingConvention(const FunctionType *&FT) const override;
+ void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
};
class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
public:
@@ -238,6 +240,20 @@ void CommonSPIRTargetCodeGenInfo::setOCLKernelStubCallingConvention(
FT, FT->getExtInfo().withCallingConv(CC_SpirFunction));
}
+void CommonSPIRTargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (!FD)
+ return;
+
+ llvm::Function *F = cast<llvm::Function>(GV);
+
+ // Attach kernel metadata directly if compiling for SPIR.
+ if (FD->hasAttr<SPIRKernelAttr>()) {
+ F->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
+ }
+}
+
LangAS
SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const {
@@ -262,6 +278,7 @@ SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
void SPIRVTargetCodeGenInfo::setTargetAttributes(
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
+ CommonSPIRTargetCodeGenInfo::setTargetAttributes(D, GV, M);
if (!M.getLangOpts().HIP ||
M.getTarget().getTriple().getVendor() != llvm::Triple::AMD)
return;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index ab66ae860f86b..56aea1e878f23 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5503,6 +5503,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
llvm::Log2_64(ABIVLen) - 5);
break;
}
+ case ParsedAttr::AT_SPIRKernel:
+ CC = CC_SpirKernel;
+ break;
default: llvm_unreachable("unexpected attribute kind");
}
@@ -7152,6 +7155,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_CUDALaunchBounds:
handleLaunchBoundsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_SPIRKernel:
+ handleSimpleAttribute<SPIRKernelAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_Restrict:
handleRestrictAttr(S, D, AL);
break;
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 7affacb1a109a..53a7ea4c8033b 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -181,6 +181,7 @@
// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
// CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function)
+// CHECK-NEXT: SPIRKernel (SubjectMatchRule_function)
// CHECK-NEXT: SYCLKernelEntryPoint (SubjectMatchRule_function)
// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record)
// CHECK-NEXT: ScopedLockable (SubjectMatchRule_record)
diff --git a/clang/test/Misc/spir-kernel-attr.c b/clang/test/Misc/spir-kernel-attr.c
new file mode 100644
index 0000000000000..40de980716ff2
--- /dev/null
+++ b/clang/test/Misc/spir-kernel-attr.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple spir -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple spir64 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-compute -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple spirv32 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple spirv64 -emit-llvm %s -o - | FileCheck %s
+__attribute__((spir_kernel)) void foo(void) {}
+
+[[clang::spir_kernel]] void bar(void) {}
+
+// CHECK-COUNT-2: spir_kernel
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index e52324a8ebc12..575ab05f4e3c4 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -1127,6 +1127,7 @@ HANDLE_DW_CC(0xcd, LLVM_PreserveNone)
HANDLE_DW_CC(0xce, LLVM_RISCVVectorCall)
HANDLE_DW_CC(0xcf, LLVM_SwiftTail)
HANDLE_DW_CC(0xd0, LLVM_RISCVVLSCall)
+HANDLE_DW_CC(0xd1, LLVM_SpirKernel)
// From GCC source code (include/dwarf2.h): This DW_CC_ value is not currently
// generated by any toolchain. It is used internally to GDB to indicate OpenCL
// C functions that have been compiled with the IBM XL C for OpenCL compiler and
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index bd25f6c30ebf1..82337774f2396 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -741,6 +741,9 @@ void DWARFTypePrinter<DieType>::appendSubroutineNameAfter(
// instantiated with function types with these calling conventions won't
// have distinct names - so we'd need to fix that too)
break;
+ case dwarf::CallingConvention::DW_CC_LLVM_SpirKernel:
+ OS << " __attribute((spir_kernel))";
+ break;
case dwarf::CallingConvention::DW_CC_LLVM_Swift:
// SwiftAsync missing
OS << " __attribute__((swiftcall))";
|
clang/lib/Sema/SemaDeclAttr.cpp
Outdated
@@ -5503,6 +5503,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, | |||
llvm::Log2_64(ABIVLen) - 5); | |||
break; | |||
} | |||
case ParsedAttr::AT_SPIRKernel: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a silly request, but please sort this as 'not last'. It is too easy to miss when after a big block.
clang/include/clang/Basic/Attr.td
Outdated
def SPIRKernel : InheritableAttr, TargetSpecificAttr<TargetAnySPIR> { | ||
let Spellings = [Clang<"spir_kernel">]; | ||
let Subjects = SubjectList<[Function]>; | ||
let Documentation = [Undocumented]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this non-documented? WE very much don't approve/accept new undocumented attributes without good reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I wasn't sure how strict we were with that, will add documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need yet another calling convention or is there a way we can start to combine some of these for all the offloading languages? It seems we keep re-implementing the same concepts multiple times for each language and it would be nice to share as much of the frontend logic as possible rather than keep doing this dance of adding another case to every switch in the compiler. :-D
Do you have an idea? Maybe we could have a |
I was thinking that orthogonal calling conventions could be combined so that we need fewer of them. e.g., if spir_kernel cannot be mixed with nvptx_kernel in the same TU, then there's no need for two distinct internal representations for the attributes, just two distinct spellings that are based on the target. |
Ah, I see. Okay, I'll try, but it might take me a while. Thanks for the feedback. Marking this as a draft for now. |
Signed-off-by: Sarnie, Nick <[email protected]>
@AaronBallman I just pushed a first attempt to combine the attrs, however I'm not sure if it's much cleaner given the attrs have different subjects/allowed cases/expected warnings/etc. Do you mind taking a first look and seeing if you think the general direction is a good idea? Thanks |
SPIR kernels have a specific calling convention, so add an attribute to explicitly specify this calling convention when targetting pure SPIR/SPIRV.