https://github.com/Lancern created https://github.com/llvm/llvm-project/pull/144201
This patch adds `side_effect` attribute to `cir.call` operation. Other function call attributes will be added in later patches. >From ccf7371db9793ac980093fb3a43f24a7e9b176e7 Mon Sep 17 00:00:00 2001 From: Sirui Mu <msrlanc...@gmail.com> Date: Sat, 14 Jun 2025 11:46:18 +0800 Subject: [PATCH] [CIR] Add side effect attribute to call operations --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 16 +++-- clang/include/clang/CIR/Dialect/IR/CIROps.td | 57 ++++++++++++++-- .../clang/CIR/Interfaces/CIROpInterfaces.td | 21 +++--- clang/include/clang/CIR/MissingFeatures.h | 1 - clang/lib/CIR/CodeGen/CIRGenCall.cpp | 46 +++++++++++-- clang/lib/CIR/CodeGen/CIRGenCall.h | 6 ++ clang/lib/CIR/CodeGen/CIRGenModule.h | 10 +++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 66 ++++++++++++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 51 ++++++++++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 5 ++ clang/test/CIR/CodeGen/call.c | 26 ++++++++ clang/test/CIR/IR/call.cir | 4 ++ 12 files changed, 271 insertions(+), 38 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index a3754f4de66b0..b6ae9965161d4 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -213,22 +213,26 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { //===--------------------------------------------------------------------===// cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, - mlir::Type returnType, mlir::ValueRange operands) { - return create<cir::CallOp>(loc, callee, returnType, operands); + mlir::Type returnType, mlir::ValueRange operands, + cir::SideEffect sideEffect = cir::SideEffect::All) { + return create<cir::CallOp>(loc, callee, returnType, operands, sideEffect); } cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee, - mlir::ValueRange operands) { + mlir::ValueRange operands, + cir::SideEffect sideEffect = cir::SideEffect::All) { return createCallOp(loc, mlir::SymbolRefAttr::get(callee), - callee.getFunctionType().getReturnType(), operands); + callee.getFunctionType().getReturnType(), operands, + sideEffect); } cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, - mlir::ValueRange operands) { + mlir::ValueRange operands, + cir::SideEffect sideEffect) { return create<cir::CallOp>(loc, indirectTarget, funcType.getReturnType(), - operands); + operands, sideEffect); } //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 194153caa9271..01c0dec584dd6 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1858,6 +1858,40 @@ def FuncOp : CIR_Op<"func", [ // CallOp //===----------------------------------------------------------------------===// +def SE_All : I32EnumAttrCase<"All", 1, "all">; +def SE_Pure : I32EnumAttrCase<"Pure", 2, "pure">; +def SE_Const : I32EnumAttrCase<"Const", 3, "const">; + +def SideEffect + : I32EnumAttr< + "SideEffect", + "allowed side effects of a function", [SE_All, SE_Pure, SE_Const]> { + let description = [{ + The side effect attribute specifies the possible side effects of the callee + of a call operation. This is an enumeration attribute and all possible + enumerators are: + + - all: The callee can have any side effects. This is the default if no side + effects are explicitly listed. + - pure: The callee may read data from memory, but it cannot write data to + memory. This has the same effect as the GNU C/C++ attribute + `__attribute__((pure))`. + - const: The callee may not read or write data from memory. This has the + same effect as the GNU C/C++ attribute `__attribute__((const))`. + + Examples: + + ```mlir + %0 = cir.const #cir.int<0> : !s32i + %1 = cir.const #cir.int<1> : !s32i + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(all) + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(pure) + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(const) + ``` + }]; + let cppNamespace = "::cir"; +} + class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []> : Op<CIR_Dialect, mnemonic, !listconcat(extra_traits, @@ -1911,7 +1945,8 @@ class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []> // will add in the future. dag commonArgs = (ins OptionalAttr<FlatSymbolRefAttr>:$callee, - Variadic<CIR_AnyType>:$args); + Variadic<CIR_AnyType>:$args, + DefaultValuedAttr<SideEffect, "SideEffect::All">:$side_effect); } def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> { @@ -1940,22 +1975,30 @@ 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), [{ + // 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); + $_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), [{ + // 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 80d78b11c2ba4..ecb2ba8887c3a 100644 --- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td +++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td @@ -24,16 +24,17 @@ let cppNamespace = "::cir" in { def CIRCallOpInterface : OpInterface<"CIRCallOpInterface", [CallOpInterface]> { // Currently we don't have any methods defined in CIRCallOpInterface. We'll // add more methods as the upstreaming proceeds. - let methods = [ - InterfaceMethod< - "Return the operand at index 'i', accounts for indirect call or " - "exception info", - "mlir::Value", "getArgOperand", - (ins "unsigned":$i)>, - InterfaceMethod< - "Return the number of operands, accounts for indirect call or " - "exception info", - "unsigned", "getNumArgOperands", (ins)>, + let methods = + [InterfaceMethod< + "Return the operand at index 'i', accounts for indirect call or " + "exception info", + "mlir::Value", "getArgOperand", (ins "unsigned":$i)>, + InterfaceMethod< + "Return the number of operands, accounts for indirect call or " + "exception info", + "unsigned", "getNumArgOperands", (ins)>, + InterfaceMethod<"Return the side effects of the call operation", + "cir::SideEffect", "getSideEffect", (ins)>, ]; } diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 225e9ec89a827..d5e1442d562b8 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -95,7 +95,6 @@ struct MissingFeatures { static bool opCallReturn() { return false; } static bool opCallArgEvaluationOrder() { return false; } static bool opCallCallConv() { return false; } - static bool opCallSideEffect() { return false; } static bool opCallNoPrototypeFunc() { return false; } static bool opCallMustTail() { return false; } static bool opCallVirtual() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 0d9064425fa95..b37f98ac06af6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -77,6 +77,35 @@ void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) { builder.createStore(*currSrcLoc, value, dest); } +/// Construct the CIR attribute list of a function or call. +void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo, + cir::SideEffect &sideEffect) { + assert(!cir::MissingFeatures::opCallCallConv()); + sideEffect = cir::SideEffect::All; + + assert(!cir::MissingFeatures::opCallAttrs()); + + const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl(); + + if (targetDecl) { + assert(!cir::MissingFeatures::opCallAttrs()); + + // 'const', 'pure' and 'noalias' attributed functions are also nounwind. + if (targetDecl->hasAttr<ConstAttr>()) { + // gcc specifies that 'const' functions have greater restrictions than + // 'pure' functions, so they also cannot have infinite loops. + sideEffect = cir::SideEffect::Const; + } else if (targetDecl->hasAttr<PureAttr>()) { + // gcc specifies that 'pure' functions cannot have infinite loops. + sideEffect = cir::SideEffect::Pure; + } + + assert(!cir::MissingFeatures::opCallAttrs()); + } + + assert(!cir::MissingFeatures::opCallAttrs()); +} + /// Returns the canonical formal type of the given C++ method. static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) { return md->getType() @@ -386,7 +415,8 @@ static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, cir::FuncOp directFuncOp, - const SmallVectorImpl<mlir::Value> &cirCallArgs) { + const SmallVectorImpl<mlir::Value> &cirCallArgs, + cir::SideEffect sideEffect) { CIRGenBuilderTy &builder = cgf.getBuilder(); assert(!cir::MissingFeatures::opCallSurroundingTry()); @@ -397,11 +427,11 @@ 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); + return builder.createIndirectCallOp( + callLoc, indirectFuncVal, indirectFuncTy, cirCallArgs, sideEffect); } - return builder.createCallOp(callLoc, directFuncOp, cirCallArgs); + return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect); } const CIRGenFunctionInfo & @@ -513,8 +543,9 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, funcName = calleeFuncOp.getName(); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); assert(!cir::MissingFeatures::opCallAttrs()); + cir::SideEffect sideEffect; + cgm.constructAttributeList(callee.getAbstractInfo(), sideEffect); assert(!cir::MissingFeatures::invokeOp()); @@ -538,8 +569,9 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, assert(!cir::MissingFeatures::opCallAttrs()); mlir::Location callLoc = loc; - cir::CIRCallOpInterface theCall = emitCallLikeOp( - *this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs); + cir::CIRCallOpInterface theCall = + emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, + cirCallArgs, sideEffect); if (callOp) *callOp = theCall; diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h index 0353848f3ec0d..56c76c51a46d8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -105,6 +105,12 @@ class CIRGenCallee { /// callee CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const; + CIRGenCalleeInfo getAbstractInfo() const { + assert(!cir::MissingFeatures::opCallVirtual()); + assert(isOrdinary()); + return abstractInfo; + } + mlir::Operation *getFunctionPointer() const { assert(isOrdinary()); return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index f76fd8e733642..a3703c90395f6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H #include "CIRGenBuilder.h" +#include "CIRGenCall.h" #include "CIRGenTypeCache.h" #include "CIRGenTypes.h" #include "CIRGenValue.h" @@ -145,6 +146,15 @@ class CIRGenModule : public CIRGenTypeCache { const CXXRecordDecl *derivedClass, llvm::iterator_range<CastExpr::path_const_iterator> path); + /// Get the CIR attributes and calling convention to use for a particular + /// function type. + /// + /// \param calleeInfo - The callee information these attributes are being + /// 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); + /// 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 8ed0ee92574dc..82bec96edc5ff 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -92,6 +92,46 @@ Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder, // Helpers //===----------------------------------------------------------------------===// +// Parses one of the keywords provided in the list `keywords` and returns the +// position of the parsed keyword in the list. If none of the keywords from the +// list is parsed, returns -1. +static int parseOptionalKeywordAlternative(AsmParser &parser, + ArrayRef<llvm::StringRef> keywords) { + for (auto en : llvm::enumerate(keywords)) { + if (succeeded(parser.parseOptionalKeyword(en.value()))) + return en.index(); + } + return -1; +} + +namespace { +template <typename Ty> struct EnumTraits {}; + +#define REGISTER_ENUM_TYPE(Ty) \ + template <> struct EnumTraits<cir::Ty> { \ + static llvm::StringRef stringify(cir::Ty value) { \ + return stringify##Ty(value); \ + } \ + static unsigned getMaxEnumVal() { return cir::getMaxEnumValFor##Ty(); } \ + } + +REGISTER_ENUM_TYPE(SideEffect); +} // namespace + +/// Parse an enum from the keyword, return failure if the keyword is not found. +template <typename EnumTy, typename RetTy = EnumTy> +static ParseResult parseCIRKeyword(AsmParser &parser, RetTy &result) { + llvm::SmallVector<llvm::StringRef, 10> names; + for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i) + names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); + + int index = parseOptionalKeywordAlternative(parser, names); + if (index == -1) + return failure(); + result = static_cast<RetTy>(index); + return success(); +} + // Check if a region's termination omission is valid and, if so, creates and // inserts the omitted terminator into the region. static LogicalResult ensureRegionTerm(OpAsmParser &parser, Region ®ion, @@ -534,6 +574,18 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser, if (parser.parseRParen()) return mlir::failure(); + if (parser.parseOptionalKeyword("side_effect").succeeded()) { + if (parser.parseLParen().failed()) + return failure(); + cir::SideEffect sideEffect; + if (parseCIRKeyword<cir::SideEffect>(parser, sideEffect).failed()) + return failure(); + if (parser.parseRParen().failed()) + return failure(); + auto attr = cir::SideEffectAttr::get(parser.getContext(), sideEffect); + result.addAttribute("side_effect", attr); + } + if (parser.parseOptionalAttrDict(result.attributes)) return ::mlir::failure(); @@ -556,7 +608,8 @@ 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, + cir::SideEffect sideEffect) { printer << ' '; auto callLikeOp = mlir::cast<cir::CIRCallOpInterface>(op); @@ -572,7 +625,13 @@ static void printCallCommon(mlir::Operation *op, } printer << "(" << ops << ")"; - printer.printOptionalAttrDict(op->getAttrs(), {"callee"}); + if (sideEffect != cir::SideEffect::All) { + printer << " side_effect("; + printer << stringifySideEffect(sideEffect); + printer << ")"; + } + + printer.printOptionalAttrDict(op->getAttrs(), {"callee", "side_effect"}); printer << " : "; printer.printFunctionalType(op->getOperands().getTypes(), @@ -586,7 +645,8 @@ mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser, void cir::CallOp::print(mlir::OpAsmPrinter &p) { mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr; - printCallCommon(*this, getCalleeAttr(), indirectCallee, p); + cir::SideEffect sideEffect = getSideEffect(); + printCallCommon(*this, getCalleeAttr(), indirectCallee, p, sideEffect); } static LogicalResult diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 619e113202c9a..cb6c89f395f89 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -220,6 +220,39 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, return value; } +void convertSideEffectForCall(mlir::Operation *callOp, + cir::SideEffect sideEffect, + mlir::LLVM::MemoryEffectsAttr &memoryEffect, + bool &noUnwind, bool &willReturn) { + using mlir::LLVM::ModRefInfo; + + switch (sideEffect) { + case cir::SideEffect::All: + memoryEffect = {}; + noUnwind = false; + willReturn = false; + break; + + case cir::SideEffect::Pure: + memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( + callOp->getContext(), /*other=*/ModRefInfo::Ref, + /*argMem=*/ModRefInfo::Ref, + /*inaccessibleMem=*/ModRefInfo::Ref); + noUnwind = true; + willReturn = true; + break; + + case cir::SideEffect::Const: + memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( + callOp->getContext(), /*other=*/ModRefInfo::NoModRef, + /*argMem=*/ModRefInfo::NoModRef, + /*inaccessibleMem=*/ModRefInfo::NoModRef); + noUnwind = true; + willReturn = true; + break; + } +} + /// IntAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) { mlir::Location loc = parentOp->getLoc(); @@ -737,12 +770,18 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, mlir::FlatSymbolRefAttr calleeAttr) { llvm::SmallVector<mlir::Type, 8> llvmResults; mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes(); + auto call = cast<cir::CIRCallOpInterface>(op); if (converter->convertTypes(cirResults, llvmResults).failed()) return mlir::failure(); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); + + mlir::LLVM::MemoryEffectsAttr memoryEffects; + bool noUnwind = false; + bool willReturn = false; + convertSideEffectForCall(op, call.getSideEffect(), memoryEffects, noUnwind, + willReturn); mlir::LLVM::LLVMFunctionType llvmFnTy; if (calleeAttr) { // direct call @@ -767,10 +806,14 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, assert(!cir::MissingFeatures::opCallLandingPad()); assert(!cir::MissingFeatures::opCallContinueBlock()); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); - rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(op, llvmFnTy, calleeAttr, - callOperands); + auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( + op, llvmFnTy, calleeAttr, callOperands); + if (memoryEffects) + newOp.setMemoryEffectsAttr(memoryEffects); + newOp.setNoUnwind(noUnwind); + newOp.setWillReturn(willReturn); + return mlir::success(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 2eda568c84bdb..bf353c34b46c9 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -29,6 +29,11 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr, mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage); +void convertSideEffectForCall(mlir::Operation *callOp, + cir::SideEffect sideEffect, + mlir::LLVM::MemoryEffectsAttr &memoryEffect, + bool &noUnwind, bool &willReturn); + class CIRToLLVMBrCondOpLowering : public mlir::OpConversionPattern<cir::BrCondOp> { public: diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c index 13f3c5a21ceb0..f6aa41df7439e 100644 --- a/clang/test/CIR/CodeGen/call.c +++ b/clang/test/CIR/CodeGen/call.c @@ -109,3 +109,29 @@ void f9() { // OGCG-NEXT: store i64 %[[RET]], ptr %[[SLOT]], align 4 // OGCG-NEXT: %[[ARG:.+]] = load i64, ptr %[[SLOT]], align 4 // OGCG-NEXT: call void @f1(i64 %[[ARG]]) + +__attribute__((pure)) int f10(int); +__attribute__((const)) int f11(int); +int f12(void) { + return f10(1) + f11(2); +} + +// CIR-LABEL: cir.func @f12() -> !s32i +// CIR: %[[A:.+]] = cir.const #cir.int<1> : !s32i +// CIR-NEXT: %{{.+}} = cir.call @f10(%[[A]]) side_effect(pure) : (!s32i) -> !s32i +// CIR-NEXT: %[[B:.+]] = cir.const #cir.int<2> : !s32i +// CIR-NEXT: %{{.+}} = cir.call @f11(%[[B]]) side_effect(const) : (!s32i) -> !s32i + +// LLVM-LABEL: define i32 @f12() +// LLVM: %{{.+}} = call i32 @f10(i32 1) #[[ATTR0:.+]] +// LLVM-NEXT: %{{.+}} = call i32 @f11(i32 2) #[[ATTR1:.+]] + +// OGCG-LABEL: define dso_local i32 @f12() +// OGCG: %{{.+}} = call i32 @f10(i32 noundef 1) #[[ATTR0:.+]] +// OGCG-NEXT: %{{.+}} = call i32 @f11(i32 noundef 2) #[[ATTR1:.+]] + +// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read, errnomem: none) } +// LLVM: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } + +// OGCG: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } +// OGCG: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } diff --git a/clang/test/CIR/IR/call.cir b/clang/test/CIR/IR/call.cir index e35c201b6ed48..5f0916775479e 100644 --- a/clang/test/CIR/IR/call.cir +++ b/clang/test/CIR/IR/call.cir @@ -8,11 +8,15 @@ cir.func @f1() cir.func @f2() { cir.call @f1() : () -> () + cir.call @f1() side_effect(pure) : () -> () + cir.call @f1() side_effect(const) : () -> () cir.return } // CHECK: cir.func @f2() { // CHECK-NEXT: cir.call @f1() : () -> () +// CHECK-NEXT: cir.call @f1() side_effect(pure) : () -> () +// CHECK-NEXT: cir.call @f1() side_effect(const) : () -> () // CHECK-NEXT: cir.return // CHECK-NEXT: } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits