[clang] 23104a7 - [CIR] Add nothrow attribute to the call operation (#145178)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 3 07:54:18 PDT 2025
Author: Sirui Mu
Date: 2025-07-03T22:54:15+08:00
New Revision: 23104a74e79f208d467830058111fd883dfcb489
URL: https://github.com/llvm/llvm-project/commit/23104a74e79f208d467830058111fd883dfcb489
DIFF: https://github.com/llvm/llvm-project/commit/23104a74e79f208d467830058111fd883dfcb489.diff
LOG: [CIR] Add nothrow attribute to the call operation (#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.
Added:
Modified:
clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
clang/include/clang/CIR/Dialect/IR/CIRDialect.td
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
clang/lib/CIR/CodeGen/CIRGenCall.cpp
clang/lib/CIR/CodeGen/CIRGenCall.h
clang/lib/CIR/CodeGen/CIRGenModule.h
clang/lib/CIR/Dialect/IR/CIRDialect.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
clang/test/CIR/CodeGen/builtin_call.cpp
clang/test/CIR/CodeGen/builtin_printf.cpp
clang/test/CIR/CodeGen/call.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 41ac8c1c875df..277c278fd38b7 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -228,25 +228,28 @@ 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);
+ llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
+ auto op = create<cir::CallOp>(loc, callee, returnType, operands);
+ op->setAttrs(attrs);
+ return op;
}
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
mlir::ValueRange operands,
- cir::SideEffect sideEffect = cir::SideEffect::All) {
+ llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
callee.getFunctionType().getReturnType(), operands,
- sideEffect);
+ attrs);
}
- 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,
+ llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
+ llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
+ resOperands.append(operands.begin(), operands.end());
+ return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
+ resOperands, attrs);
}
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index d77ed53aa93a1..fa73e5bf41f23 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -37,6 +37,9 @@ def CIR_Dialect : Dialect {
let extraClassDeclaration = [{
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
+ static llvm::StringRef getCalleeAttrName() { return "callee"; }
+ static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
+ static llvm::StringRef getSideEffectAttrName() { return "side_effect"; }
void registerAttributes();
void registerTypes();
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 187e04bc25f24..7e0f3dba6fbe0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1991,6 +1991,7 @@ class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []>
dag commonArgs = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
Variadic<CIR_AnyType>:$args,
+ UnitAttr:$nothrow,
DefaultValuedAttr<CIR_SideEffect, "SideEffect::All">:$side_effect);
}
@@ -2020,29 +2021,14 @@ 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");
+ "mlir::ValueRange":$operands), [{
$_state.addOperands(operands);
- $_state.addAttribute("callee", callee);
- $_state.addAttribute("side_effect",
- SideEffectAttr::get($_builder.getContext(), sideEffect));
+ if (callee)
+ $_state.addAttribute("callee", callee);
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/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index 5817b91b49e31..4702b4ef08acc 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -34,6 +34,8 @@ let cppNamespace = "::cir" in {
"Return the number of operands, accounts for indirect call or "
"exception info",
"unsigned", "getNumArgOperands", (ins)>,
+ InterfaceMethod<"Return whether the callee is nothrow",
+ "bool", "getNothrow", (ins)>,
InterfaceMethod<"Return the side effects of the call operation",
"cir::SideEffect", "getSideEffect", (ins)>,
];
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 163d0dbfec3dc..938d1436a76ea 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -77,17 +77,40 @@ 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())
+ attrs.set(cir::CIRDialect::getNoThrowAttrName(),
+ mlir::UnitAttr::get(builder.getContext()));
+}
+
/// Construct the CIR attribute list of a function or call.
void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
- cir::SideEffect &sideEffect) {
+ mlir::NamedAttrList &attrs) {
assert(!cir::MissingFeatures::opCallCallConv());
- sideEffect = cir::SideEffect::All;
+ auto 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>())
+ attrs.set(cir::CIRDialect::getNoThrowAttrName(),
+ mlir::UnitAttr::get(&getMLIRContext()));
+
+ 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.
@@ -104,6 +127,9 @@ void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
}
assert(!cir::MissingFeatures::opCallAttrs());
+
+ attrs.set(cir::CIRDialect::getSideEffectAttrName(),
+ cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
}
/// Returns the canonical formal type of the given C++ method.
@@ -416,7 +442,7 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
cir::FuncOp directFuncOp,
const SmallVectorImpl<mlir::Value> &cirCallArgs,
- cir::SideEffect sideEffect) {
+ const mlir::NamedAttrList &attrs) {
CIRGenBuilderTy &builder = cgf.getBuilder();
assert(!cir::MissingFeatures::opCallSurroundingTry());
@@ -424,14 +450,17 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
assert(builder.getInsertionBlock() && "expected valid basic block");
+ cir::CallOp op;
if (indirectFuncTy) {
// TODO(cir): Set calling convention for indirect calls.
assert(!cir::MissingFeatures::opCallCallConv());
- return builder.createIndirectCallOp(
- callLoc, indirectFuncVal, indirectFuncTy, cirCallArgs, sideEffect);
+ op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,
+ cirCallArgs, attrs);
+ } else {
+ op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs);
}
- return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect);
+ return op;
}
const CIRGenFunctionInfo &
@@ -544,8 +573,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);
assert(!cir::MissingFeatures::invokeOp());
@@ -566,12 +594,10 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
indirectFuncVal = calleePtr->getResult(0);
}
- assert(!cir::MissingFeatures::opCallAttrs());
-
mlir::Location callLoc = loc;
cir::CIRCallOpInterface theCall =
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
- cirCallArgs, sideEffect);
+ cirCallArgs, attrs);
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 5a1eb9dea35c6..16922b115027e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -166,7 +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,
- cir::SideEffect &sideEffect);
+ mlir::NamedAttrList &attrs);
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 2a54906703011..8512b229c2663 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -597,7 +597,9 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
llvm::ArrayRef<mlir::Type> allResultTypes;
// If we cannot parse a string callee, it means this is an indirect call.
- if (!parser.parseOptionalAttribute(calleeAttr, "callee", result.attributes)
+ if (!parser
+ .parseOptionalAttribute(calleeAttr, CIRDialect::getCalleeAttrName(),
+ result.attributes)
.has_value()) {
OpAsmParser::UnresolvedOperand indirectVal;
// Do not resolve right now, since we need to figure out the type
@@ -615,6 +617,10 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.parseRParen())
return mlir::failure();
+ if (parser.parseOptionalKeyword("nothrow").succeeded())
+ result.addAttribute(CIRDialect::getNoThrowAttrName(),
+ mlir::UnitAttr::get(parser.getContext()));
+
if (parser.parseOptionalKeyword("side_effect").succeeded()) {
if (parser.parseLParen().failed())
return failure();
@@ -624,7 +630,7 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.parseRParen().failed())
return failure();
auto attr = cir::SideEffectAttr::get(parser.getContext(), sideEffect);
- result.addAttribute("side_effect", attr);
+ result.addAttribute(CIRDialect::getSideEffectAttrName(), attr);
}
if (parser.parseOptionalAttrDict(result.attributes))
@@ -649,7 +655,7 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
static void printCallCommon(mlir::Operation *op,
mlir::FlatSymbolRefAttr calleeSym,
mlir::Value indirectCallee,
- mlir::OpAsmPrinter &printer,
+ mlir::OpAsmPrinter &printer, bool isNothrow,
cir::SideEffect sideEffect) {
printer << ' ';
@@ -666,13 +672,19 @@ static void printCallCommon(mlir::Operation *op,
}
printer << "(" << ops << ")";
+ if (isNothrow)
+ printer << " nothrow";
+
if (sideEffect != cir::SideEffect::All) {
printer << " side_effect(";
printer << stringifySideEffect(sideEffect);
printer << ")";
}
- printer.printOptionalAttrDict(op->getAttrs(), {"callee", "side_effect"});
+ printer.printOptionalAttrDict(op->getAttrs(),
+ {CIRDialect::getCalleeAttrName(),
+ CIRDialect::getNoThrowAttrName(),
+ CIRDialect::getSideEffectAttrName()});
printer << " : ";
printer.printFunctionalType(op->getOperands().getTypes(),
@@ -687,13 +699,15 @@ mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
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, getNothrow(),
+ sideEffect);
}
static LogicalResult
verifyCallCommInSymbolUses(mlir::Operation *op,
SymbolTableCollection &symbolTable) {
- auto fnAttr = op->getAttrOfType<FlatSymbolRefAttr>("callee");
+ auto fnAttr =
+ op->getAttrOfType<FlatSymbolRefAttr>(CIRDialect::getCalleeAttrName());
if (!fnAttr) {
// This is an indirect call, thus we don't have to check the symbol uses.
return mlir::success();
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 891017e1d8256..b24e2ee2de86f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -232,7 +232,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
return value;
}
-void convertSideEffectForCall(mlir::Operation *callOp,
+void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
cir::SideEffect sideEffect,
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
bool &noUnwind, bool &willReturn) {
@@ -241,7 +241,7 @@ void convertSideEffectForCall(mlir::Operation *callOp,
switch (sideEffect) {
case cir::SideEffect::All:
memoryEffect = {};
- noUnwind = false;
+ noUnwind = isNothrow;
willReturn = false;
break;
@@ -800,8 +800,8 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
mlir::LLVM::MemoryEffectsAttr memoryEffects;
bool noUnwind = false;
bool willReturn = false;
- convertSideEffectForCall(op, call.getSideEffect(), memoryEffects, noUnwind,
- willReturn);
+ convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),
+ memoryEffects, noUnwind, willReturn);
mlir::LLVM::LLVMFunctionType llvmFnTy;
if (calleeAttr) { // direct call
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 1c3622172f836..de4600f376e55 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -29,7 +29,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr,
mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
-void convertSideEffectForCall(mlir::Operation *callOp,
+void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
cir::SideEffect sideEffect,
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
bool &noUnwind, bool &willReturn);
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp
index b956f2580593e..ad0e478040836 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -84,8 +84,8 @@ void library_builtins() {
// CIR: cir.func{{.*}} @_Z16library_builtinsv() {
// CIR: %[[NULL:.+]] = cir.const #cir.ptr<null> : !cir.ptr<!s8i>
-// CIR: cir.call @printf(%[[NULL]]) : (!cir.ptr<!s8i>) -> !s32i
-// CIR: cir.call @abort() : () -> ()
+// CIR: cir.call @printf(%[[NULL]]) nothrow : (!cir.ptr<!s8i>) -> !s32i
+// CIR: cir.call @abort() nothrow : () -> ()
// LLVM: define{{.*}} void @_Z16library_builtinsv()
// LLVM: call i32 (ptr, ...) @printf(ptr null)
diff --git a/clang/test/CIR/CodeGen/builtin_printf.cpp b/clang/test/CIR/CodeGen/builtin_printf.cpp
index d12f822d43ebf..43128e44b19e4 100644
--- a/clang/test/CIR/CodeGen/builtin_printf.cpp
+++ b/clang/test/CIR/CodeGen/builtin_printf.cpp
@@ -26,16 +26,16 @@ void func(char const * const str, int i) {
// CIR: cir.store %[[arg0]], %[[str_ptr]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
// CIR: cir.store %[[arg1]], %[[i_ptr]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[null_ptr:.+]] = cir.const #cir.ptr<null> : !cir.ptr<!s8i>
-// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) : (!cir.ptr<!s8i>) -> !s32i
+// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) nothrow : (!cir.ptr<!s8i>) -> !s32i
// CIR: %[[str_fmt_global:.+]] = cir.get_global @".str" : !cir.ptr<!cir.array<!s8i x 3>>
// CIR: %[[str_fmt_ptr:.+]] = cir.cast(array_to_ptrdecay, %[[str_fmt_global]] : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
// CIR: %[[str_val:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!s8i>
-// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) : (!cir.ptr<!s8i>, !cir.ptr<!s8i>) -> !s32i
+// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) nothrow : (!cir.ptr<!s8i>, !cir.ptr<!s8i>) -> !s32i
// CIR: %[[full_fmt_global:.+]] = cir.get_global @".str.1" : !cir.ptr<!cir.array<!s8i x 7>>
// CIR: %[[full_fmt_ptr:.+]] = cir.cast(array_to_ptrdecay, %[[full_fmt_global]] : !cir.ptr<!cir.array<!s8i x 7>>), !cir.ptr<!s8i>
// CIR: %[[str_val2:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!s8i>
// CIR: %[[i_val:.+]] = cir.load{{.*}} %[[i_ptr]] : !cir.ptr<!s32i>, !s32i
-// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) : (!cir.ptr<!s8i>, !cir.ptr<!s8i>, !s32i) -> !s32i
+// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) nothrow : (!cir.ptr<!s8i>, !cir.ptr<!s8i>, !s32i) -> !s32i
// CIR: cir.return
// LLVM: define{{.*}} void @_Z4funcPKci(ptr %[[arg0:.+]], i32 %[[arg1:.+]])
diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp
index f7653ed7a572b..43e5d150a949f 100644
--- a/clang/test/CIR/CodeGen/call.cpp
+++ b/clang/test/CIR/CodeGen/call.cpp
@@ -102,3 +102,18 @@ 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() nothrow : () -> ()
+// CIR: }
+
+// LLVM-LABEL: define{{.+}} void @_Z3f14v()
+// LLVM: call void @_Z3f13v() #[[LLVM_ATTR_0:.+]]
+// LLVM: }
+
+// LLLVM: attributes #[[LLVM_ATTR_0]] = { nounwind }
More information about the cfe-commits
mailing list