Author: John McCall Date: 2020-05-16T14:44:54-04:00 New Revision: 32870a84d9a40ea682e22a24b5f0d1a218c3b062
URL: https://github.com/llvm/llvm-project/commit/32870a84d9a40ea682e22a24b5f0d1a218c3b062 DIFF: https://github.com/llvm/llvm-project/commit/32870a84d9a40ea682e22a24b5f0d1a218c3b062.diff LOG: Expose IRGen API to add the default IR attributes to a function definition. I've also made a stab at imposing some more order on where and how we add attributes; this part should be NFC. I wasn't sure whether the CUDA use case for libdevice should propagate CPU/features attributes, so there's a bit of unnecessary duplication. Added: Modified: clang/include/clang/CodeGen/CodeGenABITypes.h clang/lib/CodeGen/CGCall.cpp clang/lib/CodeGen/CodeGenABITypes.cpp clang/lib/CodeGen/CodeGenAction.cpp clang/lib/CodeGen/CodeGenModule.h Removed: ################################################################################ diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h index 5f4af7fd2a36..255e1603509e 100644 --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -28,6 +28,7 @@ #include "clang/CodeGen/CGFunctionInfo.h" namespace llvm { +class AttrBuilder; class Constant; class DataLayout; class Module; @@ -86,6 +87,25 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); unsigned getLLVMFieldNumber(CodeGenModule &CGM, const RecordDecl *RD, const FieldDecl *FD); +/// Given the language and code-generation options that Clang was configured +/// with, set the default LLVM IR attributes for a function definition. +/// The attributes set here are mostly global target-configuration and +/// pipeline-configuration options like the target CPU, variant stack +/// rules, whether to optimize for size, and so on. This is useful for +/// frontends (such as Swift) that generally intend to interoperate with +/// C code and rely on Clang's target configuration logic. +/// +/// As a general rule, this function assumes that meaningful attributes +/// haven't already been added to the builder. It won't intentionally +/// displace any existing attributes, but it also won't check to avoid +/// overwriting them. Callers should generally apply customizations after +/// making this call. +/// +/// This function assumes that the caller is not defining a function that +/// requires special no-builtin treatment. +void addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM, + llvm::AttrBuilder &attrs); + /// Returns the default constructor for a C struct with non-trivially copyable /// fields, generating it if necessary. The returned function uses the `cdecl` /// calling convention, returns void, and takes a single argument that is a diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 068d053d17cc..b8bd8a780e50 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1700,8 +1700,9 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } -void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, - bool AttrOnCallSite, +void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, + bool HasOptnone, + bool AttrOnCallSite, llvm::AttrBuilder &FuncAttrs) { // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed. if (!HasOptnone) { @@ -1796,6 +1797,8 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute("stackrealign"); if (CodeGenOpts.Backchain) FuncAttrs.addAttribute("backchain"); + if (CodeGenOpts.EnableSegmentedStacks) + FuncAttrs.addAttribute("split-stack"); if (CodeGenOpts.SpeculativeLoadHardening) FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); @@ -1822,13 +1825,21 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, } } -void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) { +void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) { llvm::AttrBuilder FuncAttrs; - ConstructDefaultFnAttrList(F.getName(), F.hasOptNone(), - /* AttrOnCallSite = */ false, FuncAttrs); + getDefaultFunctionAttributes(F.getName(), F.hasOptNone(), + /* AttrOnCallSite = */ false, FuncAttrs); + // TODO: call GetCPUAndFeaturesAttributes? F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); } +void CodeGenModule::addDefaultFunctionDefinitionAttributes( + llvm::AttrBuilder &attrs) { + getDefaultFunctionAttributes(/*function name*/ "", /*optnone*/ false, + /*for call*/ false, attrs); + GetCPUAndFeaturesAttributes(GlobalDecl(), attrs); +} + static void addNoBuiltinAttributes(llvm::AttrBuilder &FuncAttrs, const LangOptions &LangOpts, const NoBuiltinAttr *NBA = nullptr) { @@ -1865,29 +1876,49 @@ static void addNoBuiltinAttributes(llvm::AttrBuilder &FuncAttrs, llvm::for_each(NBA->builtinNames(), AddNoBuiltinAttr); } +/// Construct the IR attribute list of a function or call. +/// +/// When adding an attribute, please consider where it should be handled: +/// +/// - getDefaultFunctionAttributes is for attributes that are essentially +/// part of the global target configuration (but perhaps can be +/// overridden on a per-function basis). Adding attributes there +/// will cause them to also be set in frontends that build on Clang's +/// target-configuration logic, as well as for code defined in library +/// modules such as CUDA's libdevice. +/// +/// - ConstructAttributeList builds on top of getDefaultFunctionAttributes +/// and adds declaration-specific, convention-specific, and +/// frontend-specific logic. The last is of particular importance: +/// attributes that restrict how the frontend generates code must be +/// added here rather than getDefaultFunctionAttributes. +/// void CodeGenModule::ConstructAttributeList( StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo, llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) { llvm::AttrBuilder FuncAttrs; llvm::AttrBuilder RetAttrs; + // Collect function IR attributes from the CC lowering. + // We'll collect the paramete and result attributes later. CallingConv = FI.getEffectiveCallingConvention(); if (FI.isNoReturn()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); - if (FI.isCmseNSCall()) FuncAttrs.addAttribute("cmse_nonsecure_call"); - // If we have information about the function prototype, we can learn - // attributes from there. + // Collect function IR attributes from the callee prototype if we have one. AddAttributesFromFunctionProtoType(getContext(), FuncAttrs, CalleeInfo.getCalleeFunctionProtoType()); const Decl *TargetDecl = CalleeInfo.getCalleeDecl().getDecl(); bool HasOptnone = false; - // The NoBuiltinAttr attached to a TargetDecl (only allowed on FunctionDecls). + // The NoBuiltinAttr attached to the target FunctionDecl. const NoBuiltinAttr *NBA = nullptr; + + // Collect function IR attributes based on declaration-specific + // information. // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) @@ -1953,6 +1984,21 @@ void CodeGenModule::ConstructAttributeList( FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(), NumElemsParam); } + + if (TargetDecl->hasAttr<OpenCLKernelAttr>()) { + if (getLangOpts().OpenCLVersion <= 120) { + // OpenCL v1.2 Work groups are always uniform + FuncAttrs.addAttribute("uniform-work-group-size", "true"); + } else { + // OpenCL v2.0 Work groups may be whether uniform or not. + // '-cl-uniform-work-group-size' compile option gets a hint + // to the compiler that the global work-size be a multiple of + // the work-group size specified to clEnqueueNDRangeKernel + // (i.e. work groups are uniform). + FuncAttrs.addAttribute("uniform-work-group-size", + llvm::toStringRef(CodeGenOpts.UniformWGSize)); + } + } } // Attach "no-builtins" attributes to: @@ -1963,71 +2009,68 @@ void CodeGenModule::ConstructAttributeList( // * FunctionDecl attributes: __attribute__((no_builtin(...))) addNoBuiltinAttributes(FuncAttrs, getLangOpts(), NBA); - ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs); + // Collect function IR attributes based on global settiings. + getDefaultFunctionAttributes(Name, HasOptnone, AttrOnCallSite, FuncAttrs); - // This must run after constructing the default function attribute list - // to ensure that the speculative load hardening attribute is removed - // in the case where the -mspeculative-load-hardening flag was passed. + // Override some default IR attributes based on declaration-specific + // information. if (TargetDecl) { if (TargetDecl->hasAttr<NoSpeculativeLoadHardeningAttr>()) FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening); if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>()) FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); - } - - if (CodeGenOpts.EnableSegmentedStacks && - !(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>())) - FuncAttrs.addAttribute("split-stack"); - - // Add NonLazyBind attribute to function declarations when -fno-plt - // is used. - if (TargetDecl && CodeGenOpts.NoPLT) { - if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { - if (!Fn->isDefined() && !AttrOnCallSite) { - FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind); + if (TargetDecl->hasAttr<NoSplitStackAttr>()) + FuncAttrs.removeAttribute("split-stack"); + + // Add NonLazyBind attribute to function declarations when -fno-plt + // is used. + // FIXME: what if we just haven't processed the function definition + // yet, or if it's an external definition like C99 inline? + if (CodeGenOpts.NoPLT) { + if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { + if (!Fn->isDefined() && !AttrOnCallSite) { + FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind); + } } } } - if (TargetDecl && TargetDecl->hasAttr<OpenCLKernelAttr>()) { - if (getLangOpts().OpenCLVersion <= 120) { - // OpenCL v1.2 Work groups are always uniform - FuncAttrs.addAttribute("uniform-work-group-size", "true"); - } else { - // OpenCL v2.0 Work groups may be whether uniform or not. - // '-cl-uniform-work-group-size' compile option gets a hint - // to the compiler that the global work-size be a multiple of - // the work-group size specified to clEnqueueNDRangeKernel - // (i.e. work groups are uniform). - FuncAttrs.addAttribute("uniform-work-group-size", - llvm::toStringRef(CodeGenOpts.UniformWGSize)); - } - } - + // Collect non-call-site function IR attributes from declaration-specific + // information. if (!AttrOnCallSite) { if (TargetDecl && TargetDecl->hasAttr<CmseNSEntryAttr>()) FuncAttrs.addAttribute("cmse_nonsecure_entry"); - bool DisableTailCalls = false; + // Whether tail calls are enabled. + auto shouldDisableTailCalls = [&] { + // Should this be honored in getDefaultFunctionAttributes? + if (CodeGenOpts.DisableTailCalls) + return true; + + if (!TargetDecl) + return false; - if (CodeGenOpts.DisableTailCalls) - DisableTailCalls = true; - else if (TargetDecl) { if (TargetDecl->hasAttr<DisableTailCallsAttr>() || TargetDecl->hasAttr<AnyX86InterruptAttr>()) - DisableTailCalls = true; - else if (CodeGenOpts.NoEscapingBlockTailCalls) { + return true; + + if (CodeGenOpts.NoEscapingBlockTailCalls) { if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl)) if (!BD->doesNotEscape()) - DisableTailCalls = true; + return true; } - } + return false; + }; FuncAttrs.addAttribute("disable-tail-calls", - llvm::toStringRef(DisableTailCalls)); + llvm::toStringRef(shouldDisableTailCalls())); + + // CPU/feature overrides. addDefaultFunctionDefinitionAttributes + // handles these separately to set them based on the global defaults. GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs); } + // Collect attributes from arguments and return values. ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI); QualType RetTy = FI.getReturnType(); diff --git a/clang/lib/CodeGen/CodeGenABITypes.cpp b/clang/lib/CodeGen/CodeGenABITypes.cpp index 6b6a116cf259..fb8600029683 100644 --- a/clang/lib/CodeGen/CodeGenABITypes.cpp +++ b/clang/lib/CodeGen/CodeGenABITypes.cpp @@ -25,6 +25,11 @@ using namespace clang; using namespace CodeGen; +void CodeGen::addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM, + llvm::AttrBuilder &attrs) { + CGM.addDefaultFunctionDefinitionAttributes(attrs); +} + const CGFunctionInfo & CodeGen::arrangeObjCMessageSendSignature(CodeGenModule &CGM, const ObjCMethodDecl *MD, diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index b8ffe343db22..55925110708e 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -246,7 +246,7 @@ namespace clang { for (auto &LM : LinkModules) { if (LM.PropagateAttrs) for (Function &F : *LM.Module) - Gen->CGM().AddDefaultFnAttrs(F); + Gen->CGM().addDefaultFunctionDefinitionAttributes(F); CurLinkModule = LM.Module.get(); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 2408ac3cbf44..370fcecb9f15 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1170,7 +1170,11 @@ class CodeGenModule : public CodeGenTypeCache { /// on the function more conservative. But it's unsafe to call this on a /// function which relies on particular fast-math attributes for correctness. /// It's up to you to ensure that this is safe. - void AddDefaultFnAttrs(llvm::Function &F); + void addDefaultFunctionDefinitionAttributes(llvm::Function &F); + + /// Like the overload taking a `Function &`, but intended specifically + /// for frontends that want to build on Clang's target-configuration logic. + void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs); StringRef getMangledName(GlobalDecl GD); StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); @@ -1532,11 +1536,12 @@ class CodeGenModule : public CodeGenTypeCache { /// function. void SimplifyPersonality(); - /// Helper function for ConstructAttributeList and AddDefaultFnAttrs. - /// Constructs an AttrList for a function with the given properties. - void ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, - bool AttrOnCallSite, - llvm::AttrBuilder &FuncAttrs); + /// Helper function for ConstructAttributeList and + /// addDefaultFunctionDefinitionAttributes. Builds a set of function + /// attributes to add to a function with the given properties. + void getDefaultFunctionAttributes(StringRef Name, bool HasOptnone, + bool AttrOnCallSite, + llvm::AttrBuilder &FuncAttrs); llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map, StringRef Suffix); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits