Skip to content

Commit ce5ccf3

Browse files
committed
[CIR] Add nothrow attribute to call operations
This patch adds nothrow attribute to call operations to indicate the callee will not throw. This patch also contains a minor refactor. The construction of call operations is now split into two steps. The CallOp::build function and the create function in CIR builder now only accepts basic parameters including the callee and the arguments. Other extra arguments, including any additional attributes, are set later on the constructed op in a separate step.
1 parent 651c994 commit ce5ccf3

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)