Skip to content

[CIR] Add nothrow attribute to the call operation #145178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,26 +227,24 @@ 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);
mlir::Type returnType, mlir::ValueRange operands) {
return create<cir::CallOp>(loc, callee, returnType, operands);
}

cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee,
mlir::ValueRange operands,
cir::SideEffect sideEffect = cir::SideEffect::All) {
mlir::ValueRange operands) {
return createCallOp(loc, mlir::SymbolRefAttr::get(callee),
callee.getFunctionType().getReturnType(), operands,
sideEffect);
callee.getFunctionType().getReturnType(), operands);
}

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);
mlir::ValueRange operands) {
llvm::SmallVector<mlir::Value> resOperands{indirectTarget};
resOperands.append(operands.begin(), operands.end());
return createCallOp(loc, mlir::SymbolRefAttr(), funcType.getReturnType(),
resOperands);
}

//===--------------------------------------------------------------------===//
Expand Down
24 changes: 5 additions & 19 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,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);
}

Expand Down Expand Up @@ -1941,29 +1942,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));
}]>,
}]>
];
}

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -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)>,
];
Expand Down
49 changes: 37 additions & 12 deletions clang/lib/CIR/CodeGen/CIRGenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,38 @@ 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("nothrow", 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("nothrow", 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.
Expand All @@ -104,6 +125,9 @@ void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
}

assert(!cir::MissingFeatures::opCallAttrs());

attrs.set("side_effect",
cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
}

/// Returns the canonical formal type of the given C++ method.
Expand Down Expand Up @@ -416,22 +440,26 @@ 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());
assert(!cir::MissingFeatures::invokeOp());

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);
} else {
op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
}

return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect);
op->setAttrs(attrs);
return op;
}

const CIRGenFunctionInfo &
Expand Down Expand Up @@ -544,8 +572,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());

Expand All @@ -566,12 +593,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;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,9 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.parseRParen())
return mlir::failure();

if (parser.parseOptionalKeyword("nothrow").succeeded())
result.addAttribute("nothrow", mlir::UnitAttr::get(parser.getContext()));

if (parser.parseOptionalKeyword("side_effect").succeeded()) {
if (parser.parseLParen().failed())
return failure();
Expand Down Expand Up @@ -645,7 +648,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 << ' ';

Expand All @@ -662,13 +665,17 @@ 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(),
{"callee", "nothrow", "side_effect"});

printer << " : ";
printer.printFunctionalType(op->getOperands().getTypes(),
Expand All @@ -683,7 +690,8 @@ 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
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -241,7 +241,7 @@ void convertSideEffectForCall(mlir::Operation *callOp,
switch (sideEffect) {
case cir::SideEffect::All:
memoryEffect = {};
noUnwind = false;
noUnwind = isNothrow;
willReturn = false;
break;

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/CodeGen/builtin_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CIR/CodeGen/builtin_printf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:.+]])
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CIR/CodeGen/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Loading