[clang] 32870a8 - Expose IRGen API to add the default IR attributes to a function definition.
John McCall via cfe-commits
cfe-commits at lists.llvm.org
Sat May 16 11:49:33 PDT 2020
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);
More information about the cfe-commits
mailing list