Skip to content

Commit 23104a7

Browse files
authored
[CIR] Add nothrow attribute to the call operation (llvm#145178)
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.
1 parent 3ba161b commit 23104a7

File tree

13 files changed

+110
-60
lines changed

13 files changed

+110
-60
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -228,25 +228,28 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
228228

229229
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
230230
mlir::Type returnType, mlir::ValueRange operands,
231-
cir::SideEffect sideEffect = cir::SideEffect::All) {
232-
return create<cir::CallOp>(loc, callee, returnType, operands, sideEffect);
231+
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
232+
auto op = create<cir::CallOp>(loc, callee, returnType, operands);
233+
op->setAttrs(attrs);
234+
return op;
233235
}
234236

235237
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
236238
mlir::ValueRange operands,
237-
cir::SideEffect sideEffect = cir::SideEffect::All) {
239+
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
238240
return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
239241
callee.getFunctionType().getReturnType(), operands,
240-
sideEffect);
242+
attrs);
241243
}
242244

243-
cir::CallOp createIndirectCallOp(mlir::Location loc,
244-
mlir::Value indirectTarget,
245-
cir::FuncType funcType,
246-
mlir::ValueRange operands,
247-
cir::SideEffect sideEffect) {
248-
return create<cir::CallOp>(loc, indirectTarget, funcType.getReturnType(),
249-
operands, sideEffect);
245+
cir::CallOp
246+
createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget,
247+
cir::FuncType funcType, mlir::ValueRange operands,
248+
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
249+
llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
250+
resOperands.append(operands.begin(), operands.end());
251+
return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
252+
resOperands, attrs);
250253
}
251254

252255
//===--------------------------------------------------------------------===//

clang/include/clang/CIR/Dialect/IR/CIRDialect.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def CIR_Dialect : Dialect {
3737
let extraClassDeclaration = [{
3838
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
3939
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
40+
static llvm::StringRef getCalleeAttrName() { return "callee"; }
41+
static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
42+
static llvm::StringRef getSideEffectAttrName() { return "side_effect"; }
4043

4144
void registerAttributes();
4245
void registerTypes();

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,7 @@ class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []>
19911991

19921992
dag commonArgs = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
19931993
Variadic<CIR_AnyType>:$args,
1994+
UnitAttr:$nothrow,
19941995
DefaultValuedAttr<CIR_SideEffect, "SideEffect::All">:$side_effect);
19951996
}
19961997

@@ -2020,29 +2021,14 @@ def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
20202021
let arguments = commonArgs;
20212022

20222023
let builders = [
2023-
// Build a call op for a direct call
20242024
OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
2025-
"mlir::ValueRange":$operands,
2026-
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
2027-
assert(callee && "callee attribute is required for direct call");
2025+
"mlir::ValueRange":$operands), [{
20282026
$_state.addOperands(operands);
2029-
$_state.addAttribute("callee", callee);
2030-
$_state.addAttribute("side_effect",
2031-
SideEffectAttr::get($_builder.getContext(), sideEffect));
2027+
if (callee)
2028+
$_state.addAttribute("callee", callee);
20322029
if (resType && !isa<VoidType>(resType))
20332030
$_state.addTypes(resType);
2034-
}]>,
2035-
// Build a call op for an indirect call
2036-
OpBuilder<(ins "mlir::Value":$calleePtr, "mlir::Type":$resType,
2037-
"mlir::ValueRange":$operands,
2038-
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
2039-
$_state.addOperands(calleePtr);
2040-
$_state.addOperands(operands);
2041-
if (resType && !isa<VoidType>(resType))
2042-
$_state.addTypes(resType);
2043-
$_state.addAttribute("side_effect",
2044-
SideEffectAttr::get($_builder.getContext(), sideEffect));
2045-
}]>,
2031+
}]>
20462032
];
20472033
}
20482034

clang/include/clang/CIR/Interfaces/CIROpInterfaces.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ let cppNamespace = "::cir" in {
3434
"Return the number of operands, accounts for indirect call or "
3535
"exception info",
3636
"unsigned", "getNumArgOperands", (ins)>,
37+
InterfaceMethod<"Return whether the callee is nothrow",
38+
"bool", "getNothrow", (ins)>,
3739
InterfaceMethod<"Return the side effects of the call operation",
3840
"cir::SideEffect", "getSideEffect", (ins)>,
3941
];

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,40 @@ void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {
7777
builder.createStore(*currSrcLoc, value, dest);
7878
}
7979

80+
static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder,
81+
mlir::NamedAttrList &attrs,
82+
const FunctionProtoType *fpt) {
83+
if (!fpt)
84+
return;
85+
86+
if (!isUnresolvedExceptionSpec(fpt->getExceptionSpecType()) &&
87+
fpt->isNothrow())
88+
attrs.set(cir::CIRDialect::getNoThrowAttrName(),
89+
mlir::UnitAttr::get(builder.getContext()));
90+
}
91+
8092
/// Construct the CIR attribute list of a function or call.
8193
void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
82-
cir::SideEffect &sideEffect) {
94+
mlir::NamedAttrList &attrs) {
8395
assert(!cir::MissingFeatures::opCallCallConv());
84-
sideEffect = cir::SideEffect::All;
96+
auto sideEffect = cir::SideEffect::All;
8597

86-
assert(!cir::MissingFeatures::opCallAttrs());
98+
addAttributesFromFunctionProtoType(getBuilder(), attrs,
99+
calleeInfo.getCalleeFunctionProtoType());
87100

88101
const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
89102

90103
if (targetDecl) {
104+
if (targetDecl->hasAttr<NoThrowAttr>())
105+
attrs.set(cir::CIRDialect::getNoThrowAttrName(),
106+
mlir::UnitAttr::get(&getMLIRContext()));
107+
108+
if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
109+
addAttributesFromFunctionProtoType(
110+
getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
111+
assert(!cir::MissingFeatures::opCallAttrs());
112+
}
113+
91114
assert(!cir::MissingFeatures::opCallAttrs());
92115

93116
// 'const', 'pure' and 'noalias' attributed functions are also nounwind.
@@ -104,6 +127,9 @@ void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
104127
}
105128

106129
assert(!cir::MissingFeatures::opCallAttrs());
130+
131+
attrs.set(cir::CIRDialect::getSideEffectAttrName(),
132+
cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
107133
}
108134

109135
/// Returns the canonical formal type of the given C++ method.
@@ -416,22 +442,25 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
416442
cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
417443
cir::FuncOp directFuncOp,
418444
const SmallVectorImpl<mlir::Value> &cirCallArgs,
419-
cir::SideEffect sideEffect) {
445+
const mlir::NamedAttrList &attrs) {
420446
CIRGenBuilderTy &builder = cgf.getBuilder();
421447

422448
assert(!cir::MissingFeatures::opCallSurroundingTry());
423449
assert(!cir::MissingFeatures::invokeOp());
424450

425451
assert(builder.getInsertionBlock() && "expected valid basic block");
426452

453+
cir::CallOp op;
427454
if (indirectFuncTy) {
428455
// TODO(cir): Set calling convention for indirect calls.
429456
assert(!cir::MissingFeatures::opCallCallConv());
430-
return builder.createIndirectCallOp(
431-
callLoc, indirectFuncVal, indirectFuncTy, cirCallArgs, sideEffect);
457+
op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,
458+
cirCallArgs, attrs);
459+
} else {
460+
op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs);
432461
}
433462

434-
return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect);
463+
return op;
435464
}
436465

437466
const CIRGenFunctionInfo &
@@ -544,8 +573,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
544573

545574
assert(!cir::MissingFeatures::opCallCallConv());
546575
assert(!cir::MissingFeatures::opCallAttrs());
547-
cir::SideEffect sideEffect;
548-
cgm.constructAttributeList(callee.getAbstractInfo(), sideEffect);
576+
cgm.constructAttributeList(callee.getAbstractInfo(), attrs);
549577

550578
assert(!cir::MissingFeatures::invokeOp());
551579

@@ -566,12 +594,10 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
566594
indirectFuncVal = calleePtr->getResult(0);
567595
}
568596

569-
assert(!cir::MissingFeatures::opCallAttrs());
570-
571597
mlir::Location callLoc = loc;
572598
cir::CIRCallOpInterface theCall =
573599
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
574-
cirCallArgs, sideEffect);
600+
cirCallArgs, attrs);
575601

576602
if (callOp)
577603
*callOp = theCall;

clang/lib/CIR/CodeGen/CIRGenCall.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class CIRGenCalleeInfo {
3333
CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy,
3434
clang::GlobalDecl calleeDecl)
3535
: calleeProtoTy(calleeProtoTy), calleeDecl(calleeDecl) {}
36-
CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {}
36+
CIRGenCalleeInfo(clang::GlobalDecl calleeDecl)
37+
: calleeProtoTy(nullptr), calleeDecl(calleeDecl) {}
3738

3839
const clang::FunctionProtoType *getCalleeFunctionProtoType() const {
3940
return calleeProtoTy;

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class CIRGenModule : public CIRGenTypeCache {
166166
/// constructed for. If valid, the attributes applied to this decl may
167167
/// contribute to the function attributes and calling convention.
168168
void constructAttributeList(CIRGenCalleeInfo calleeInfo,
169-
cir::SideEffect &sideEffect);
169+
mlir::NamedAttrList &attrs);
170170

171171
/// Return a constant array for the given string.
172172
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,9 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
597597
llvm::ArrayRef<mlir::Type> allResultTypes;
598598

599599
// If we cannot parse a string callee, it means this is an indirect call.
600-
if (!parser.parseOptionalAttribute(calleeAttr, "callee", result.attributes)
600+
if (!parser
601+
.parseOptionalAttribute(calleeAttr, CIRDialect::getCalleeAttrName(),
602+
result.attributes)
601603
.has_value()) {
602604
OpAsmParser::UnresolvedOperand indirectVal;
603605
// Do not resolve right now, since we need to figure out the type
@@ -615,6 +617,10 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
615617
if (parser.parseRParen())
616618
return mlir::failure();
617619

620+
if (parser.parseOptionalKeyword("nothrow").succeeded())
621+
result.addAttribute(CIRDialect::getNoThrowAttrName(),
622+
mlir::UnitAttr::get(parser.getContext()));
623+
618624
if (parser.parseOptionalKeyword("side_effect").succeeded()) {
619625
if (parser.parseLParen().failed())
620626
return failure();
@@ -624,7 +630,7 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
624630
if (parser.parseRParen().failed())
625631
return failure();
626632
auto attr = cir::SideEffectAttr::get(parser.getContext(), sideEffect);
627-
result.addAttribute("side_effect", attr);
633+
result.addAttribute(CIRDialect::getSideEffectAttrName(), attr);
628634
}
629635

630636
if (parser.parseOptionalAttrDict(result.attributes))
@@ -649,7 +655,7 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
649655
static void printCallCommon(mlir::Operation *op,
650656
mlir::FlatSymbolRefAttr calleeSym,
651657
mlir::Value indirectCallee,
652-
mlir::OpAsmPrinter &printer,
658+
mlir::OpAsmPrinter &printer, bool isNothrow,
653659
cir::SideEffect sideEffect) {
654660
printer << ' ';
655661

@@ -666,13 +672,19 @@ static void printCallCommon(mlir::Operation *op,
666672
}
667673
printer << "(" << ops << ")";
668674

675+
if (isNothrow)
676+
printer << " nothrow";
677+
669678
if (sideEffect != cir::SideEffect::All) {
670679
printer << " side_effect(";
671680
printer << stringifySideEffect(sideEffect);
672681
printer << ")";
673682
}
674683

675-
printer.printOptionalAttrDict(op->getAttrs(), {"callee", "side_effect"});
684+
printer.printOptionalAttrDict(op->getAttrs(),
685+
{CIRDialect::getCalleeAttrName(),
686+
CIRDialect::getNoThrowAttrName(),
687+
CIRDialect::getSideEffectAttrName()});
676688

677689
printer << " : ";
678690
printer.printFunctionalType(op->getOperands().getTypes(),
@@ -687,13 +699,15 @@ mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
687699
void cir::CallOp::print(mlir::OpAsmPrinter &p) {
688700
mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;
689701
cir::SideEffect sideEffect = getSideEffect();
690-
printCallCommon(*this, getCalleeAttr(), indirectCallee, p, sideEffect);
702+
printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getNothrow(),
703+
sideEffect);
691704
}
692705

693706
static LogicalResult
694707
verifyCallCommInSymbolUses(mlir::Operation *op,
695708
SymbolTableCollection &symbolTable) {
696-
auto fnAttr = op->getAttrOfType<FlatSymbolRefAttr>("callee");
709+
auto fnAttr =
710+
op->getAttrOfType<FlatSymbolRefAttr>(CIRDialect::getCalleeAttrName());
697711
if (!fnAttr) {
698712
// This is an indirect call, thus we don't have to check the symbol uses.
699713
return mlir::success();

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
232232
return value;
233233
}
234234

235-
void convertSideEffectForCall(mlir::Operation *callOp,
235+
void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
236236
cir::SideEffect sideEffect,
237237
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
238238
bool &noUnwind, bool &willReturn) {
@@ -241,7 +241,7 @@ void convertSideEffectForCall(mlir::Operation *callOp,
241241
switch (sideEffect) {
242242
case cir::SideEffect::All:
243243
memoryEffect = {};
244-
noUnwind = false;
244+
noUnwind = isNothrow;
245245
willReturn = false;
246246
break;
247247

@@ -800,8 +800,8 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
800800
mlir::LLVM::MemoryEffectsAttr memoryEffects;
801801
bool noUnwind = false;
802802
bool willReturn = false;
803-
convertSideEffectForCall(op, call.getSideEffect(), memoryEffects, noUnwind,
804-
willReturn);
803+
convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),
804+
memoryEffects, noUnwind, willReturn);
805805

806806
mlir::LLVM::LLVMFunctionType llvmFnTy;
807807
if (calleeAttr) { // direct call

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr,
2929

3030
mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
3131

32-
void convertSideEffectForCall(mlir::Operation *callOp,
32+
void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
3333
cir::SideEffect sideEffect,
3434
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
3535
bool &noUnwind, bool &willReturn);

0 commit comments

Comments
 (0)