diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index e2f554019422..d61c5e618605 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -192,11 +192,22 @@ struct MissingFeatures { //-- Missing AST queries static bool recordDeclCanPassInRegisters() { return false; } + static bool funcDeclIsCXXConstructorDecl() { return false; } + static bool funcDeclIsCXXDestructorDecl() { return false; } + static bool funcDeclIsCXXMethodDecl() { return false; } + static bool funcDeclIsInlineBuiltinDeclaration() { return false; } + static bool funcDeclIsReplaceableGlobalAllocationFunction() { return false; } + static bool qualTypeIsReferenceType() { return false; } //-- Missing types static bool vectorType() { return false; } + //-- Missing LLVM attributes + + static bool noReturn() { return false; } + static bool csmeCall() { return false; } + //-- Other missing features // Calls with a static chain pointer argument may be optimized (p.e. freeing diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp index ad35d7835255..9363c7349519 100644 --- a/clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp @@ -82,9 +82,11 @@ struct CallConvLoweringPattern : public OpRewritePattern { } } - // Rewrite function definition. - // FIXME(cir): This is a workaround to avoid an infinite loop in the driver. - rewriter.replaceOp(op, rewriter.clone(*op)); + // TODO(cir): Instead of re-emmiting every load and store, bitcast arguments + // and return values to their ABI-specific counterparts when possible. + if (lowerModule.rewriteFunctionDefinition(op).failed()) + return failure(); + return success(); } }; diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp index 59d736c0574f..85890532e4f9 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp @@ -1,12 +1,18 @@ #include "LowerCall.h" +#include "CIRToCIRArgMapping.h" #include "LowerFunctionInfo.h" +#include "LowerModule.h" #include "LowerTypes.h" #include "clang/CIR/FnInfoOpts.h" +#include "clang/CIR/MissingFeatures.h" +#include "llvm/Support/ErrorHandling.h" using namespace mlir; using namespace mlir::cir; +using ABIArgInfo = ::cir::ABIArgInfo; using FnInfoOpts = ::cir::FnInfoOpts; +using MissingFeatures = ::cir::MissingFeatures; namespace { @@ -44,8 +50,150 @@ arrangeFreeFunctionLikeCall(LowerTypes <, LowerModule &LM, fnType.getInputs(), required); } +/// Adds the formal parameters in FPT to the given prefix. If any parameter in +/// FPT has pass_object_size attrs, then we'll add parameters for those, too. +static void appendParameterTypes(SmallVectorImpl &prefix, FuncType fnTy) { + // Fast path: don't touch param info if we don't need to. + if (/*!fnTy->hasExtParameterInfos()=*/true) { + prefix.append(fnTy.getInputs().begin(), fnTy.getInputs().end()); + return; + } + + assert(MissingFeatures::extParamInfo()); + llvm_unreachable("NYI"); +} + +/// Arrange the LLVM function layout for a value of the given function +/// type, on top of any implicit parameters already stored. +/// +/// \param CGT - Abstraction for lowering CIR types. +/// \param instanceMethod - Whether the function is an instance method. +/// \param prefix - List of implicit parameters to be prepended (e.g. 'this'). +/// \param FTP - ABI-agnostic function type. +static const LowerFunctionInfo & +arrangeCIRFunctionInfo(LowerTypes &CGT, bool instanceMethod, + SmallVectorImpl &prefix, FuncType fnTy) { + assert(!MissingFeatures::extParamInfo()); + RequiredArgs Required = RequiredArgs::forPrototypePlus(fnTy, prefix.size()); + // FIXME: Kill copy. + appendParameterTypes(prefix, fnTy); + assert(!MissingFeatures::qualifiedTypes()); + Type resultType = fnTy.getReturnType(); + + FnInfoOpts opts = + instanceMethod ? FnInfoOpts::IsInstanceMethod : FnInfoOpts::None; + return CGT.arrangeLLVMFunctionInfo(resultType, opts, prefix, Required); +} + } // namespace +/// Update function with ABI-specific attributes. +/// +/// NOTE(cir): Partially copies CodeGenModule::ConstructAttributeList, but +/// focuses on ABI/Target-related attributes. +void LowerModule::constructAttributeList(StringRef Name, + const LowerFunctionInfo &FI, + FuncOp CalleeInfo, FuncOp newFn, + unsigned &CallingConv, + bool AttrOnCallSite, bool IsThunk) { + // Collect function IR attributes from the CC lowering. + // We'll collect the paramete and result attributes later. + // FIXME(cir): Codegen differentiates between CallConv and EffectiveCallConv, + // but I don't think we need to do this here. + CallingConv = FI.getCallingConvention(); + // FIXME(cir): No-return should probably be set in CIRGen (ABI-agnostic). + if (MissingFeatures::noReturn()) + llvm_unreachable("NYI"); + if (MissingFeatures::csmeCall()) + llvm_unreachable("NYI"); + + // TODO(cir): Implement AddAttributesFromFunctionProtoType here. + // TODO(cir): Implement AddAttributesFromOMPAssumes here. + assert(!MissingFeatures::openMP()); + + // TODO(cir): Skipping a bunch of AST queries here. We will need to partially + // implement some of them as this section sets target-specific attributes + // too. + // if (TargetDecl) { + // [...] + // } + + // NOTE(cir): The original code adds default and no-builtin attributes here as + // well. AFAIK, these are ABI/Target-agnostic, so it would be better handled + // in CIRGen. Regardless, I'm leaving this comment here as a heads up. + + // Override some default IR attributes based on declaration-specific + // information. + // NOTE(cir): Skipping another set of AST queries here. + + // Collect attributes from arguments and return values. + CIRToCIRArgMapping IRFunctionArgs(getContext(), FI); + + const ABIArgInfo &RetAI = FI.getReturnInfo(); + + // TODO(cir): No-undef attribute for return values partially depends on + // ABI-specific information. Maybe we should include it here. + + switch (RetAI.getKind()) { + case ABIArgInfo::Ignore: + break; + default: + llvm_unreachable("Missing ABIArgInfo::Kind"); + } + + if (!IsThunk) { + if (MissingFeatures::qualTypeIsReferenceType()) { + llvm_unreachable("NYI"); + } + } + + // Attach attributes to sret. + if (MissingFeatures::sretArgs()) { + llvm_unreachable("sret is NYI"); + } + + // Attach attributes to inalloca arguments. + if (MissingFeatures::inallocaArgs()) { + llvm_unreachable("inalloca is NYI"); + } + + // Apply `nonnull`, `dereferencable(N)` and `align N` to the `this` argument, + // unless this is a thunk function. + // FIXME: fix this properly, https://reviews.llvm.org/D100388 + if (MissingFeatures::funcDeclIsCXXMethodDecl() || + MissingFeatures::inallocaArgs()) { + llvm_unreachable("`this` argument attributes are NYI"); + } + + unsigned ArgNo = 0; + for (LowerFunctionInfo::const_arg_iterator I = FI.arg_begin(), + E = FI.arg_end(); + I != E; ++I, ++ArgNo) { + llvm_unreachable("NYI"); + } + assert(ArgNo == FI.arg_size()); +} + +/// Arrange the argument and result information for the declaration or +/// definition of the given function. +const LowerFunctionInfo &LowerTypes::arrangeFunctionDeclaration(FuncOp fnOp) { + if (MissingFeatures::funcDeclIsCXXMethodDecl()) + llvm_unreachable("NYI"); + + assert(!MissingFeatures::qualifiedTypes()); + FuncType FTy = fnOp.getFunctionType(); + + assert(!MissingFeatures::CUDA()); + + // When declaring a function without a prototype, always use a + // non-variadic type. + if (fnOp.getNoProto()) { + llvm_unreachable("NYI"); + } + + return arrangeFreeFunctionType(FTy); +} + /// Figure out the rules for calling a function with the given formal /// type using the given arguments. The arguments are necessary /// because the function might be unprototyped, in which case it's @@ -57,6 +205,24 @@ LowerTypes::arrangeFreeFunctionCall(const OperandRange args, chainCall); } +/// Arrange the argument and result information for the declaration or +/// definition of the given function. +const LowerFunctionInfo &LowerTypes::arrangeFreeFunctionType(FuncType FTy) { + SmallVector argTypes; + return ::arrangeCIRFunctionInfo(*this, /*instanceMethod=*/false, argTypes, + FTy); +} + +/// Arrange the argument and result information for the declaration or +/// definition of the given function. +const LowerFunctionInfo &LowerTypes::arrangeGlobalDeclaration(FuncOp fnOp) { + if (MissingFeatures::funcDeclIsCXXConstructorDecl() || + MissingFeatures::funcDeclIsCXXDestructorDecl()) + llvm_unreachable("NYI"); + + return arrangeFunctionDeclaration(fnOp); +} + /// Arrange the argument and result information for an abstract value /// of a given function type. This is the method which all of the /// above functions ultimately defer to. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp index ae341dd03f53..edf4dfc7d4b3 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp @@ -23,6 +23,8 @@ #include "clang/CIR/MissingFeatures.h" #include "llvm/Support/ErrorHandling.h" +using ABIArgInfo = ::cir::ABIArgInfo; + namespace mlir { namespace cir { @@ -37,6 +39,110 @@ LowerFunction::LowerFunction(LowerModule &LM, PatternRewriter &rewriter, : Target(LM.getTarget()), rewriter(rewriter), SrcFn(srcFn), callOp(callOp), LM(LM) {} +/// This method has partial parity with CodeGenFunction::EmitFunctionProlog from +/// the original codegen. However, it focuses on the ABI-specific details. On +/// top of that, it is also responsible for rewriting the original function. +LogicalResult +LowerFunction::buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn, + MutableArrayRef Args) { + // NOTE(cir): Skipping naked and implicit-return-zero functions here. These + // are dealt with in CIRGen. + + CIRToCIRArgMapping IRFunctionArgs(LM.getContext(), FI); + assert(Fn.getNumArguments() == IRFunctionArgs.totalIRArgs()); + + // If we're using inalloca, all the memory arguments are GEPs off of the last + // parameter, which is a pointer to the complete memory area. + assert(!::cir::MissingFeatures::inallocaArgs()); + + // Name the struct return parameter. + assert(!::cir::MissingFeatures::sretArgs()); + + // Track if we received the parameter as a pointer (indirect, byval, or + // inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it + // into a local alloca for us. + SmallVector ArgVals; + ArgVals.reserve(Args.size()); + + // Create a pointer value for every parameter declaration. This usually + // entails copying one or more LLVM IR arguments into an alloca. Don't push + // any cleanups or do anything that might unwind. We do that separately, so + // we can push the cleanups in the correct order for the ABI. + assert(FI.arg_size() == Args.size()); + unsigned ArgNo = 0; + LowerFunctionInfo::const_arg_iterator info_it = FI.arg_begin(); + for (MutableArrayRef::const_iterator i = Args.begin(), + e = Args.end(); + i != e; ++i, ++info_it, ++ArgNo) { + llvm_unreachable("NYI"); + } + + if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) { + llvm_unreachable("NYI"); + } else { + // FIXME(cir): In the original codegen, EmitParamDecl is called here. It is + // likely that said function considers ABI details during emission, so we + // migth have to add a counter part here. Currently, it is not needed. + } + + return success(); +} + +LogicalResult LowerFunction::buildFunctionEpilog(const LowerFunctionInfo &FI) { + const ABIArgInfo &RetAI = FI.getReturnInfo(); + + switch (RetAI.getKind()) { + + case ABIArgInfo::Ignore: + break; + + default: + llvm_unreachable("Unhandled ABIArgInfo::Kind"); + } + + return success(); +} + +/// Generate code for a function based on the ABI-specific information. +/// +/// This method has partial parity with CodeGenFunction::GenerateCode, but it +/// focuses on the ABI-specific details. So a lot of codegen stuff is removed. +LogicalResult LowerFunction::generateCode(FuncOp oldFn, FuncOp newFn, + const LowerFunctionInfo &FnInfo) { + assert(newFn && "generating code for null Function"); + auto Args = oldFn.getArguments(); + + // Emit the ABI-specific function prologue. + assert(newFn.empty() && "Function already has a body"); + rewriter.setInsertionPointToEnd(newFn.addEntryBlock()); + if (buildFunctionProlog(FnInfo, newFn, oldFn.getArguments()).failed()) + return failure(); + + // Ensure that old ABI-agnostic arguments uses were replaced. + const auto hasNoUses = [](Value val) { return val.getUses().empty(); }; + assert(std::all_of(Args.begin(), Args.end(), hasNoUses) && "Missing RAUW?"); + + // Migrate function body to new ABI-aware function. + assert(oldFn.getBody().hasOneBlock() && + "Multiple blocks in original function not supported"); + + // Move old function body to new function. + // FIXME(cir): The merge below is not very good: will not work if SrcFn has + // multiple blocks and it mixes the new and old prologues. + rewriter.mergeBlocks(&oldFn.getBody().front(), &newFn.getBody().front(), + newFn.getArguments()); + + // FIXME(cir): What about saving parameters for corotines? Should we do + // something about it in this pass? If the change with the calling + // convention, we might have to handle this here. + + // Emit the standard function epilogue. + if (buildFunctionEpilog(FnInfo).failed()) + return failure(); + + return success(); +} + /// Rewrite a call operation to abide to the ABI calling convention. /// /// FIXME(cir): This method has partial parity to CodeGenFunction's diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.h index 6498bd705288..40cdd39463e6 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.h @@ -53,6 +53,21 @@ class LowerFunction { LowerModule &LM; // Per-module state. + const clang::TargetInfo &getTarget() const { return Target; } + + // Build ABI/Target-specific function prologue. + LogicalResult buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn, + MutableArrayRef Args); + + // Build ABI/Target-specific function epilogue. + LogicalResult buildFunctionEpilog(const LowerFunctionInfo &FI); + + // Parity with CodeGenFunction::GenerateCode. Keep in mind that several + // sections in the original function are focused on codegen unrelated to the + // ABI. Such sections are handled in CIR's codegen, not here. + LogicalResult generateCode(FuncOp oldFn, FuncOp newFn, + const LowerFunctionInfo &FnInfo); + /// Rewrite a call operation to abide to the ABI calling convention. LogicalResult rewriteCallOp(CallOp op, ReturnValueSlot retValSlot = ReturnValueSlot()); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunctionInfo.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunctionInfo.h index ea7174caf6b9..c81335c9985a 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunctionInfo.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunctionInfo.h @@ -37,6 +37,19 @@ class RequiredArgs { RequiredArgs(All_t _) : NumRequired(~0U) {} explicit RequiredArgs(unsigned n) : NumRequired(n) { assert(n != ~0U); } + /// Compute the arguments required by the given formal prototype, + /// given that there may be some additional, non-formal arguments + /// in play. + /// + /// If FD is not null, this will consider pass_object_size params in FD. + static RequiredArgs forPrototypePlus(const FuncType prototype, + unsigned additional) { + if (!prototype.isVarArg()) + return All; + + llvm_unreachable("Variadic function is NYI"); + } + bool allowsOptionalArgs() const { return NumRequired != ~0U; } }; diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp index 28760fea585d..0ec4b589bb41 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp @@ -21,6 +21,8 @@ #include "mlir/Support/LogicalResult.h" #include "llvm/Support/ErrorHandling.h" +using MissingFeatures = ::cir::MissingFeatures; + namespace mlir { namespace cir { @@ -75,11 +77,108 @@ const TargetLoweringInfo &LowerModule::getTargetLoweringInfo() { return *TheTargetCodeGenInfo; } -LogicalResult LowerModule::rewriteGlobalFunctionDefinition(FuncOp op, - LowerModule &state) { +void LowerModule::setCIRFunctionAttributes(FuncOp GD, + const LowerFunctionInfo &Info, + FuncOp F, bool IsThunk) { + unsigned CallingConv; + // NOTE(cir): The method below will update the F function in-place with the + // proper attributes. + constructAttributeList(GD.getName(), Info, GD, F, CallingConv, + /*AttrOnCallSite=*/false, IsThunk); + // TODO(cir): Set Function's calling convention. +} + +/// Set function attributes for a function declaration. +/// +/// This method is based on CodeGenModule::SetFunctionAttributes but it +/// altered to consider only the ABI/Target-related bits. +void LowerModule::setFunctionAttributes(FuncOp oldFn, FuncOp newFn, + bool IsIncompleteFunction, + bool IsThunk) { + + // TODO(cir): There's some special handling from attributes related to LLVM + // intrinsics. Should we do that here as well? + + // Setup target-specific attributes. + if (!IsIncompleteFunction) + setCIRFunctionAttributes(oldFn, getTypes().arrangeGlobalDeclaration(oldFn), + newFn, IsThunk); + + // TODO(cir): Handle attributes for returned "this" objects. + + // NOTE(cir): Skipping some linkage and other global value attributes here as + // it might be better for CIRGen to handle them. + + // TODO(cir): Skipping section attributes here. + + // TODO(cir): Skipping error attributes here. + + // If we plan on emitting this inline builtin, we can't treat it as a builtin. + if (MissingFeatures::funcDeclIsInlineBuiltinDeclaration()) { + llvm_unreachable("NYI"); + } + + if (MissingFeatures::funcDeclIsReplaceableGlobalAllocationFunction()) { + llvm_unreachable("NYI"); + } + + if (MissingFeatures::funcDeclIsCXXConstructorDecl() || + MissingFeatures::funcDeclIsCXXDestructorDecl()) + llvm_unreachable("NYI"); + else if (MissingFeatures::funcDeclIsCXXMethodDecl()) + llvm_unreachable("NYI"); + + // NOTE(cir) Skipping emissions that depend on codegen options, as well as + // sanitizers handling here. Do this in CIRGen. + + if (MissingFeatures::langOpts() && MissingFeatures::openMP()) + llvm_unreachable("NYI"); + + // NOTE(cir): Skipping more things here that depend on codegen options. + + if (MissingFeatures::extParamInfo()) { + llvm_unreachable("NYI"); + } +} + +/// Rewrites an existing function to conform to the ABI. +/// +/// This method is based on CodeGenModule::EmitGlobalFunctionDefinition but it +/// considerably simplified as it tries to remove any CodeGen related code. +LogicalResult LowerModule::rewriteFunctionDefinition(FuncOp op) { mlir::OpBuilder::InsertionGuard guard(rewriter); rewriter.setInsertionPoint(op); - return failure(); + + // Get ABI/target-specific function information. + const LowerFunctionInfo &FI = this->getTypes().arrangeGlobalDeclaration(op); + + // Get ABI/target-specific function type. + FuncType Ty = this->getTypes().getFunctionType(FI); + + // NOTE(cir): Skipping getAddrOfFunction and getOrCreateCIRFunction methods + // here, as they are mostly codegen logic. + + // Create a new function with the ABI-specific types. + FuncOp newFn = cast(rewriter.cloneWithoutRegions(op)); + newFn.setType(Ty); + + // NOTE(cir): The clone above will preserve any existing attributes. If there + // are high-level attributes that ought to be dropped, do it here. + + // Set up ABI-specific function attributes. + setFunctionAttributes(op, newFn, false, /*IsThunk=*/false); + if (MissingFeatures::extParamInfo()) { + llvm_unreachable("ExtraAttrs are NYI"); + } + + if (LowerFunction(*this, rewriter, op, newFn) + .generateCode(op, newFn, FI) + .failed()) + return failure(); + + // Erase original ABI-agnostic function. + rewriter.eraseOp(op); + return success(); } LogicalResult LowerModule::rewriteFunctionCall(CallOp callOp, FuncOp funcOp) { diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h index bb56cb5fef92..74f7ed0bb5ac 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h @@ -64,8 +64,28 @@ class LowerModule { return kind; } + void + constructAttributeList(StringRef Name, const LowerFunctionInfo &FI, + FuncOp CalleeInfo, // TODO(cir): Implement CalleeInfo? + FuncOp newFn, unsigned &CallingConv, + bool AttrOnCallSite, bool IsThunk); + + void setCIRFunctionAttributes(FuncOp GD, const LowerFunctionInfo &Info, + FuncOp F, bool IsThunk); + + /// Set function attributes for a function declaration. + void setFunctionAttributes(FuncOp oldFn, FuncOp newFn, + bool IsIncompleteFunction, bool IsThunk); + + // Create a CIR FuncOp with with the given signature. + FuncOp createCIRFunction( + StringRef MangledName, FuncType Ty, FuncOp D, bool ForVTable, + bool DontDefer = false, bool IsThunk = false, + ArrayRef = {}, // TODO(cir): __attribute__(()) stuff. + bool IsForDefinition = false); + // Rewrite CIR FuncOp to match the target ABI. - LogicalResult rewriteGlobalFunctionDefinition(FuncOp op, LowerModule &state); + LogicalResult rewriteFunctionDefinition(FuncOp op); // Rewrite CIR CallOp to match the target ABI. LogicalResult rewriteFunctionCall(CallOp callOp, FuncOp funcOp); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.h index 941b3d7aeab7..44f0d16b1bd8 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.h @@ -21,6 +21,7 @@ #include "mlir/IR/MLIRContext.h" #include "clang/Basic/Specifiers.h" #include "clang/CIR/Dialect/IR/CIRDataLayout.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/FnInfoOpts.h" namespace mlir { @@ -65,9 +66,14 @@ class LowerTypes { /// Free functions are functions that are compatible with an ordinary /// C function pointer type. + /// FIXME(cir): Does the "free function" concept makes sense here? + const LowerFunctionInfo &arrangeFunctionDeclaration(FuncOp fnOp); const LowerFunctionInfo &arrangeFreeFunctionCall(const OperandRange args, const FuncType fnType, bool chainCall); + const LowerFunctionInfo &arrangeFreeFunctionType(FuncType FTy); + + const LowerFunctionInfo &arrangeGlobalDeclaration(FuncOp fnOp); /// Arrange the argument and result information for an abstract value /// of a given function type. This is the method which all of the