diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index cb404205f019..783b89f2aa72 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -113,7 +113,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return getPointerTo(cir::VoidType::get(getContext()), as); } - cir::MethodAttr getMethodAttr(cir::MethodType ty, cir::FuncOp methodFuncOp) { + cir::MethodAttr getMethodAttr(cir::MethodType ty, cir::CIRCallableOpInterface methodFuncOp) { auto methodFuncSymbolRef = mlir::FlatSymbolRefAttr::get(methodFuncOp); return cir::MethodAttr::get(ty, methodFuncSymbolRef); } @@ -681,7 +681,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return callOp; } - cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee, + cir::CallOp createCallOp(mlir::Location loc, cir::CIRCallableOpInterface callee, mlir::ValueRange operands = mlir::ValueRange(), cir::CallingConv callingConv = cir::CallingConv::C, cir::SideEffect sideEffect = cir::SideEffect::All, @@ -737,7 +737,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { } cir::CallOp - createTryCallOp(mlir::Location loc, cir::FuncOp callee, + createTryCallOp(mlir::Location loc, cir::CIRCallableOpInterface callee, mlir::ValueRange operands, cir::CallingConv callingConv = cir::CallingConv::C, cir::SideEffect sideEffect = cir::SideEffect::All, diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c8f5e0f6cfde..be6d848efb9d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3762,8 +3762,95 @@ def CIR_OptionalPriorityAttr : OptionalAttr< > >; +def CIR_AliasOp : CIR_Op<"alias", [ + AutomaticAllocationScope, + DeclareOpInterfaceMethods, + CIRCallableOpInterface, + CallableOpInterface, FunctionOpInterface, IsolatedFromAbove]> { + let summary = "Declare or define an alias."; + + let description = [{ + Declare or define an alias that can be used for either + a global variable or a function (only support function for now). + + This operation models the LLVMIR AliasOp to ensure easy lowering: + >`llvm.mlir.alias` is a top level operation that defines a global alias for + >global variables and functions. The operation is always initialized by + >using a initializer region which could be a direct map to another global + >value or contain some address computation on top of it. + + It also mirrors CIR_FuncOp to allow for generation of functions and calling of said + functions. + + Examples: + ``` + // Defining an alias. + "cir.alias"() <{aliasee = @_ZN1AC2Ev, calling_conv = 1 : i32, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1AC1Ev"}> ({ + }) {sym_visibility = "private"} : () -> () + + + // Call an alias op like how you would call a FuncOp + cir.call @_ZN1AC1Ev(%0) : (!cir.ptr) -> () + + ``` + + + + }]; + + let arguments = (ins + SymbolNameAttr:$sym_name, + TypeAttrOf:$function_type, FlatSymbolRefAttr:$aliasee, + CIR_VisibilityAttr:$global_visibility, + DefaultValuedAttr:$linkage, + OptionalAttr:$arg_attrs, + OptionalAttr:$res_attrs, + UnitAttr:$comdat, + UnitAttr:$dso_local, + UnitAttr:$no_proto, + UnitAttr:$builtin, + CIR_OptionalPriorityAttr:$global_ctor_priority, + CIR_OptionalPriorityAttr:$global_dtor_priority, + CIR_ExtraFuncAttr:$extra_attrs, + OptionalAttr:$cxx_special_member, + DefaultValuedAttr:$calling_conv + ); + + let regions = (region AnyRegion:$body); + let skipDefaultBuilders = 1; + + let builders = [OpBuilder<(ins + "llvm::StringRef":$name, "FuncType":$type, + "llvm::StringRef":$aliasee, + CArg<"GlobalLinkageKind", "GlobalLinkageKind::ExternalLinkage">:$linkage, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"llvm::ArrayRef", "{}">:$attrs, + CArg<"llvm::ArrayRef", "{}">:$argAttrs) + >]; + + let extraClassDeclaration = [{ + /// Returns the region on the current operation that is callable. + /// Since this is just an alias, it should return nullptr. + + /// Actualy definition will be generated once lowered to LLVMIR + ::mlir::Region *getCallableRegion() { + return nullptr; + } + + //===------------------------------------------------------------------===// + // SymbolOpInterface Methods + //===------------------------------------------------------------------===// + + bool isDeclaration() { + return true; + } + }]; +} + def FuncOp : CIR_Op<"func", [ AutomaticAllocationScope, CallableOpInterface, FunctionOpInterface, + CIRCallableOpInterface, DeclareOpInterfaceMethods, HasAtMostOneOfAttrs<["global_ctor_priority", "global_dtor_priority"]>, IsolatedFromAbove @@ -3889,35 +3976,6 @@ def FuncOp : CIR_Op<"func", [ /// function. ::mlir::Region *getCallableRegion(); - /// Returns the results types that the callable region produces when - /// executed. - llvm::ArrayRef getCallableResults() { - return getFunctionType().getReturnTypes(); - } - - /// Returns the argument attributes for all callable region arguments or - /// null if there are none. - ::mlir::ArrayAttr getCallableArgAttrs() { - return getArgAttrs().value_or(nullptr); - } - - /// Returns the result attributes for all callable region results or null if - /// there are none. - ::mlir::ArrayAttr getCallableResAttrs() { - return getResAttrs().value_or(nullptr); - } - - /// Returns the argument types of this function. - llvm::ArrayRef getArgumentTypes() { - return getFunctionType().getInputs(); - } - - /// Returns 0 or 1 result type of this function (0 in the case of a function - /// returing void) - llvm::ArrayRef getResultTypes() { - return getFunctionType().getReturnTypes(); - } - //===------------------------------------------------------------------===// // SymbolOpInterface Methods //===------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h index 86064619af7d..2f8c39b0fbb6 100644 --- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h +++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h @@ -18,6 +18,8 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" namespace cir {} // namespace cir diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td index 9f171c2ae4cd..a6d7f5cd4260 100644 --- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td +++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td @@ -43,6 +43,123 @@ let cppNamespace = "::cir" in { ]; } + def CIRCallableOpInterface + : OpInterface<"CIRCallableOpInterface"> { + let description = [{ + The CIRCallableOpInterface is created due to the flexibility that + either AliasOp or FuncOp is returned from the same function. + + It also handles all the default and similar methods that AliasOp and FuncOp might have so + we don't have to define them twice. + + Notice that even though we are declaring methods from CallableOpInterface and + FunctionOpInterface, we cannot add them to the inheritance in OpInterface<...>, as + it will produce clashing of definitions. + }]; + let methods = [ + InterfaceMethod< + "Returns the region on the current operation that is callable. This may " + "return null in the case of an external callable object, e.g. an external " + "function.", + "::mlir::Region*", "getCallableRegion", (ins)>, + InterfaceMethod< + "Returns the type of this function.", + "cir::FuncType", "getFunctionType", + (ins)>, + InterfaceMethod< + "Returns the results types that the callable region produces when " + "executed.", + "llvm::ArrayRef", "getCallableResults", + (ins), [{}], + /*defaultImplementation=*/[{ + return $_op.getFunctionType().getReturnTypes(); + }]>, + InterfaceMethod< + "Returns the result attributes for all callable region results or null if " + "there are none.", + "::mlir::ArrayAttr", "getCallableResAttrs", + (ins), [{}], + /*defaultImplementation=*/[{ + return $_op.getResAttrs().value_or(nullptr); + }]>, + InterfaceMethod< + "Returns the argument types of this function.", + "llvm::ArrayRef", "getArgumentTypes", + (ins), [{}], + /*defaultImplementation=*/[{ + return $_op.getFunctionType().getInputs(); + }]>, + InterfaceMethod< + "Returns 0 or 1 result type of this function (0 in the case of a function " + "returing void).", + "llvm::ArrayRef", "getResultTypes", + (ins), [{}], + /*defaultImplementation=*/[{ + return $_op.getFunctionType().getReturnTypes(); + }]>, + InterfaceMethod< + "Return the calling convention of the called operation", + "cir::CallingConv", "getCallingConv", (ins)>, + InterfaceMethod< + "Return if the callable is prototype defined or not", + "bool", "getNoProto", (ins)>, + InterfaceMethod< + "Set the attribute indicating if the callable is prototype defined or not", + "void", "setNoProtoAttr", (ins "::mlir::UnitAttr":$noProto)>, + InterfaceMethod< + "Set the attribute indicating if the callable is prototype defined or not", + "::mlir::UnitAttr", "getNoProtoAttr", (ins)>, + InterfaceMethod< + "Return if the callable is builtin or not", + "::mlir::UnitAttr", "getBuiltinAttr", (ins)>, + InterfaceMethod< + "Set the attribute indicating if the callable is builtin or not", + "void", "setBuiltinAttr", (ins "::mlir::UnitAttr":$builtin)>, + InterfaceMethod< + "Set the function's calling convention", + "void", "setCallingConv", (ins "::cir::CallingConv":$attr)>, + InterfaceMethod< + "Set the function's calling convention", + "::cir::ExtraFuncAttributesAttr", "getExtraAttrs", (ins)>, + InterfaceMethod< + "Set the function's calling convention", + "void", "setExtraAttrsAttr", (ins "::cir::ExtraFuncAttributesAttr":$attr)>, + InterfaceMethod< + "Return if the callable is a declaration or not", + "bool", "isDeclaration", (ins)>, + InterfaceMethod< + "Return function symbol name", + "::mlir::StringRef", "getSymName", (ins)>, + InterfaceMethod< + "Return function symbol name", + "::mlir::StringAttr", "getSymNameAttr", (ins)>, + InterfaceMethod< + "Return function linkage kind", + "::cir::GlobalLinkageKind", "getLinkage", (ins)>, + InterfaceMethod< + "Set function linkage kind", + "void", "setLinkage", (ins "::cir::GlobalLinkageKind":$kind)>, + InterfaceMethod< + "Set function linkage kind attr", + "void", "setLinkageAttr", (ins "::cir::GlobalLinkageKindAttr":$kind)>, + InterfaceMethod< + "Set function linkage kind", + "void", "setGlobalVisibilityAttr", (ins "::cir::VisibilityAttr":$attr)>, + InterfaceMethod< + "Set function custructor priotity", + "void", "setGlobalCtorPriority", (ins "::std::optional":$prio)>, + InterfaceMethod< + "Set function custructor priotity", + "void", "setGlobalDtorPriority", (ins "::std::optional":$prio)>, + InterfaceMethod< + "Set special member attribute", + "void", "setCxxSpecialMemberAttr", (ins "mlir::Attribute":$attr)>, + + + + ]; + } + def CIRGlobalValueInterface : OpInterface<"CIRGlobalValueInterface", [Symbol]> { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 9022d3f3577c..7e24e12fa916 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -2887,7 +2887,7 @@ mlir::Value CIRGenFunction::evaluateOrEmitBuiltinObjectSize( /// Given a builtin id for a function like "__builtin_fabsf", return a Function* /// for "fabsf". -cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *FD, +cir::CIRCallableOpInterface CIRGenModule::getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID) { assert(astContext.BuiltinInfo.isLibFunction(BuiltinID)); diff --git a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp index dba29d8cab83..f6f49ac41a2a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp @@ -59,9 +59,9 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { std::unique_ptr deviceMC; private: - void emitDeviceStubBodyLegacy(CIRGenFunction &cgf, cir::FuncOp fn, + void emitDeviceStubBodyLegacy(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn, FunctionArgList &args); - void emitDeviceStubBodyNew(CIRGenFunction &cgf, cir::FuncOp fn, + void emitDeviceStubBodyNew(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn, FunctionArgList &args); std::string addPrefixToName(StringRef FuncName) const; std::string addUnderscoredPrefixToName(StringRef FuncName) const; @@ -70,10 +70,10 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { CIRGenNVCUDARuntime(CIRGenModule &cgm); ~CIRGenNVCUDARuntime(); - void emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn, + void emitDeviceStub(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn, FunctionArgList &args) override; - mlir::Operation *getKernelHandle(cir::FuncOp fn, GlobalDecl GD) override; + mlir::Operation *getKernelHandle(cir::CIRCallableOpInterface fn, GlobalDecl GD) override; void internalizeDeviceSideVar(const VarDecl *d, cir::GlobalLinkageKind &linkage) override; @@ -109,13 +109,13 @@ CIRGenNVCUDARuntime::addUnderscoredPrefixToName(StringRef FuncName) const { } void CIRGenNVCUDARuntime::emitDeviceStubBodyLegacy(CIRGenFunction &cgf, - cir::FuncOp fn, + cir::CIRCallableOpInterface fn, FunctionArgList &args) { llvm_unreachable("NYI"); } void CIRGenNVCUDARuntime::emitDeviceStubBodyNew(CIRGenFunction &cgf, - cir::FuncOp fn, + cir::CIRCallableOpInterface fn, FunctionArgList &args) { // This requires arguments to be sent to kernels in a different way. @@ -198,7 +198,7 @@ void CIRGenNVCUDARuntime::emitDeviceStubBodyNew(CIRGenFunction &cgf, builder.createAlloca(loc, cir::PointerType::get(streamTy), streamTy, "stream", cgm.getPointerAlign()); - cir::FuncOp popConfig = cgm.createRuntimeFunction( + cir::CIRCallableOpInterface popConfig = cgm.createRuntimeFunction( cir::FuncType::get({gridDim.getType(), blockDim.getType(), sharedMem.getType(), stream.getType()}, cgm.SInt32Ty), @@ -257,7 +257,7 @@ void CIRGenNVCUDARuntime::emitDeviceStubBodyNew(CIRGenFunction &cgf, launchArgs); } -void CIRGenNVCUDARuntime::emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn, +void CIRGenNVCUDARuntime::emitDeviceStub(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn, FunctionArgList &args) { if (auto globalOp = llvm::dyn_cast(KernelHandles[fn.getSymName()])) { @@ -275,7 +275,7 @@ void CIRGenNVCUDARuntime::emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn, emitDeviceStubBodyLegacy(cgf, fn, args); } -mlir::Operation *CIRGenNVCUDARuntime::getKernelHandle(cir::FuncOp fn, +mlir::Operation *CIRGenNVCUDARuntime::getKernelHandle(cir::CIRCallableOpInterface fn, GlobalDecl GD) { // Check if we already have a kernel handle for this function diff --git a/clang/lib/CIR/CodeGen/CIRGenCUDARuntime.h b/clang/lib/CIR/CodeGen/CIRGenCUDARuntime.h index 0694a9a95d6f..e2e35d917dde 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCUDARuntime.h +++ b/clang/lib/CIR/CodeGen/CIRGenCUDARuntime.h @@ -38,13 +38,13 @@ class CIRGenCUDARuntime { CIRGenCUDARuntime(CIRGenModule &cgm) : cgm(cgm) {} virtual ~CIRGenCUDARuntime(); - virtual void emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn, + virtual void emitDeviceStub(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn, FunctionArgList &args) = 0; virtual RValue emitCUDAKernelCallExpr(CIRGenFunction &cgf, const CUDAKernelCallExpr *expr, ReturnValueSlot retValue); - virtual mlir::Operation *getKernelHandle(cir::FuncOp fn, GlobalDecl GD) = 0; + virtual mlir::Operation *getKernelHandle(cir::CIRCallableOpInterface fn, GlobalDecl GD) = 0; virtual void internalizeDeviceSideVar(const VarDecl *d, cir::GlobalLinkageKind &linkage) = 0; /// Returns function or variable name on device side even if the current diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index 79157921bfe2..883b99c1556d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -259,7 +259,7 @@ static void emitDeclDestroy(CIRGenFunction &CGF, const VarDecl *D) { // generated elsewhere which uses atexit instead, and it takes the destructor // directly. auto UsingExternalHelper = CGM.getCodeGenOpts().CXAAtExit; - cir::FuncOp fnOp; + cir::CIRCallableOpInterface fnOp; if (Record && (CanRegisterDestructor || UsingExternalHelper)) { assert(!D->getTLSKind() && "TLS NYI"); assert(!Record->hasTrivialDestructor()); @@ -282,7 +282,7 @@ static void emitDeclDestroy(CIRGenFunction &CGF, const VarDecl *D) { CGM.getCXXABI().registerGlobalDtor(CGF, D, fnOp, nullptr); } -cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl GD) { +cir::CIRCallableOpInterface CIRGenModule::codegenCXXStructor(GlobalDecl GD) { const auto &FnInfo = getTypes().arrangeCXXStructorDeclaration(GD); auto Fn = getAddrOfCXXStructor(GD, &FnInfo, /*FnType=*/nullptr, /*DontDefer=*/true, ForDefinition); diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 9d9b80dd1d2d..14efd1650be7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -180,7 +180,7 @@ class CIRGenCXXABI { /// \param Dtor - a function taking a single pointer argument /// \param Addr - a pointer to pass to the destructor function. virtual void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D, - cir::FuncOp dtor, mlir::Value Addr) = 0; + cir::CIRCallableOpInterface dtor, mlir::Value Addr) = 0; virtual void emitVirtualObjectDelete(CIRGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 11225ba1a102..d1bb4c2201fd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -319,7 +319,7 @@ void CIRGenModule::constructAttributeList( static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &CGF, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, - cir::FuncOp directFuncOp, + cir::CIRCallableOpInterface directFuncOp, SmallVectorImpl &CIRCallArgs, bool isInvoke, cir::CallingConv callingConv, cir::SideEffect sideEffect, cir::ExtraFuncAttributesAttr extraFnAttrs) { @@ -560,8 +560,8 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo, // Compute the calling convention and attributes. mlir::NamedAttrList Attrs; StringRef FnName; - if (auto calleeFnOp = dyn_cast(CalleePtr)) - FnName = calleeFnOp.getName(); + if (auto calleeFnOp = dyn_cast(CalleePtr)) + FnName = calleeFnOp.getSymName(); cir::CallingConv callingConv; cir::SideEffect sideEffect; @@ -601,7 +601,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo, auto noThrowAttr = cir::NoThrowAttr::get(&getMLIRContext()); CannotThrow = Attrs.getNamed(noThrowAttr.getMnemonic()).has_value(); - if (auto fptr = dyn_cast(CalleePtr)) + if (auto fptr = dyn_cast(CalleePtr)) if (fptr.getExtraAttrs().getElements().contains( noThrowAttr.getMnemonic())) CannotThrow = true; @@ -618,9 +618,9 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo, cir::CIRCallOpInterface theCall = [&]() { cir::FuncType indirectFuncTy; mlir::Value indirectFuncVal; - cir::FuncOp directFuncOp; + cir::CIRCallableOpInterface directFuncOp; - if (auto fnOp = dyn_cast(CalleePtr)) { + if (auto fnOp = dyn_cast(CalleePtr)) { directFuncOp = fnOp; } else if (auto getGlobalOp = dyn_cast(CalleePtr)) { // FIXME(cir): This peephole optimization to avoids indirect calls for @@ -629,7 +629,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo, auto *globalOp = mlir::SymbolTable::lookupSymbolIn(CGM.getModule(), getGlobalOp.getName()); assert(getGlobalOp && "undefined global function"); - directFuncOp = llvm::dyn_cast(globalOp); + directFuncOp = llvm::dyn_cast(globalOp); assert(directFuncOp && "operation is not a function"); } else { [[maybe_unused]] auto resultTypes = CalleePtr->getResultTypes(); @@ -738,7 +738,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo, } mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc, - cir::FuncOp callee, + cir::CIRCallableOpInterface callee, ArrayRef args) { // TODO(cir): set the calling convention to this runtime call. assert(!cir::MissingFeatures::setCallingConv()); diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 549ef3ac7d22..94bc5b709693 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -167,7 +167,7 @@ cir::CallOp CIRGenFunction::emitCoroIDBuiltinCall(mlir::Location loc, mlir::Operation *builtin = CGM.getGlobalValue(CGM.builtinCoroId); - cir::FuncOp fnOp; + cir::CIRCallableOpInterface fnOp; if (!builtin) { fnOp = CGM.createCIRFunction( loc, CGM.builtinCoroId, @@ -189,7 +189,7 @@ cir::CallOp CIRGenFunction::emitCoroAllocBuiltinCall(mlir::Location loc) { mlir::Operation *builtin = CGM.getGlobalValue(CGM.builtinCoroAlloc); - cir::FuncOp fnOp; + cir::CIRCallableOpInterface fnOp; if (!builtin) { fnOp = CGM.createCIRFunction(loc, CGM.builtinCoroAlloc, cir::FuncType::get({int32Ty}, boolTy), @@ -209,7 +209,7 @@ CIRGenFunction::emitCoroBeginBuiltinCall(mlir::Location loc, auto int32Ty = builder.getUInt32Ty(); mlir::Operation *builtin = CGM.getGlobalValue(CGM.builtinCoroBegin); - cir::FuncOp fnOp; + cir::CIRCallableOpInterface fnOp; if (!builtin) { fnOp = CGM.createCIRFunction( loc, CGM.builtinCoroBegin, @@ -230,7 +230,7 @@ cir::CallOp CIRGenFunction::emitCoroEndBuiltinCall(mlir::Location loc, auto boolTy = builder.getBoolTy(); mlir::Operation *builtin = CGM.getGlobalValue(CGM.builtinCoroEnd); - cir::FuncOp fnOp; + cir::CIRCallableOpInterface fnOp; if (!builtin) { fnOp = CGM.createCIRFunction(loc, CGM.builtinCoroEnd, diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 4e2b2cb0e178..25a4c604c0f8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -46,7 +46,7 @@ using namespace clang; using namespace clang::CIRGen; using namespace cir; -static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &CGM, GlobalDecl GD) { +static cir::CIRCallableOpInterface emitFunctionDeclPointer(CIRGenModule &CGM, GlobalDecl GD) { const auto *FD = cast(GD.getDecl()); if (FD->hasAttr()) { @@ -2270,7 +2270,7 @@ static void pushTemporaryCleanup(CIRGenFunction &CGF, switch (M->getStorageDuration()) { case SD_Static: case SD_Thread: { - cir::FuncOp cleanupFn; + cir::CIRCallableOpInterface cleanupFn; mlir::Value cleanupArg; if (E->getType()->isArrayType()) { llvm_unreachable("SD_Static|SD_Thread + array types not implemented"); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 2aa96fa3b7f2..0f83fb7b5b30 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -621,12 +621,12 @@ void CIRGenFunction::finishFunction(SourceLocation endLoc) { // block, it'd be deleted now. Same for unused ret allocas from ReturnValue } -static void eraseEmptyAndUnusedBlocks(cir::FuncOp fnOp) { +static void eraseEmptyAndUnusedBlocks(cir::CIRCallableOpInterface fnOp) { // Remove any left over blocks that are unrecheable and empty, since they do // not represent unrecheable code useful for warnings nor anything deemed // useful in general. SmallVector blocksToDelete; - for (auto &blk : fnOp.getBlocks()) { + for (auto &blk : cast(fnOp).getBlocks()) { if (!blk.empty() || !blk.getUses().empty()) continue; blocksToDelete.push_back(&blk); @@ -635,7 +635,7 @@ static void eraseEmptyAndUnusedBlocks(cir::FuncOp fnOp) { b->erase(); } -static bool isInterposable(cir::FuncOp fn) { +static bool isInterposable(cir::CIRCallableOpInterface fn) { if (isInterposableLinkage(fn.getLinkage())) return true; @@ -644,7 +644,7 @@ static bool isInterposable(cir::FuncOp fn) { return false; } -static void tryMarkNoThrow(CIRGenFunction &cgf, cir::FuncOp fn) { +static void tryMarkNoThrow(CIRGenFunction &cgf, cir::CIRCallableOpInterface fn) { // LLVM treats 'nounwind' on a function as part of the type, so we // can't do this on functions that can be overwritten. if (isInterposable(fn) || cgf.mayThrow) @@ -657,7 +657,7 @@ static void tryMarkNoThrow(CIRGenFunction &cgf, cir::FuncOp fn) { extraAttrs.getDictionary(&cgf.getMLIRContext()))); } -cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, +cir::CIRCallableOpInterface CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::CIRCallableOpInterface fn, const CIRGenFunctionInfo &fnInfo) { assert(fn && "generating code for a null function"); const auto *const fd = cast(gd.getDecl()); @@ -743,7 +743,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, SourceLocRAIIObject fnLoc{*this, loc.isValid() ? getLoc(loc) : unknownLoc}; assert(fn.isDeclaration() && "Function already has body?"); - mlir::Block *entryBb = fn.addEntryBlock(); + mlir::Block *entryBb = cast(fn).addEntryBlock(); builder.setInsertionPointToStart(entryBb); { // Initialize lexical scope information. @@ -810,7 +810,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, assert(builder.getInsertionBlock() && "Should be valid"); - if (mlir::failed(fn.verifyBody())) + if (mlir::failed(cast(fn).verifyBody())) return nullptr; // Emit the standard function epilogue. @@ -981,7 +981,7 @@ static mlir::Value emitArgumentDemotion(CIRGenFunction &cgf, const VarDecl *var, } void CIRGenFunction::StartFunction(GlobalDecl gd, QualType retTy, - cir::FuncOp Fn, + cir::CIRCallableOpInterface Fn, const CIRGenFunctionInfo &fnInfo, const FunctionArgList &args, SourceLocation Loc, @@ -1249,7 +1249,7 @@ void CIRGenFunction::StartFunction(GlobalDecl gd, QualType retTy, // codegen logic. (void)returnBlock(retBlock); - mlir::Block *entryBb = &Fn.getBlocks().front(); + mlir::Block *entryBb = &cast(Fn).getBlocks().front(); if (cir::MissingFeatures::requiresReturnValueCheck()) llvm_unreachable("NYI"); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 6b05e476833e..488c381f3234 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -835,7 +835,7 @@ class CIRGenFunction : public CIRGenTypeCache { const CaseStmt *foldCaseStmt(const clang::CaseStmt &S, mlir::Type condType, mlir::ArrayAttr &value, cir::CaseOpKind &kind); - cir::FuncOp generateCode(clang::GlobalDecl GD, cir::FuncOp Fn, + cir::CIRCallableOpInterface generateCode(clang::GlobalDecl GD, cir::CIRCallableOpInterface Fn, const CIRGenFunctionInfo &FnInfo); clang::QualType buildFunctionArgList(clang::GlobalDecl GD, @@ -1081,7 +1081,7 @@ class CIRGenFunction : public CIRGenTypeCache { /// \param Loc The location to be associated with the function. /// \param StartLoc The location of the function body. void StartFunction(clang::GlobalDecl GD, clang::QualType RetTy, - cir::FuncOp Fn, const CIRGenFunctionInfo &FnInfo, + cir::CIRCallableOpInterface Fn, const CIRGenFunctionInfo &FnInfo, const FunctionArgList &Args, clang::SourceLocation Loc, clang::SourceLocation StartLoc); @@ -1688,7 +1688,7 @@ class CIRGenFunction : public CIRGenTypeCache { private: /// Add OpenCL kernel arg metadata and the kernel attribute metadata to /// the function metadata. - void emitKernelMetadata(const FunctionDecl *FD, cir::FuncOp Fn); + void emitKernelMetadata(const FunctionDecl *FD, cir::CIRCallableOpInterface Fn); void emitAndUpdateRetAlloca(clang::QualType ty, mlir::Location loc, clang::CharUnits alignment); @@ -2356,7 +2356,7 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitRotate(const CallExpr *E, bool IsRotateRight); - mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, + mlir::Value emitRuntimeCall(mlir::Location loc, cir::CIRCallableOpInterface callee, llvm::ArrayRef args = {}); mlir::Value emitScalarConstant(const ConstantEmission &Constant, Expr *E); diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index d47527d15ae9..e850ac4b815b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -186,7 +186,7 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { bool Delegating, Address This, QualType ThisTy) override; void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D, - cir::FuncOp dtor, mlir::Value Addr) override; + cir::CIRCallableOpInterface dtor, mlir::Value Addr) override; void emitVirtualObjectDelete(CIRGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) override; @@ -532,8 +532,8 @@ static void emitConstructorDestructorAlias(CIRGenModule &CGM, auto Entry = dyn_cast_or_null(CGM.getGlobalValue(MangledName)); // Retrieve aliasee info. - auto Aliasee = dyn_cast_or_null(CGM.GetAddrOfGlobal(TargetDecl)); - assert(Aliasee && "expected cir.func"); + auto Aliasee = dyn_cast_or_null(CGM.GetAddrOfGlobal(TargetDecl)); + assert(Aliasee && "expected cir.func or cir.alias"); // Populate actual alias. CGM.emitAliasForGlobal(MangledName, Entry, AliasDecl, Aliasee, Linkage); @@ -2271,7 +2271,7 @@ void CIRGenItaniumCXXABI::emitDestructorCall( } void CIRGenItaniumCXXABI::registerGlobalDtor(CIRGenFunction &CGF, - const VarDecl *D, cir::FuncOp dtor, + const VarDecl *D, cir::CIRCallableOpInterface dtor, mlir::Value Addr) { if (D->isNoDestroy(CGM.getASTContext())) return; @@ -2435,7 +2435,7 @@ mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset( return VBaseOffset; } -static cir::FuncOp getBadCastFn(CIRGenFunction &CGF) { +static cir::CIRCallableOpInterface getBadCastFn(CIRGenFunction &CGF) { // Prototype: void __cxa_bad_cast(); // TODO(cir): set the calling convention of the runtime function. @@ -2511,7 +2511,7 @@ static CharUnits computeOffsetHint(ASTContext &astContext, return Offset; } -static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &CGF) { +static cir::CIRCallableOpInterface getItaniumDynamicCastFn(CIRGenFunction &CGF) { // Prototype: // void *__dynamic_cast(const void *sub, // global_as const abi::__class_type_info *src, diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index d80c9a1f09e0..d866e7fd4614 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -744,7 +744,7 @@ void CIRGenModule::emitGlobalFunctionDefinition(GlobalDecl gd, auto ty = getTypes().GetFunctionType(fi); // Get or create the prototype for the function. - auto fn = dyn_cast_if_present(op); + auto fn = dyn_cast_if_present(op); if (!fn || fn.getFunctionType() != ty) { fn = GetAddrOfFunction(gd, ty, /*ForVTable=*/false, /*DontDefer=*/true, ForDefinition); @@ -781,7 +781,7 @@ void CIRGenModule::emitGlobalFunctionDefinition(GlobalDecl gd, } /// Track functions to be called before main() runs. -void CIRGenModule::AddGlobalCtor(cir::FuncOp ctor, +void CIRGenModule::AddGlobalCtor(cir::CIRCallableOpInterface ctor, std::optional priority) { // FIXME(cir): handle LexOrder and Associated data upon testcases. // @@ -794,7 +794,7 @@ void CIRGenModule::AddGlobalCtor(cir::FuncOp ctor, } /// Add a function to the list that will be called when the module is unloaded. -void CIRGenModule::AddGlobalDtor(cir::FuncOp dtor, std::optional priority, +void CIRGenModule::AddGlobalDtor(cir::CIRCallableOpInterface dtor, std::optional priority, bool isDtorAttrFunc) { assert(isDtorAttrFunc && "NYI"); if (codeGenOpts.RegisterGlobalDtorsWithAtExit && @@ -2389,7 +2389,7 @@ cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator( /// won't inline them. Instcombine normally deletes these calls, but it isn't /// run at -O0. void CIRGenModule::ReplaceUsesOfNonProtoTypeWithRealFunction( - mlir::Operation *old, cir::FuncOp newFn) { + mlir::Operation *old, cir::CIRCallableOpInterface newFn) { // If we're redefining a global as a function, don't transform it. auto oldFn = dyn_cast(old); @@ -2450,7 +2450,7 @@ cir::GlobalLinkageKind CIRGenModule::getFunctionLinkage(GlobalDecl gd) { void CIRGenModule::emitAliasForGlobal(StringRef mangledName, mlir::Operation *op, GlobalDecl aliasGD, - cir::FuncOp aliasee, + cir::CIRCallableOpInterface aliasee, cir::GlobalLinkageKind linkage) { auto *aliasFD = dyn_cast(aliasGD.getDecl()); assert(aliasFD && "expected FunctionDecl"); @@ -2460,11 +2460,9 @@ void CIRGenModule::emitAliasForGlobal(StringRef mangledName, // point. auto &fnInfo = getTypes().arrangeCXXStructorDeclaration(aliasGD); auto fnType = getTypes().GetFunctionType(fnInfo); - - auto alias = createCIRFunction(getLoc(aliasGD.getDecl()->getSourceRange()), - mangledName, fnType, aliasFD); - alias.setAliasee(aliasee.getName()); - alias.setLinkage(linkage); + auto alias = createCIRAliasFunction( + getLoc(aliasGD.getDecl()->getSourceRange()), mangledName, fnType, + aliasee.getSymName(), linkage, aliasFD); // Declarations cannot have public MLIR visibility, just mark them private // but this really should have no meaning since CIR should not be using // this information to derive linkage information. @@ -2476,9 +2474,10 @@ void CIRGenModule::emitAliasForGlobal(StringRef mangledName, // Switch any previous uses to the alias. if (op) { - llvm_unreachable("NYI"); + op->replaceAllUsesWith(alias); + op->erase(); } else { - // Name already set by createCIRFunction + // Name already set by createCIRAliasFunction } // Finally, set up the alias with its proper name and attributes. @@ -2496,7 +2495,7 @@ bool CIRGenModule::verifyModule() { return mlir::verify(theModule).succeeded(); } -std::pair CIRGenModule::getAddrAndTypeOfCXXStructor( +std::pair CIRGenModule::getAddrAndTypeOfCXXStructor( GlobalDecl gd, const CIRGenFunctionInfo *fnInfo, cir::FuncType fnType, bool dontdefer, ForDefinition_t isForDefinition) { auto *md = cast(gd.getDecl()); @@ -2523,7 +2522,7 @@ std::pair CIRGenModule::getAddrAndTypeOfCXXStructor( return {fnType, fn}; } -cir::FuncOp CIRGenModule::GetAddrOfFunction(clang::GlobalDecl gd, mlir::Type ty, +cir::CIRCallableOpInterface CIRGenModule::GetAddrOfFunction(clang::GlobalDecl gd, mlir::Type ty, bool forVTable, bool dontDefer, ForDefinition_t isForDefinition) { assert(!cast(gd.getDecl())->isConsteval() && @@ -2707,8 +2706,39 @@ bool CIRGenModule::lookupRepresentativeDecl(StringRef mangledName, result = res->getValue(); return true; } +cir::AliasOp +CIRGenModule::createCIRAliasFunction(mlir::Location loc, llvm::StringRef name, + cir::FuncType Ty, StringRef aliasee, + cir::GlobalLinkageKind linkage, + const clang::FunctionDecl *FD) { + AliasOp Alias; + { + mlir::OpBuilder::InsertionGuard guard(builder); + + // Be sure to insert a new function before a current one. + auto *curCGF = getCurrCIRGenFun(); + if (curCGF) + builder.setInsertionPoint(curCGF->CurFn); + + Alias = builder.create(loc,name, Ty, aliasee, + linkage); -cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, + assert(Alias.isDeclaration() && "expected empty body"); + + // A declaration gets private visibility by default, but external linkage + // as the default linkage. + Alias.setLinkageAttr(cir::GlobalLinkageKindAttr::get( + &getMLIRContext(), cir::GlobalLinkageKind::ExternalLinkage)); + mlir::SymbolTable::setSymbolVisibility( + Alias, mlir::SymbolTable::Visibility::Private); + + if (!curCGF) + theModule.push_back(Alias); + } + + return Alias; +} +cir::CIRCallableOpInterface CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, cir::FuncType ty, const clang::FunctionDecl *fd) { // At the point we need to create the function, the insertion point @@ -2774,7 +2804,7 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, return f; } -cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty, +cir::CIRCallableOpInterface CIRGenModule::createRuntimeFunction(cir::FuncType ty, StringRef name, mlir::ArrayAttr, [[maybe_unused]] bool local, bool assumeConvergent) { @@ -2831,7 +2861,7 @@ static bool hasUnwindExceptions(const LangOptions &langOpts) { } void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl, - FuncOp f) { + cir::CIRCallableOpInterface f) { mlir::NamedAttrList attrs{f.getExtraAttrs().getElements().getValue()}; if ((!decl || !decl->hasAttr()) && codeGenOpts.UnwindTables) { @@ -3006,14 +3036,14 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl, void CIRGenModule::setCIRFunctionAttributes(GlobalDecl gd, const CIRGenFunctionInfo &info, - cir::FuncOp func, bool isThunk) { + cir::CIRCallableOpInterface func, bool isThunk) { // TODO(cir): More logic of constructAttributeList is needed. cir::CallingConv callingConv; cir::SideEffect sideEffect; // Initialize PAL with existing attributes to merge attributes. mlir::NamedAttrList pal{func.getExtraAttrs().getElements().getValue()}; - constructAttributeList(func.getName(), info, gd, pal, callingConv, sideEffect, + constructAttributeList(func->getName().getStringRef(), info, gd, pal, callingConv, sideEffect, /*AttrOnCallSite=*/false, isThunk); func.setExtraAttrsAttr( cir::ExtraFuncAttributesAttr::get(pal.getDictionary(&getMLIRContext()))); @@ -3024,7 +3054,7 @@ void CIRGenModule::setCIRFunctionAttributes(GlobalDecl gd, } void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl, - cir::FuncOp func, + cir::CIRCallableOpInterface func, bool isIncompleteFunction, bool isThunk) { // NOTE(cir): Original CodeGen checks if this is an intrinsic. In CIR we @@ -3061,7 +3091,7 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl, /// /// If D is non-null, it specifies a decl that corresponded to this. This is /// used to set the attributes on the function when it is first created. -cir::FuncOp CIRGenModule::GetOrCreateCIRFunction( +cir::CIRCallableOpInterface CIRGenModule::GetOrCreateCIRFunction( StringRef mangledName, mlir::Type ty, GlobalDecl gd, bool forVTable, bool dontDefer, bool isThunk, ForDefinition_t isForDefinition, mlir::ArrayAttr extraAttrs) { @@ -3084,8 +3114,8 @@ cir::FuncOp CIRGenModule::GetOrCreateCIRFunction( // Lookup the entry, lazily creating it if necessary. mlir::Operation *entry = getGlobalValue(mangledName); if (entry) { - assert(isa(entry) && - "not implemented, only supports FuncOp for now"); + // assert(isa(entry) && + // "not implemented, only supports FuncOp for now"); if (WeakRefReferences.erase(entry)) { llvm_unreachable("NYI"); @@ -3099,7 +3129,7 @@ cir::FuncOp CIRGenModule::GetOrCreateCIRFunction( // If there are two attempts to define the same mangled name, issue an // error. - auto fn = cast(entry); + auto fn = cast(entry); if (isForDefinition && fn && !fn.isDeclaration()) { GlobalDecl otherGd; // CHeck that GD is not yet in DiagnosedConflictingDefinitions is required @@ -3160,7 +3190,7 @@ cir::FuncOp CIRGenModule::GetOrCreateCIRFunction( assert(symbolOp && "Expected a symbol-defining operation"); // TODO(cir): When can this symbol be something other than a function? - assert(isa(entry) && "NYI"); + assert(isa(entry) && "NYI"); // This might be an implementation of a function without a prototype, in // which case, try to do special replacement of calls which match the new @@ -3873,11 +3903,11 @@ void CIRGenModule::maybeSetTrivialComdat(const Decl &d, mlir::Operation *op) { assert(!cir::MissingFeatures::setComdat() && "NYI"); } -bool CIRGenModule::isInNoSanitizeList(SanitizerMask kind, cir::FuncOp fn, +bool CIRGenModule::isInNoSanitizeList(SanitizerMask kind, cir::CIRCallableOpInterface fn, SourceLocation loc) const { const auto &noSanitizeL = getASTContext().getNoSanitizeList(); // NoSanitize by function name. - if (noSanitizeL.containsFunction(kind, fn.getName())) + if (noSanitizeL.containsFunction(kind, fn.getSymName())) llvm_unreachable("NYI"); // NoSanitize by location. if (loc.isValid()) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index cc7bff03eaa4..036a317db784 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -267,9 +267,9 @@ class CIRGenModule : public CIRGenTypeCache { /// Add a global constructor or destructor to the module. /// The priority is optional, if not specified, the default priority is used. - void AddGlobalCtor(cir::FuncOp ctor, + void AddGlobalCtor(cir::CIRCallableOpInterface ctor, std::optional priority = std::nullopt); - void AddGlobalDtor(cir::FuncOp dtor, + void AddGlobalDtor(cir::CIRCallableOpInterface dtor, std::optional priority = std::nullopt, bool isDtorAttrFunc = false); @@ -559,7 +559,7 @@ class CIRGenModule : public CIRGenTypeCache { const CXXRecordDecl *Derived, const CXXRecordDecl *VBase); - cir::FuncOp + cir::CIRCallableOpInterface getAddrOfCXXStructor(clang::GlobalDecl GD, const CIRGenFunctionInfo *FnInfo = nullptr, cir::FuncType FnType = nullptr, bool DontDefer = false, @@ -645,7 +645,7 @@ class CIRGenModule : public CIRGenTypeCache { DeferredDeclsToEmit.emplace_back(GD); } - std::pair getAddrAndTypeOfCXXStructor( + std::pair getAddrAndTypeOfCXXStructor( clang::GlobalDecl GD, const CIRGenFunctionInfo *FnInfo = nullptr, cir::FuncType FnType = nullptr, bool Dontdefer = false, ForDefinition_t IsForDefinition = NotForDefinition); @@ -660,7 +660,7 @@ class CIRGenModule : public CIRGenTypeCache { bool tryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); void emitAliasForGlobal(llvm::StringRef mangledName, mlir::Operation *op, - GlobalDecl aliasGD, cir::FuncOp aliasee, + GlobalDecl aliasGD, cir::CIRCallableOpInterface aliasee, cir::GlobalLinkageKind linkage); mlir::Type convertType(clang::QualType type); @@ -697,7 +697,7 @@ class CIRGenModule : public CIRGenTypeCache { bool MayDropFunctionReturn(const clang::ASTContext &astContext, clang::QualType ReturnType); - bool isInNoSanitizeList(clang::SanitizerMask Kind, cir::FuncOp Fn, + bool isInNoSanitizeList(clang::SanitizerMask Kind, cir::CIRCallableOpInterface Fn, clang::SourceLocation) const; /// Determine whether the definition can be emitted eagerly, or should be @@ -711,7 +711,7 @@ class CIRGenModule : public CIRGenTypeCache { /// Return the address of the given function. If Ty is non-null, then this /// function will use the specified type if it has to create it. // TODO: this is a bit weird as `GetAddr` given we give back a FuncOp? - cir::FuncOp + cir::CIRCallableOpInterface GetAddrOfFunction(clang::GlobalDecl GD, mlir::Type Ty = nullptr, bool ForVTable = false, bool Dontdefer = false, ForDefinition_t IsForDefinition = NotForDefinition); @@ -750,17 +750,17 @@ class CIRGenModule : public CIRGenTypeCache { void UpdateCompletedType(const clang::TagDecl *TD); /// Set function attributes for a function declaration. - void setFunctionAttributes(GlobalDecl GD, cir::FuncOp F, + void setFunctionAttributes(GlobalDecl GD, cir::CIRCallableOpInterface F, bool IsIncompleteFunction, bool IsThunk); /// Set the CIR function attributes (sext, zext, etc). void setCIRFunctionAttributes(GlobalDecl GD, const CIRGenFunctionInfo &info, - cir::FuncOp func, bool isThunk); + cir::CIRCallableOpInterface func, bool isThunk); /// Set the CIR function attributes which only apply to a function /// definition. void setCIRFunctionAttributesForDefinition(const Decl *decl, - cir::FuncOp func); + cir::CIRCallableOpInterface func); void emitGlobalDefinition(clang::GlobalDecl D, mlir::Operation *Op = nullptr); void emitGlobalFunctionDefinition(clang::GlobalDecl D, mlir::Operation *Op); @@ -814,7 +814,7 @@ class CIRGenModule : public CIRGenTypeCache { // Produce code for this constructor/destructor. This method doesn't try to // apply any ABI rules about which other constructors/destructors are needed // or if they are alias to each other. - cir::FuncOp codegenCXXStructor(clang::GlobalDecl GD); + cir::CIRCallableOpInterface codegenCXXStructor(clang::GlobalDecl GD); bool lookupRepresentativeDecl(llvm::StringRef MangledName, clang::GlobalDecl &Result) const; @@ -839,7 +839,7 @@ class CIRGenModule : public CIRGenTypeCache { cir::GlobalLinkageKind getCIRLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable); - void setFunctionLinkage(GlobalDecl GD, cir::FuncOp f) { + void setFunctionLinkage(GlobalDecl GD, cir::CIRCallableOpInterface f) { auto L = getFunctionLinkage(GD); f.setLinkageAttr(cir::GlobalLinkageKindAttr::get(&getMLIRContext(), L)); mlir::SymbolTable::setSymbolVisibility(f, @@ -854,11 +854,15 @@ class CIRGenModule : public CIRGenTypeCache { mlir::Location getLocForFunction(const clang::FunctionDecl *FD); void ReplaceUsesOfNonProtoTypeWithRealFunction(mlir::Operation *Old, - cir::FuncOp NewFn); + cir::CIRCallableOpInterface NewFn); + cir::AliasOp createCIRAliasFunction(mlir::Location loc, llvm::StringRef name, + cir::FuncType Ty, StringRef aliasee, + cir::GlobalLinkageKind linkage, + const clang::FunctionDecl *FD); // TODO: CodeGen also passes an AttributeList here. We'll have to match that // in CIR - cir::FuncOp + cir::CIRCallableOpInterface GetOrCreateCIRFunction(llvm::StringRef MangledName, mlir::Type Ty, clang::GlobalDecl D, bool ForVTable, bool DontDefer = false, bool IsThunk = false, @@ -866,11 +870,11 @@ class CIRGenModule : public CIRGenTypeCache { mlir::ArrayAttr ExtraAttrs = {}); // Effectively create the CIR instruction, properly handling insertion // points. - cir::FuncOp createCIRFunction(mlir::Location loc, llvm::StringRef name, + cir::CIRCallableOpInterface createCIRFunction(mlir::Location loc, llvm::StringRef name, cir::FuncType Ty, const clang::FunctionDecl *FD); - cir::FuncOp createRuntimeFunction(cir::FuncType Ty, llvm::StringRef Name, + cir::CIRCallableOpInterface createRuntimeFunction(cir::FuncType Ty, llvm::StringRef Name, mlir::ArrayAttr = {}, bool Local = false, bool AssumeConvergent = false); @@ -886,7 +890,7 @@ class CIRGenModule : public CIRGenTypeCache { /// Given a builtin id for a function like "__builtin_fabsf", return a /// Function* for "fabsf". - cir::FuncOp getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); + cir::CIRCallableOpInterface getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); /// Emit a general error that something can't be done. void Error(SourceLocation loc, llvm::StringRef error); @@ -929,7 +933,7 @@ class CIRGenModule : public CIRGenTypeCache { /// \param FN is a pointer to IR function being generated. /// \param FD is a pointer to function declaration if any. /// \param CGF is a pointer to CIRGenFunction that generates this function. - void genKernelArgMetadata(cir::FuncOp FN, const FunctionDecl *FD = nullptr, + void genKernelArgMetadata(cir::CIRCallableOpInterface FN, const FunctionDecl *FD = nullptr, CIRGenFunction *CGF = nullptr); /// Emits OpenCL specific Metadata e.g. OpenCL version. diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenCL.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenCL.cpp index d0e8575dc827..b0abc99d5f54 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenCL.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenCL.cpp @@ -41,7 +41,7 @@ static unsigned ArgInfoAddressSpace(LangAS AS) { } } -void CIRGenModule::genKernelArgMetadata(cir::FuncOp Fn, const FunctionDecl *FD, +void CIRGenModule::genKernelArgMetadata(cir::CIRCallableOpInterface Fn, const FunctionDecl *FD, CIRGenFunction *CGF) { assert(((FD && CGF) || (!FD && !CGF)) && "Incorrect use - FD and CGF should either be both null or not!"); @@ -187,7 +187,7 @@ void CIRGenModule::genKernelArgMetadata(cir::FuncOp Fn, const FunctionDecl *FD, } void CIRGenFunction::emitKernelMetadata(const FunctionDecl *FD, - cir::FuncOp Fn) { + cir::CIRCallableOpInterface Fn) { if (!(FD->hasAttr() && DeviceKernelAttr::isOpenCLSpelling(FD->getAttr())) && !FD->hasAttr()) return; diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index 3619fcaf7a1b..9b9053df0302 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -224,7 +224,7 @@ void CIRGenVTables::addVTableComponent(ConstantArrayBuilder &builder, llvm_unreachable("NYI"); } - auto getSpecialVirtualFn = [&](StringRef name) -> cir::FuncOp { + auto getSpecialVirtualFn = [&](StringRef name) -> cir::CIRCallableOpInterface { // FIXME(PR43094): When merging comdat groups, lld can select a local // symbol as the signature symbol even though it cannot be accessed // outside that symbol's TU. The relative vtables ABI would make @@ -243,13 +243,13 @@ void CIRGenVTables::addVTableComponent(ConstantArrayBuilder &builder, cir::FuncType fnTy = CGM.getBuilder().getFuncType({}, CGM.getBuilder().getVoidTy()); - cir::FuncOp fnPtr = CGM.createRuntimeFunction(fnTy, name); + cir::CIRCallableOpInterface fnPtr = CGM.createRuntimeFunction(fnTy, name); // LLVM codegen handles unnamedAddr assert(!cir::MissingFeatures::unnamedAddr()); return fnPtr; }; - cir::FuncOp fnPtr; + cir::CIRCallableOpInterface fnPtr; if (cast(GD.getDecl())->isPureVirtual()) { // Pure virtual member functions. if (!PureVirtualFn) diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h index 451ea2cbec4f..89f301d482c2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.h +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h @@ -52,10 +52,10 @@ class CIRGenVTables { SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; /// Cache for the pure virtual member call function. - cir::FuncOp PureVirtualFn = nullptr; + cir::CIRCallableOpInterface PureVirtualFn = nullptr; /// Cache for the deleted virtual member call function. - cir::FuncOp DeletedVirtualFn = nullptr; + cir::CIRCallableOpInterface DeletedVirtualFn = nullptr; void addVTableComponent(ConstantArrayBuilder &builder, const VTableLayout &layout, unsigned componentIndex, diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index b499796c00b4..badf43c8cb2f 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2460,14 +2460,48 @@ LogicalResult cir::VTTAddrPointOp::verify() { << resTy << "', but provided result type is '" << resultType << "'"; return success(); } +/// Returns the name used for the linkage attribute. This *must* correspond to +/// the name of the attribute in ODS. +static llvm::StringRef getLinkageAttrNameString() { return "linkage"; } +//===----------------------------------------------------------------------===// +// AliasOp +//===----------------------------------------------------------------------===// +void cir::AliasOp::build(OpBuilder &builder, OperationState &result, + llvm::StringRef name, cir::FuncType type, + llvm::StringRef aliasee, + GlobalLinkageKind linkage, CallingConv callingConv, + ArrayRef attrs, + ArrayRef argAttrs) { + result.addRegion(); + result.addAttribute(SymbolTable::getSymbolAttrName(), + builder.getStringAttr(name)); + result.addAttribute(getFunctionTypeAttrName(result.name), + TypeAttr::get(type)); + result.addAttribute(getAliaseeAttrName(result.name), + FlatSymbolRefAttr::get(builder.getContext(), aliasee)); + result.addAttribute(getExtraAttrsAttrName(result.name), + ExtraFuncAttributesAttr::get(builder.getDictionaryAttr({}))); + result.addAttribute( + getLinkageAttrNameString(), + GlobalLinkageKindAttr::get(builder.getContext(), linkage)); + result.addAttribute(getCallingConvAttrName(result.name), + CallingConvAttr::get(builder.getContext(), callingConv)); + result.addAttribute(getGlobalVisibilityAttrName(result.name), + cir::VisibilityAttr::get(builder.getContext())); + + result.attributes.append(attrs.begin(), attrs.end()); + if (argAttrs.empty()) + return; + + call_interface_impl::addArgAndResultAttrs( + builder, result, argAttrs, ArrayRef{}, + getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name)); +} //===----------------------------------------------------------------------===// // FuncOp //===----------------------------------------------------------------------===// -/// Returns the name used for the linkage attribute. This *must* correspond to -/// the name of the attribute in ODS. -static llvm::StringRef getLinkageAttrNameString() { return "linkage"; } void cir::FuncOp::build(OpBuilder &builder, OperationState &result, llvm::StringRef name, cir::FuncType type, @@ -2951,7 +2985,7 @@ verifyCallCommInSymbolUses(Operation *op, SymbolTableCollection &symbolTable) { if (!fnAttr) return success(); - cir::FuncOp fn = symbolTable.lookupNearestSymbolFrom(op, fnAttr); + cir::CIRCallableOpInterface fn = symbolTable.lookupNearestSymbolFrom(op, fnAttr); if (!fn) return op->emitOpError() << "'" << fnAttr.getValue() << "' does not reference a valid function"; diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 5c27762bdfe3..b10a99b9621e 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) special_member<#cir.cxx_ctor> alias(@_ZN1BC2Ev) +// CHECK: "cir.alias"() <{aliasee = @_ZN1BC2Ev, calling_conv = 1 : i32, extra_attrs = #fn_attr1, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1BC1Ev"}> diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index 8fb3dfdae335..dd30b3f4344a 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -37,7 +37,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) +// CIR: "cir.alias"() <{aliasee = @_ZN1BD2Ev, calling_conv = 1 : i32, extra_attrs = #fn_attr2, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1BD1Ev"}> // Deleting dtor: defers to the complete dtor. // LLVM: define{{.*}} void @_ZN1BD0Ev(ptr @@ -46,11 +46,11 @@ struct B : A { // (aliases from C) // CIR: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) +// CIR: "cir.alias"() <{aliasee = @_ZN1CD2Ev, calling_conv = 1 : i32, extra_attrs = #fn_attr2, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1CD1Ev"}> // CIR_O1-NOT: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) -// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) +// CIR_O1: "cir.alias"() <{aliasee = @_ZN1BD2Ev, calling_conv = 1 : i32, extra_attrs = #fn_attr1, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1CD2Ev"}> ({ +// CIR_O1: "cir.alias"() <{aliasee = @_ZN1CD2Ev, calling_conv = 1 : i32, extra_attrs = #fn_attr1, function_type = !cir.func<(!cir.ptr)>, global_visibility = #cir, linkage = 0 : i32, sym_name = "_ZN1CD1Ev"}> ({ // FIXME: LLVM output should be: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: define dso_local void @_ZN1CD2Ev(ptr