[clang] [CIR] Initial extra attributes for call operation (PR #145178)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 21 10:25:49 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Sirui Mu (Lancern)
<details>
<summary>Changes</summary>
This patch adds extra function attributes to the `cir.call` operation. The extra attributes now may contain a single `cir.nothrow` attribute that indicates whether the callee throws.
---
Full diff: https://github.com/llvm/llvm-project/pull/145178.diff
8 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+27-11)
- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+30)
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+5-16)
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+41-13)
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.h (+2-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+1)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+34-4)
- (modified) clang/test/CIR/CodeGen/call.cpp (+15)
``````````diff
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 3e052c564112e..520ac32dccebc 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -228,25 +228,41 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
mlir::Type returnType, mlir::ValueRange operands,
- cir::SideEffect sideEffect = cir::SideEffect::All) {
- return create<cir::CallOp>(loc, callee, returnType, operands, sideEffect);
+ cir::SideEffect sideEffect = cir::SideEffect::All,
+ cir::ExtraFuncAttributesAttr extraFuncAttr = {}) {
+ auto op =
+ create<cir::CallOp>(loc, callee, returnType, operands, sideEffect);
+
+ if (extraFuncAttr) {
+ op->setAttr("extra_attrs", extraFuncAttr);
+ } else {
+ mlir::NamedAttrList empty;
+ op->setAttr("extra_attrs", cir::ExtraFuncAttributesAttr::get(
+ empty.getDictionary(getContext())));
+ }
+
+ return op;
}
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
mlir::ValueRange operands,
- cir::SideEffect sideEffect = cir::SideEffect::All) {
+ cir::SideEffect sideEffect = cir::SideEffect::All,
+ cir::ExtraFuncAttributesAttr extraFuncAttr = {}) {
return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
callee.getFunctionType().getReturnType(), operands,
- sideEffect);
+ sideEffect, extraFuncAttr);
}
- cir::CallOp createIndirectCallOp(mlir::Location loc,
- mlir::Value indirectTarget,
- cir::FuncType funcType,
- mlir::ValueRange operands,
- cir::SideEffect sideEffect) {
- return create<cir::CallOp>(loc, indirectTarget, funcType.getReturnType(),
- operands, sideEffect);
+ cir::CallOp
+ createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget,
+ cir::FuncType funcType, mlir::ValueRange operands,
+ cir::SideEffect sideEffect,
+ cir::ExtraFuncAttributesAttr extraFuncAttr = {}) {
+ llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
+ resOperands.append(operands.begin(), operands.end());
+
+ return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
+ resOperands, sideEffect, extraFuncAttr);
}
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 9e01dde379d7a..5a03bd0c135cd 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -368,4 +368,34 @@ def CIR_VisibilityAttr : CIR_Attr<"Visibility", "visibility"> {
}];
}
+//===----------------------------------------------------------------------===//
+// ExtraFuncAttributesAttr
+//===----------------------------------------------------------------------===//
+
+def ExtraFuncAttributesAttr : CIR_Attr<"ExtraFuncAttributes", "extra"> {
+ let summary = "Represents aggregated attributes for a function";
+ let description = [{
+ This is a wrapper of attribute dictionary that contains extra attributes of
+ a function.
+ }];
+
+ let parameters = (ins "mlir::DictionaryAttr":$elements);
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::DictionaryAttr":$elements), [{
+ return $_get(elements.getContext(), elements);
+ }]>
+ ];
+
+ let assemblyFormat = [{ `(` $elements `)` }];
+}
+
+//===----------------------------------------------------------------------===//
+// Unit Function Attributes
+//===----------------------------------------------------------------------===//
+
+def NoThrowAttr : CIRUnitAttr<"NoThrow", "nothrow"> {
+ let storageType = "NoThrowAttr";
+}
+
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 852d3aa131148..dfa0079758dc9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1942,7 +1942,8 @@ class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []>
dag commonArgs = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
Variadic<CIR_AnyType>:$args,
- DefaultValuedAttr<CIR_SideEffect, "SideEffect::All">:$side_effect);
+ DefaultValuedAttr<CIR_SideEffect, "SideEffect::All">:$side_effect,
+ ExtraFuncAttributesAttr:$extra_attrs);
}
def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
@@ -1971,29 +1972,17 @@ def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
let arguments = commonArgs;
let builders = [
- // Build a call op for a direct call
OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
"mlir::ValueRange":$operands,
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
- assert(callee && "callee attribute is required for direct call");
$_state.addOperands(operands);
- $_state.addAttribute("callee", callee);
+ if (callee)
+ $_state.addAttribute("callee", callee);
$_state.addAttribute("side_effect",
SideEffectAttr::get($_builder.getContext(), sideEffect));
if (resType && !isa<VoidType>(resType))
$_state.addTypes(resType);
- }]>,
- // Build a call op for an indirect call
- OpBuilder<(ins "mlir::Value":$calleePtr, "mlir::Type":$resType,
- "mlir::ValueRange":$operands,
- CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
- $_state.addOperands(calleePtr);
- $_state.addOperands(operands);
- if (resType && !isa<VoidType>(resType))
- $_state.addTypes(resType);
- $_state.addAttribute("side_effect",
- SideEffectAttr::get($_builder.getContext(), sideEffect));
- }]>,
+ }]>
];
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 9c9c96604c168..17aea1a29aeca 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -77,17 +77,43 @@ void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {
builder.createStore(*currSrcLoc, value, dest);
}
+static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder,
+ mlir::NamedAttrList &attrs,
+ const FunctionProtoType *fpt) {
+ if (!fpt)
+ return;
+
+ if (!isUnresolvedExceptionSpec(fpt->getExceptionSpecType()) &&
+ fpt->isNothrow()) {
+ auto nothrowAttr = cir::NoThrowAttr::get(builder.getContext());
+ attrs.set(nothrowAttr.getMnemonic(), nothrowAttr);
+ }
+}
+
/// Construct the CIR attribute list of a function or call.
void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
+ mlir::NamedAttrList &attrs,
cir::SideEffect &sideEffect) {
assert(!cir::MissingFeatures::opCallCallConv());
sideEffect = cir::SideEffect::All;
- assert(!cir::MissingFeatures::opCallAttrs());
+ addAttributesFromFunctionProtoType(getBuilder(), attrs,
+ calleeInfo.getCalleeFunctionProtoType());
const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
if (targetDecl) {
+ if (targetDecl->hasAttr<NoThrowAttr>()) {
+ auto nothrowAttr = cir::NoThrowAttr::get(&getMLIRContext());
+ attrs.set(nothrowAttr.getMnemonic(), nothrowAttr);
+ }
+
+ if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
+ addAttributesFromFunctionProtoType(
+ getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
+ assert(!cir::MissingFeatures::opCallAttrs());
+ }
+
assert(!cir::MissingFeatures::opCallAttrs());
// 'const', 'pure' and 'noalias' attributed functions are also nounwind.
@@ -411,12 +437,11 @@ CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
return arrangeFreeFunctionType(funcTy.castAs<FunctionProtoType>());
}
-static cir::CIRCallOpInterface
-emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
- cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
- cir::FuncOp directFuncOp,
- const SmallVectorImpl<mlir::Value> &cirCallArgs,
- cir::SideEffect sideEffect) {
+static cir::CIRCallOpInterface emitCallLikeOp(
+ CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy,
+ mlir::Value indirectFuncVal, cir::FuncOp directFuncOp,
+ const SmallVectorImpl<mlir::Value> &cirCallArgs, cir::SideEffect sideEffect,
+ cir::ExtraFuncAttributesAttr extraFuncAttrs) {
CIRGenBuilderTy &builder = cgf.getBuilder();
assert(!cir::MissingFeatures::opCallSurroundingTry());
@@ -427,11 +452,13 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
if (indirectFuncTy) {
// TODO(cir): Set calling convention for indirect calls.
assert(!cir::MissingFeatures::opCallCallConv());
- return builder.createIndirectCallOp(
- callLoc, indirectFuncVal, indirectFuncTy, cirCallArgs, sideEffect);
+ return builder.createIndirectCallOp(callLoc, indirectFuncVal,
+ indirectFuncTy, cirCallArgs, sideEffect,
+ extraFuncAttrs);
}
- return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect);
+ return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect,
+ extraFuncAttrs);
}
const CIRGenFunctionInfo &
@@ -545,7 +572,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
assert(!cir::MissingFeatures::opCallCallConv());
assert(!cir::MissingFeatures::opCallAttrs());
cir::SideEffect sideEffect;
- cgm.constructAttributeList(callee.getAbstractInfo(), sideEffect);
+ cgm.constructAttributeList(callee.getAbstractInfo(), attrs, sideEffect);
assert(!cir::MissingFeatures::invokeOp());
@@ -566,12 +593,13 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
indirectFuncVal = calleePtr->getResult(0);
}
- assert(!cir::MissingFeatures::opCallAttrs());
+ auto extraFuncAttrs =
+ cir::ExtraFuncAttributesAttr::get(attrs.getDictionary(&getMLIRContext()));
mlir::Location callLoc = loc;
cir::CIRCallOpInterface theCall =
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
- cirCallArgs, sideEffect);
+ cirCallArgs, sideEffect, extraFuncAttrs);
if (callOp)
*callOp = theCall;
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h
index 56c76c51a46d8..bd113293fdafd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -33,7 +33,8 @@ class CIRGenCalleeInfo {
CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy,
clang::GlobalDecl calleeDecl)
: calleeProtoTy(calleeProtoTy), calleeDecl(calleeDecl) {}
- CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {}
+ CIRGenCalleeInfo(clang::GlobalDecl calleeDecl)
+ : calleeProtoTy(nullptr), calleeDecl(calleeDecl) {}
const clang::FunctionProtoType *getCalleeFunctionProtoType() const {
return calleeProtoTy;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 71806e3c5de21..c435c14c08f57 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -166,6 +166,7 @@ class CIRGenModule : public CIRGenTypeCache {
/// constructed for. If valid, the attributes applied to this decl may
/// contribute to the function attributes and calling convention.
void constructAttributeList(CIRGenCalleeInfo calleeInfo,
+ mlir::NamedAttrList &attrs,
cir::SideEffect &sideEffect);
/// Return a constant array for the given string.
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 16248059c4975..dadae709b3b7f 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -65,6 +65,11 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface {
os << (boolAttr.getValue() ? "true" : "false");
return AliasResult::FinalAlias;
}
+ if (auto extraFuncAttr =
+ mlir::dyn_cast<cir::ExtraFuncAttributesAttr>(attr)) {
+ os << "fn_attr";
+ return AliasResult::FinalAlias;
+ }
return AliasResult::NoAlias;
}
};
@@ -549,7 +554,8 @@ unsigned cir::CallOp::getNumArgOperands() {
}
static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
- mlir::OperationState &result) {
+ mlir::OperationState &result,
+ llvm::StringRef extraAttrsAttrName) {
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> ops;
llvm::SMLoc opsLoc;
mlir::FlatSymbolRefAttr calleeAttr;
@@ -586,6 +592,21 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
result.addAttribute("side_effect", attr);
}
+ Attribute extraAttrs;
+ if (mlir::succeeded(parser.parseOptionalKeyword("extra"))) {
+ if (parser.parseLParen().failed())
+ return failure();
+ if (parser.parseAttribute(extraAttrs).failed())
+ return failure();
+ if (parser.parseRParen().failed())
+ return failure();
+ } else {
+ NamedAttrList empty;
+ extraAttrs = cir::ExtraFuncAttributesAttr::get(
+ empty.getDictionary(parser.getContext()));
+ }
+ result.addAttribute(extraAttrsAttrName, extraAttrs);
+
if (parser.parseOptionalAttrDict(result.attributes))
return ::mlir::failure();
@@ -609,6 +630,7 @@ static void printCallCommon(mlir::Operation *op,
mlir::FlatSymbolRefAttr calleeSym,
mlir::Value indirectCallee,
mlir::OpAsmPrinter &printer,
+ cir::ExtraFuncAttributesAttr extraAttrs,
cir::SideEffect sideEffect) {
printer << ' ';
@@ -631,7 +653,14 @@ static void printCallCommon(mlir::Operation *op,
printer << ")";
}
- printer.printOptionalAttrDict(op->getAttrs(), {"callee", "side_effect"});
+ if (!extraAttrs.getElements().empty()) {
+ printer << " extra(";
+ printer.printAttributeWithoutType(extraAttrs);
+ printer << ")";
+ }
+
+ printer.printOptionalAttrDict(op->getAttrs(),
+ {"callee", "extra_attrs", "side_effect"});
printer << " : ";
printer.printFunctionalType(op->getOperands().getTypes(),
@@ -640,13 +669,14 @@ static void printCallCommon(mlir::Operation *op,
mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
mlir::OperationState &result) {
- return parseCallCommon(parser, result);
+ return parseCallCommon(parser, result, getExtraAttrsAttrName(result.name));
}
void cir::CallOp::print(mlir::OpAsmPrinter &p) {
mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;
cir::SideEffect sideEffect = getSideEffect();
- printCallCommon(*this, getCalleeAttr(), indirectCallee, p, sideEffect);
+ printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getExtraAttrs(),
+ sideEffect);
}
static LogicalResult
diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp
index cc25afce1e5a4..0941655df2aab 100644
--- a/clang/test/CIR/CodeGen/call.cpp
+++ b/clang/test/CIR/CodeGen/call.cpp
@@ -3,6 +3,8 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// CIR: #[[FN_ATTR:.+]] = #cir<extra({nothrow = #cir.nothrow})>
+
void f1() {}
void f2() {
f1();
@@ -102,3 +104,16 @@ void f12() {
// LLVM: %[[#slot:]] = alloca %struct.S, i64 1, align 4
// LLVM-NEXT: %[[#ret:]] = call %struct.S @_Z3f10v()
// LLVM-NEXT: store %struct.S %[[#ret]], ptr %[[#slot]], align 4
+
+void f13() noexcept;
+void f14() {
+ f13();
+}
+
+// CIR-LABEL: cir.func @_Z3f14v()
+// CIR: cir.call @_Z3f13v() extra(#[[FN_ATTR]]) : () -> ()
+// CIR: }
+
+// LLVM-LABEL: define void @_Z3f14v()
+// LLVM: call void @_Z3f13v()
+// LLVM: }
``````````
</details>
https://github.com/llvm/llvm-project/pull/145178
More information about the cfe-commits
mailing list