From 3ec2afd9b109fdb7493a7708a4c70f65ab2178e2 Mon Sep 17 00:00:00 2001 From: roro47 <40341016+roro47@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:39:54 +0100 Subject: [PATCH] [CIR] Add FuncAttrs to cir.calls (#637) Some function attributes are also callsite attributes, for instance, nothrow. This means they are going to show up in both. We don't support that just yet, hence the PR. CIR has an attribute `ExtraFuncAttr` that we current use as part of `FuncOp`, see CIROps.td. This attribute also needs to be added to `CallOp` and `TryCalOp`. Right now, In `CIRGenCall.cpp: AddAttributesFromFunctionProtoType` fills in `FuncAttrs`, but doesn't use it for anything. We should use the `FuncAttrs` result to populate constructing a `ExtraFuncAttr` and add it to the aforementioned call operations. --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 51 +++++++++++++++++++ clang/include/clang/CIR/Dialect/IR/CIROps.td | 25 ++++----- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 32 +++++++----- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 13 +++-- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 4 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 39 ++++++++++++-- .../Dialect/Transforms/LoweringPrepare.cpp | 25 +++++---- .../TargetLowering/LowerFunction.cpp | 5 +- .../Targets/LoweringPrepareItaniumCXXABI.cpp | 6 +-- clang/test/CIR/CodeGen/call-extra-attrs.cpp | 34 +++++++++++++ 10 files changed, 174 insertions(+), 60 deletions(-) create mode 100644 clang/test/CIR/CodeGen/call-extra-attrs.cpp diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 9420b24e42e0..cb7bb85617f5 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -415,6 +415,57 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { mlir::ValueRange value = {}) { return create(loc, value); } + + mlir::cir::CallOp + createCallOp(mlir::Location loc, + mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(), + mlir::Type returnType = mlir::cir::VoidType(), + mlir::ValueRange operands = mlir::ValueRange(), + mlir::cir::ExtraFuncAttributesAttr extraFnAttr = {}) { + + mlir::cir::CallOp callOp = + create(loc, callee, returnType, operands); + + if (extraFnAttr) { + callOp->setAttr("extra_attrs", extraFnAttr); + } else { + mlir::NamedAttrList empty; + callOp->setAttr("extra_attrs", + mlir::cir::ExtraFuncAttributesAttr::get( + getContext(), empty.getDictionary(getContext()))); + } + return callOp; + } + + mlir::cir::CallOp + createCallOp(mlir::Location loc, mlir::cir::FuncOp callee, + mlir::ValueRange operands = mlir::ValueRange(), + mlir::cir::ExtraFuncAttributesAttr extraFnAttr = {}) { + return createCallOp(loc, mlir::SymbolRefAttr::get(callee), + callee.getFunctionType().getReturnType(), operands, + extraFnAttr); + } + + mlir::cir::CallOp + createIndirectCallOp(mlir::Location loc, mlir::Value ind_target, + mlir::cir::FuncType fn_type, + mlir::ValueRange operands = mlir::ValueRange(), + mlir::cir::ExtraFuncAttributesAttr extraFnAttr = {}) { + + llvm::SmallVector resOperands({ind_target}); + resOperands.append(operands.begin(), operands.end()); + + return createCallOp(loc, mlir::SymbolRefAttr(), fn_type.getReturnType(), + resOperands, extraFnAttr); + } + + mlir::cir::CallOp + createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, + mlir::ValueRange operands = mlir::ValueRange(), + mlir::cir::ExtraFuncAttributesAttr extraFnAttr = {}) { + return createCallOp(loc, callee, mlir::cir::VoidType(), operands, + extraFnAttr); + } }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c7b3c673c545..89fb5e2e65e3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2787,6 +2787,7 @@ class CIR_CallOp extra_traits = []> : dag commonArgs = (ins OptionalAttr:$callee, Variadic:$arg_ops, + ExtraFuncAttr:$extra_attrs, OptionalAttr:$ast ); } @@ -2822,12 +2823,16 @@ def CallOp : CIR_CallOp<"call"> { let arguments = commonArgs; let results = (outs Optional:$result); + let skipDefaultBuilders = 1; + let builders = [ - OpBuilder<(ins "FuncOp":$callee, CArg<"ValueRange", "{}">:$operands), [{ + OpBuilder<(ins "SymbolRefAttr":$callee, "mlir::Type":$resType, + CArg<"ValueRange", "{}">:$operands), [{ $_state.addOperands(operands); - $_state.addAttribute("callee", SymbolRefAttr::get(callee)); - if (!callee.getFunctionType().isVoid()) - $_state.addTypes(callee.getFunctionType().getReturnType()); + if (callee) + $_state.addAttribute("callee", callee); + if (resType && !resType.isa()) + $_state.addTypes(resType); }]>, OpBuilder<(ins "Value":$ind_target, "FuncType":$fn_type, @@ -2836,18 +2841,6 @@ def CallOp : CIR_CallOp<"call"> { $_state.addOperands(operands); if (!fn_type.isVoid()) $_state.addTypes(fn_type.getReturnType()); - }]>, - OpBuilder<(ins "SymbolRefAttr":$callee, "mlir::Type":$resType, - CArg<"ValueRange", "{}">:$operands), [{ - $_state.addOperands(operands); - $_state.addAttribute("callee", callee); - if (resType && !resType.isa()) - $_state.addTypes(resType); - }]>, - OpBuilder<(ins "SymbolRefAttr":$callee, - CArg<"ValueRange", "{}">:$operands), [{ - $_state.addOperands(operands); - $_state.addAttribute("callee", callee); }]> ]; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 60268b72d9dd..bf44ddb263b7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -447,22 +447,29 @@ static mlir::cir::CIRCallOpInterface buildCallLikeOp(CIRGenFunction &CGF, mlir::Location callLoc, mlir::cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, mlir::cir::FuncOp directFuncOp, - SmallVectorImpl &CIRCallArgs, bool InvokeDest) { + SmallVectorImpl &CIRCallArgs, bool InvokeDest, + mlir::cir::ExtraFuncAttributesAttr extraFnAttrs) { auto &builder = CGF.getBuilder(); if (InvokeDest) { auto addr = CGF.currLexScope->getExceptionInfo().addr; - if (indirectFuncTy) - return builder.create( + + mlir::cir::TryCallOp tryCallOp; + if (indirectFuncTy) { + tryCallOp = builder.create( callLoc, addr, indirectFuncVal, indirectFuncTy, CIRCallArgs); - return builder.create(callLoc, directFuncOp, addr, - CIRCallArgs); + } else { + tryCallOp = builder.create(callLoc, directFuncOp, + addr, CIRCallArgs); + } + tryCallOp->setAttr("extra_attrs", extraFnAttrs); + return tryCallOp; } if (indirectFuncTy) - return builder.create(callLoc, indirectFuncVal, - indirectFuncTy, CIRCallArgs); - return builder.create(callLoc, directFuncOp, CIRCallArgs); + return builder.createIndirectCallOp( + callLoc, indirectFuncVal, indirectFuncTy, CIRCallArgs, extraFnAttrs); + return builder.createCallOp(callLoc, directFuncOp, CIRCallArgs, extraFnAttrs); } RValue CIRGenFunction::buildCall(const CIRGenFunctionInfo &CallInfo, @@ -735,9 +742,10 @@ RValue CIRGenFunction::buildCall(const CIRGenFunctionInfo &CallInfo, indirectFuncVal = CalleePtr->getResult(0); } - mlir::cir::CIRCallOpInterface callLikeOp = - buildCallLikeOp(*this, callLoc, indirectFuncTy, indirectFuncVal, - directFuncOp, CIRCallArgs, InvokeDest); + mlir::cir::CIRCallOpInterface callLikeOp = buildCallLikeOp( + *this, callLoc, indirectFuncTy, indirectFuncVal, directFuncOp, + CIRCallArgs, InvokeDest, + mlir::cir::ExtraFuncAttributesAttr::get(builder.getContext(), Attrs)); if (E) callLikeOp->setAttr( @@ -844,7 +852,7 @@ mlir::Value CIRGenFunction::buildRuntimeCall(mlir::Location loc, // TODO(cir): set the calling convention to this runtime call. assert(!MissingFeatures::setCallingConv()); - auto call = builder.create(loc, callee, args); + auto call = builder.createCallOp(loc, callee, args); assert(call->getNumResults() <= 1 && "runtime functions have at most 1 result"); diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 560335765ef6..362f1ee5fcb3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -179,10 +179,9 @@ mlir::cir::CallOp CIRGenFunction::buildCoroIDBuiltinCall(mlir::Location loc, } else fnOp = cast(builtin); - return builder.create( - loc, fnOp, - mlir::ValueRange{builder.getUInt32(NewAlign, loc), nullPtr, nullPtr, - nullPtr}); + return builder.createCallOp(loc, fnOp, + mlir::ValueRange{builder.getUInt32(NewAlign, loc), + nullPtr, nullPtr, nullPtr}); } mlir::cir::CallOp @@ -202,7 +201,7 @@ CIRGenFunction::buildCoroAllocBuiltinCall(mlir::Location loc) { } else fnOp = cast(builtin); - return builder.create( + return builder.createCallOp( loc, fnOp, mlir::ValueRange{CurCoro.Data->CoroId.getResult()}); } @@ -223,7 +222,7 @@ CIRGenFunction::buildCoroBeginBuiltinCall(mlir::Location loc, } else fnOp = cast(builtin); - return builder.create( + return builder.createCallOp( loc, fnOp, mlir::ValueRange{CurCoro.Data->CoroId.getResult(), coroframeAddr}); } @@ -244,7 +243,7 @@ mlir::cir::CallOp CIRGenFunction::buildCoroEndBuiltinCall(mlir::Location loc, } else fnOp = cast(builtin); - return builder.create( + return builder.createCallOp( loc, fnOp, mlir::ValueRange{nullPtr, builder.getBool(false, loc)}); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 9465ba3f3b05..df777b95062c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1718,8 +1718,8 @@ void CIRGenModule::ReplaceUsesOfNonProtoTypeWithRealFunction( builder.setInsertionPoint(noProtoCallOp); // Patch call type with the real function type. - auto realCallOp = builder.create( - noProtoCallOp.getLoc(), NewFn, noProtoCallOp.getOperands()); + auto realCallOp = builder.createCallOp(noProtoCallOp.getLoc(), NewFn, + noProtoCallOp.getOperands()); // Replace old no proto call with fixed call. noProtoCallOp.replaceAllUsesWith(realCallOp); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 5d1cfb3c1124..b584ea0a89b3 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2346,6 +2346,7 @@ verifyCallCommInSymbolUses(Operation *op, SymbolTableCollection &symbolTable) { static ::mlir::ParseResult parseCallCommon( ::mlir::OpAsmParser &parser, ::mlir::OperationState &result, + llvm::StringRef extraAttrsAttrName, llvm::function_ref<::mlir::ParseResult(::mlir::OpAsmParser &, ::mlir::OperationState &)> customOpHandler = @@ -2380,6 +2381,23 @@ static ::mlir::ParseResult parseCallCommon( return ::mlir::failure(); if (parser.parseRParen()) return ::mlir::failure(); + + auto &builder = parser.getBuilder(); + 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 = mlir::cir::ExtraFuncAttributesAttr::get( + builder.getContext(), empty.getDictionary(builder.getContext())); + } + result.addAttribute(extraAttrsAttrName, extraAttrs); + if (parser.parseOptionalAttrDict(result.attributes)) return ::mlir::failure(); if (parser.parseColon()) @@ -2400,6 +2418,7 @@ static ::mlir::ParseResult parseCallCommon( void printCallCommon( Operation *op, mlir::Value indirectCallee, mlir::FlatSymbolRefAttr flatSym, ::mlir::OpAsmPrinter &state, + ::mlir::cir::ExtraFuncAttributesAttr extraAttrs, llvm::function_ref customOpHandler = []() {}) { state << ' '; @@ -2415,13 +2434,20 @@ void printCallCommon( state << "("; state << ops; state << ")"; - llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs; + + llvm::SmallVector<::llvm::StringRef, 4> elidedAttrs; elidedAttrs.push_back("callee"); elidedAttrs.push_back("ast"); + elidedAttrs.push_back("extra_attrs"); state.printOptionalAttrDict(op->getAttrs(), elidedAttrs); state << ' ' << ":"; state << ' '; state.printFunctionalType(op->getOperands().getTypes(), op->getResultTypes()); + if (!extraAttrs.getElements().empty()) { + state << " extra("; + state.printAttributeWithoutType(extraAttrs); + state << ")"; + } } LogicalResult @@ -2431,12 +2457,14 @@ cir::CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) { ::mlir::ParseResult CallOp::parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result) { - return parseCallCommon(parser, result); + + return parseCallCommon(parser, result, getExtraAttrsAttrName(result.name)); } void CallOp::print(::mlir::OpAsmPrinter &state) { mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr; - printCallCommon(*this, indirectCallee, getCalleeAttr(), state); + printCallCommon(*this, indirectCallee, getCalleeAttr(), state, + getExtraAttrs()); } //===----------------------------------------------------------------------===// @@ -2493,7 +2521,7 @@ LogicalResult cir::TryCallOp::verify() { return mlir::success(); } ::mlir::ParseResult TryCallOp::parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result) { return parseCallCommon( - parser, result, + parser, result, getExtraAttrsAttrName(result.name), [](::mlir::OpAsmParser &parser, ::mlir::OperationState &result) -> ::mlir::ParseResult { ::mlir::OpAsmParser::UnresolvedOperand exceptionRawOperands[1]; @@ -2535,7 +2563,8 @@ void TryCallOp::print(::mlir::OpAsmPrinter &state) { state << getExceptionInfo(); state << ")"; mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr; - printCallCommon(*this, indirectCallee, getCalleeAttr(), state); + printCallCommon(*this, indirectCallee, getCalleeAttr(), state, + getExtraAttrs()); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 02b54c5a9962..f7643c9b8016 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -195,7 +195,7 @@ FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(GlobalOp op) { } // Create a variable initialization function. - mlir::OpBuilder builder(&getContext()); + CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointAfter(op); auto voidTy = ::mlir::cir::VoidType::get(builder.getContext()); auto fnType = mlir::cir::FuncType::get({}, voidTy); @@ -264,7 +264,7 @@ FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(GlobalOp op) { dtorCall.getArgOperand(0)); args[2] = builder.create( Handle.getLoc(), HandlePtrTy, Handle.getSymName()); - builder.create(dtorCall.getLoc(), fnAtExit, args); + builder.createCallOp(dtorCall.getLoc(), fnAtExit, args); dtorCall->erase(); entryBB->getOperations().splice(entryBB->end(), dtorBlock.getOperations(), dtorBlock.begin(), @@ -481,7 +481,7 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() { fnName += getTransformedFileName(theModule); } - mlir::OpBuilder builder(&getContext()); + CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointToEnd(&theModule.getBodyRegion().back()); auto fnType = mlir::cir::FuncType::get( {}, mlir::cir::VoidType::get(builder.getContext())); @@ -490,7 +490,7 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() { mlir::cir::GlobalLinkageKind::ExternalLinkage); builder.setInsertionPointToStart(f.addEntryBlock()); for (auto &f : dynamicInitializers) { - builder.create(f.getLoc(), f); + builder.createCallOp(f.getLoc(), f); } builder.create(f.getLoc()); @@ -597,7 +597,7 @@ void LoweringPreparePass::lowerArrayCtor(ArrayCtor op) { void LoweringPreparePass::lowerStdFindOp(StdFindOp op) { CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointAfter(op.getOperation()); - auto call = builder.create( + auto call = builder.createCallOp( op.getLoc(), op.getOriginalFnAttr(), op.getResult().getType(), mlir::ValueRange{op.getOperand(0), op.getOperand(1), op.getOperand(2)}); @@ -608,9 +608,9 @@ void LoweringPreparePass::lowerStdFindOp(StdFindOp op) { void LoweringPreparePass::lowerIterBeginOp(IterBeginOp op) { CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointAfter(op.getOperation()); - auto call = builder.create( - op.getLoc(), op.getOriginalFnAttr(), op.getResult().getType(), - mlir::ValueRange{op.getOperand()}); + auto call = builder.createCallOp(op.getLoc(), op.getOriginalFnAttr(), + op.getResult().getType(), + mlir::ValueRange{op.getOperand()}); op.replaceAllUsesWith(call); op.erase(); @@ -619,9 +619,9 @@ void LoweringPreparePass::lowerIterBeginOp(IterBeginOp op) { void LoweringPreparePass::lowerIterEndOp(IterEndOp op) { CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointAfter(op.getOperation()); - auto call = builder.create( - op.getLoc(), op.getOriginalFnAttr(), op.getResult().getType(), - mlir::ValueRange{op.getOperand()}); + auto call = builder.createCallOp(op.getLoc(), op.getOriginalFnAttr(), + op.getResult().getType(), + mlir::ValueRange{op.getOperand()}); op.replaceAllUsesWith(call); op.erase(); @@ -712,8 +712,7 @@ void LoweringPreparePass::runOnMathOp(Operation *op) { buildRuntimeFunction(builder, rtFuncName, op->getLoc(), rtFuncTy); builder.setInsertionPointAfter(op); - auto call = builder.create(op->getLoc(), rtFunc, - op->getOperands()); + auto call = builder.createCallOp(op->getLoc(), rtFunc, op->getOperands()); op->replaceAllUsesWith(call); op->erase(); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp index edf4dfc7d4b3..4d4e2d4f3ba6 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp @@ -317,8 +317,9 @@ Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo, // NOTE(cir): We don't know if the callee was already lowered, so we only // fetch the name from the callee, while the return type is fetch from the // lowering types manager. - CallOp _ = rewriter.create(loc, Caller.getCalleeAttr(), - IRFuncTy.getReturnType(), IRCallArgs); + CallOp callOp = rewriter.create(loc, Caller.getCalleeAttr(), + IRFuncTy.getReturnType(), IRCallArgs); + callOp.setExtraAttrsAttr(Caller.getExtraAttrs()); assert(!::cir::MissingFeatures::vectorType()); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp index 83235f50ffee..ebbcfab0f573 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp @@ -36,7 +36,7 @@ static void buildBadCastCall(CIRBaseBuilderTy &builder, mlir::Location loc, // TODO(cir): set the calling convention to __cxa_bad_cast. assert(!MissingFeatures::setCallingConv()); - builder.create(loc, badCastFuncRef, mlir::ValueRange{}); + builder.createCallOp(loc, badCastFuncRef, mlir::ValueRange{}); builder.create(loc); builder.clearInsertionPoint(); } @@ -62,8 +62,8 @@ static mlir::Value buildDynamicCastAfterNullCheck(CIRBaseBuilderTy &builder, assert(!MissingFeatures::setCallingConv()); mlir::Value castedPtr = builder - .create(loc, dynCastFuncRef, - builder.getVoidPtrTy(), dynCastFuncArgs) + .createCallOp(loc, dynCastFuncRef, builder.getVoidPtrTy(), + dynCastFuncArgs) .getResult(); assert(castedPtr.getType().isa() && diff --git a/clang/test/CIR/CodeGen/call-extra-attrs.cpp b/clang/test/CIR/CodeGen/call-extra-attrs.cpp new file mode 100644 index 000000000000..a17246ddb1b5 --- /dev/null +++ b/clang/test/CIR/CodeGen/call-extra-attrs.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +__attribute__((nothrow)) +int s0(int a, int b) { + int x = a + b; + return x; +} + +__attribute__((noinline)) +int s1(int a, int b) { + return s0(a,b); +} + +int s2(int a, int b) { + return s1(a, b); +} + +// CIR: #fn_attr = #cir, nothrow = #cir.nothrow, optnone = #cir.optnone})> +// CIR: #fn_attr1 = #cir + +// CIR: cir.func @_Z2s0ii(%{{.*}}, %{{.*}}) -> {{.*}} extra(#fn_attr) +// CIR: cir.func @_Z2s1ii(%{{.*}}, %{{.*}}) -> {{.*}} extra(#fn_attr) +// CIR: cir.call @_Z2s0ii(%{{.*}}, %{{.*}}) : ({{.*}}, {{.*}}) -> {{.*}} extra(#fn_attr1) +// CIR: cir.func @_Z2s2ii(%{{.*}}, %{{.*}}) -> {{.*}} extra(#fn_attr) +// CHECK-NOT: cir.call @_Z2s1ii(%{{.*}}, %{{.*}}) : ({{.*}}, {{.*}}) -> {{.*}} extra(#fn_attr{{.*}}) + +// LLVM: define i32 @_Z2s0ii(i32 %0, i32 %1) #[[#ATTR1:]] +// LLVM: define i32 @_Z2s1ii(i32 %0, i32 %1) #[[#ATTR1:]] +// LLVM: define i32 @_Z2s2ii(i32 %0, i32 %1) #[[#ATTR1:]] + +// LLVM: attributes #[[#ATTR1]] = {{.*}} noinline nounwind optnone