[clang] 3d19371 - [CIR] Add calling_conv attribute to FuncOp with lowering support (#189345)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 29 21:53:27 PDT 2026
Author: Rana Pratap Reddy
Date: 2026-04-30T10:23:22+05:30
New Revision: 3d19371ef119ad9d93e14408b4bc51e870c2ae25
URL: https://github.com/llvm/llvm-project/commit/3d19371ef119ad9d93e14408b4bc51e870c2ae25
DIFF: https://github.com/llvm/llvm-project/commit/3d19371ef119ad9d93e14408b4bc51e870c2ae25.diff
LOG: [CIR] Add calling_conv attribute to FuncOp with lowering support (#189345)
Adds `calling_conv` attribute to `FuncOp` with support
(`cc(amdgpu_kernel)` syntax) and LLVM lowering.
Continuation of #188715 and a partial upstreaming of
[clangir#760](https://github.com/llvm/clangir/pull/760/).
Added:
clang/test/CIR/IR/calling-conv.cir
clang/test/CIR/Lowering/calling-conv.cir
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/include/clang/CIR/MissingFeatures.h
clang/lib/CIR/CodeGen/CIRGenCall.cpp
clang/lib/CIR/CodeGen/CIRGenModule.cpp
clang/lib/CIR/Dialect/IR/CIRDialect.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index b30dd980f5569..97d623ba5e6d9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3628,9 +3628,16 @@ def CIR_OptionalPriorityAttr : OptionalAttr<
>
>;
-// TODO(CIR): CallingConv is a placeholder here so we can use it in
-// infrastructure calls, but it currently has no values.
-def CIR_CallingConv : CIR_I32EnumAttr<"CallingConv", "calling convention", []>;
+// The enumeration cases are ordered to match `llvm::CallingConv`. The values
+// are CIR-specific and are not in sync with `llvm::CallingConv` or
+// `clang::CallingConv`.
+def CIR_CallingConv : CIR_I32EnumAttr<"CallingConv", "calling convention", [
+ I32EnumAttrCase<"C", 0, "c">,
+ I32EnumAttrCase<"PTXKernel", 1, "ptx_kernel">,
+ I32EnumAttrCase<"SpirFunction", 2, "spir_function">,
+ I32EnumAttrCase<"SpirKernel", 3, "spir_kernel">,
+ I32EnumAttrCase<"AMDGPUKernel", 4, "amdgpu_kernel">
+]>;
def CIR_FuncOp : CIR_Op<"func", [
AutomaticAllocationScope, CallableOpInterface, FunctionOpInterface,
@@ -3646,6 +3653,11 @@ def CIR_FuncOp : CIR_Op<"func", [
The function linkage information is specified by `linkage`, as defined by
`GlobalLinkageKind` attribute.
+ The `calling_conv` attribute specifies the calling convention of the function.
+ By default calling convention is `CallingConv::C`. When printed, C calling
+ convention is omitted. Other calling conventions are printed as `cc(<mnemonic>)`,
+ e.g. `cc(amdgpu_kernel)`.
+
A compiler builtin function must be marked as `builtin` for further
processing when lowering from CIR.
@@ -3687,6 +3699,9 @@ def CIR_FuncOp : CIR_Op<"func", [
// Linkage information
cir.func linkonce_odr @some_method(...)
+ // Calling convention information
+ cir.func @func1(...) cc(amdgpu_kernel)
+
// Inline information
cir.func no_inline @some_method(...)
@@ -3718,6 +3733,10 @@ def CIR_FuncOp : CIR_Op<"func", [
CIR_GlobalLinkageKind,
"cir::GlobalLinkageKind::ExternalLinkage"
>:$linkage,
+ DefaultValuedAttr<
+ CIR_CallingConv,
+ "cir::CallingConv::C"
+ >:$calling_conv,
OptionalAttr<StrAttr>:$sym_visibility,
UnitAttr:$comdat,
OptionalAttr<DictArrayAttr>:$arg_attrs,
@@ -3737,7 +3756,8 @@ def CIR_FuncOp : CIR_Op<"func", [
let builders = [OpBuilder<(ins
"llvm::StringRef":$sym_name, "FuncType":$type,
- CArg<"cir::GlobalLinkageKind", "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)
+ CArg<"cir::GlobalLinkageKind", "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
+ CArg<"cir::CallingConv", "cir::CallingConv::C">:$callingConv)
>];
let extraClassDeclaration = [{
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 3cb9dafc0f9ce..645fae3e4404d 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -70,10 +70,10 @@ struct MissingFeatures {
static bool opFuncArmNewAttr() { return false; }
static bool opFuncArmStreamingAttr() { return false; }
static bool opFuncAstDeclAttr() { return false; }
- static bool opFuncCallingConv() { return false; }
static bool opFuncColdHotAttr() { return false; }
static bool opFuncExceptions() { return false; }
static bool opFuncExtraAttrs() { return false; }
+ static bool opFuncCallingConv() { return false; }
static bool opFuncMaybeHandleStaticInExternC() { return false; }
static bool opFuncMinSizeAttr() { return false; }
static bool opFuncMultipleReturnVals() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index e42910490f863..5f3d390e55ce2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -1356,6 +1356,7 @@ mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc,
cir::FuncOp callee,
ArrayRef<mlir::Value> args,
mlir::NamedAttrList attrs) {
+
// TODO(cir): set the calling convention to this runtime call.
assert(!cir::MissingFeatures::opFuncCallingConv());
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 26958cd5d39a8..af8fd52bef017 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2796,10 +2796,10 @@ void CIRGenModule::setCIRFunctionAttributes(GlobalDecl globalDecl,
// TODO(cir): Check X86_VectorCall incompatibility wiht WinARM64EC
- // TODO(cir): typically the calling conv is set right here, but since
- // cir::CallingConv is empty and we've not yet added calling-conv to FuncOop,
- // this isn't really useful here. This should call func.setCallingConv/etc
- // later.
+ // TODO(cir): Set the calling convention computed by constructAttributeList
+ // on the function. FuncOp supports calling_conv, but target-specific
+ // CodeGen is needed to set it correctly (e.g., AMDGPU kernel functions
+ // should be marked with AMDGPUKernel).
assert(!cir::MissingFeatures::opFuncCallingConv());
}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 0ebd08180cadc..7386819d8fce9 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -138,6 +138,7 @@ template <typename Ty> struct EnumTraits {};
REGISTER_ENUM_TYPE(GlobalLinkageKind);
REGISTER_ENUM_TYPE(VisibilityKind);
REGISTER_ENUM_TYPE(SideEffect);
+REGISTER_ENUM_TYPE(CallingConv);
} // namespace
/// Parse an enum from the keyword, or default to the provided default value.
@@ -2191,7 +2192,7 @@ static llvm::StringRef getLinkageAttrNameString() { return "linkage"; }
void cir::FuncOp::build(OpBuilder &builder, OperationState &result,
StringRef name, FuncType type,
- GlobalLinkageKind linkage) {
+ GlobalLinkageKind linkage, CallingConv callingConv) {
result.addRegion();
result.addAttribute(SymbolTable::getSymbolAttrName(),
builder.getStringAttr(name));
@@ -2200,6 +2201,8 @@ void cir::FuncOp::build(OpBuilder &builder, OperationState &result,
result.addAttribute(
getLinkageAttrNameString(),
GlobalLinkageKindAttr::get(builder.getContext(), linkage));
+ result.addAttribute(getCallingConvAttrName(result.name),
+ CallingConvAttr::get(builder.getContext(), callingConv));
}
//===----------------------------------------------------------------------===//
@@ -2351,6 +2354,20 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
return failure();
}
+ // Default to C calling convention if no keyword is provided.
+ mlir::StringAttr callConvNameAttr = getCallingConvAttrName(state.name);
+ cir::CallingConv callConv = cir::CallingConv::C;
+ if (parser.parseOptionalKeyword("cc").succeeded()) {
+ if (parser.parseLParen().failed())
+ return failure();
+ if (parseCIRKeyword<cir::CallingConv>(parser, callConv).failed())
+ return parser.emitError(loc) << "unknown calling convention";
+ if (parser.parseRParen().failed())
+ return failure();
+ }
+ state.addAttribute(callConvNameAttr,
+ cir::CallingConvAttr::get(parser.getContext(), callConv));
+
auto parseGlobalDtorCtor =
[&](StringRef keyword,
llvm::function_ref<void(std::optional<int> prio)> createAttr)
@@ -2569,6 +2586,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
p << ")";
}
+ if (getCallingConv() != cir::CallingConv::C) {
+ p << " cc(";
+ p << stringifyCallingConv(getCallingConv());
+ p << ")";
+ }
+
if (std::optional<StringRef> personalityName = getPersonality()) {
p << " personality(";
p.printSymbolName(*personalityName);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 32be32f7e319f..e17c7a209db6b 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -187,6 +187,25 @@ mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {
llvm_unreachable("Unknown CIR linkage type");
}
+static mlir::LLVM::CConv convertCallingConv(cir::CallingConv callingConv) {
+ using CIR = cir::CallingConv;
+ using LLVM = mlir::LLVM::CConv;
+
+ switch (callingConv) {
+ case CIR::C:
+ return LLVM::C;
+ case CIR::SpirKernel:
+ return LLVM::SPIR_KERNEL;
+ case CIR::SpirFunction:
+ return LLVM::SPIR_FUNC;
+ case CIR::PTXKernel:
+ return LLVM::PTX_Kernel;
+ case CIR::AMDGPUKernel:
+ return LLVM::AMDGPU_KERNEL;
+ }
+ llvm_unreachable("Unknown calling convention");
+}
+
mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
cir::CopyOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1683,7 +1702,6 @@ mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(
static void lowerCallAttributes(cir::CIRCallOpInterface op,
SmallVectorImpl<mlir::NamedAttribute> &result) {
for (mlir::NamedAttribute attr : op->getAttrs()) {
- assert(!cir::MissingFeatures::opFuncCallingConv());
if (attr.getName() == CIRDialect::getCalleeAttrName() ||
attr.getName() == CIRDialect::getSideEffectAttrName() ||
attr.getName() == CIRDialect::getNoThrowAttrName() ||
@@ -2174,12 +2192,11 @@ mlir::LogicalResult CIRToLLVMAbsOpLowering::matchAndRewrite(
void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
cir::FuncOp func, bool filterArgAndResAttrs,
SmallVectorImpl<mlir::NamedAttribute> &result) const {
- assert(!cir::MissingFeatures::opFuncCallingConv());
for (mlir::NamedAttribute attr : func->getAttrs()) {
- assert(!cir::MissingFeatures::opFuncCallingConv());
if (attr.getName() == mlir::SymbolTable::getSymbolAttrName() ||
attr.getName() == func.getFunctionTypeAttrName() ||
attr.getName() == getLinkageAttrNameString() ||
+ attr.getName() == func.getCallingConvAttrName() ||
attr.getName() == func.getDsoLocalAttrName() ||
attr.getName() == func.getInlineKindAttrName() ||
attr.getName() == func.getSideEffectAttrName() ||
@@ -2258,8 +2275,7 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
"expected single location or unknown location here");
mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
- assert(!cir::MissingFeatures::opFuncCallingConv());
- mlir::LLVM::CConv cconv = mlir::LLVM::CConv::C;
+ mlir::LLVM::CConv cconv = convertCallingConv(op.getCallingConv());
SmallVector<mlir::NamedAttribute, 4> attributes;
lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);
diff --git a/clang/test/CIR/IR/calling-conv.cir b/clang/test/CIR/IR/calling-conv.cir
new file mode 100644
index 0000000000000..3f191aa647206
--- /dev/null
+++ b/clang/test/CIR/IR/calling-conv.cir
@@ -0,0 +1,38 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+ // CHECK: cir.func @default_cc(%arg0: !s32i) -> !s32i
+ cir.func @default_cc(%arg0: !s32i) -> !s32i {
+ cir.return %arg0 : !s32i
+ }
+
+ // CHECK: cir.func @amdgpu_kernel_func() cc(amdgpu_kernel)
+ cir.func @amdgpu_kernel_func() cc(amdgpu_kernel) {
+ cir.return
+ }
+
+ // CHECK: cir.func @spir_kernel_func() cc(spir_kernel)
+ cir.func @spir_kernel_func() cc(spir_kernel) {
+ cir.return
+ }
+
+ // CHECK: cir.func @spir_function_func() cc(spir_function)
+ cir.func @spir_function_func() cc(spir_function) {
+ cir.return
+ }
+
+ // CHECK: cir.func @ptx_kernel_func() cc(ptx_kernel)
+ cir.func @ptx_kernel_func() cc(ptx_kernel) {
+ cir.return
+ }
+
+ // CHECK: cir.func no_inline dso_local @amdgpu_noinline() cc(amdgpu_kernel)
+ cir.func no_inline dso_local @amdgpu_noinline() cc(amdgpu_kernel) {
+ cir.return
+ }
+
+ // CHECK: cir.func private @amdgpu_decl() cc(amdgpu_kernel)
+ cir.func private @amdgpu_decl() cc(amdgpu_kernel)
+}
diff --git a/clang/test/CIR/Lowering/calling-conv.cir b/clang/test/CIR/Lowering/calling-conv.cir
new file mode 100644
index 0000000000000..092050e83780d
--- /dev/null
+++ b/clang/test/CIR/Lowering/calling-conv.cir
@@ -0,0 +1,34 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR
+// RUN: cir-translate %s -cir-to-llvmir --disable-cc-lowering | FileCheck %s -check-prefix=LLVM
+
+module {
+ // MLIR: llvm.func @default_cc()
+ // LLVM: define void @default_cc()
+ cir.func @default_cc() {
+ cir.return
+ }
+
+ // MLIR: llvm.func amdgpu_kernelcc @amdgpu_kernel_func()
+ // LLVM: define amdgpu_kernel void @amdgpu_kernel_func()
+ cir.func @amdgpu_kernel_func() cc(amdgpu_kernel) {
+ cir.return
+ }
+
+ // MLIR: llvm.func spir_kernelcc @spir_kernel_func()
+ // LLVM: define spir_kernel void @spir_kernel_func()
+ cir.func @spir_kernel_func() cc(spir_kernel) {
+ cir.return
+ }
+
+ // MLIR: llvm.func spir_funccc @spir_function_func()
+ // LLVM: define spir_func void @spir_function_func()
+ cir.func @spir_function_func() cc(spir_function) {
+ cir.return
+ }
+
+ // MLIR: llvm.func ptx_kernelcc @ptx_kernel_func()
+ // LLVM: define ptx_kernel void @ptx_kernel_func()
+ cir.func @ptx_kernel_func() cc(ptx_kernel) {
+ cir.return
+ }
+}
More information about the cfe-commits
mailing list