Skip to content

Commit 32870a8

Browse files
committed
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.
1 parent 49c9a68 commit 32870a8

File tree

5 files changed

+129
-56
lines changed

5 files changed

+129
-56
lines changed

clang/include/clang/CodeGen/CodeGenABITypes.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "clang/CodeGen/CGFunctionInfo.h"
2929

3030
namespace llvm {
31+
class AttrBuilder;
3132
class Constant;
3233
class DataLayout;
3334
class Module;
@@ -86,6 +87,25 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
8687
unsigned getLLVMFieldNumber(CodeGenModule &CGM,
8788
const RecordDecl *RD, const FieldDecl *FD);
8889

90+
/// Given the language and code-generation options that Clang was configured
91+
/// with, set the default LLVM IR attributes for a function definition.
92+
/// The attributes set here are mostly global target-configuration and
93+
/// pipeline-configuration options like the target CPU, variant stack
94+
/// rules, whether to optimize for size, and so on. This is useful for
95+
/// frontends (such as Swift) that generally intend to interoperate with
96+
/// C code and rely on Clang's target configuration logic.
97+
///
98+
/// As a general rule, this function assumes that meaningful attributes
99+
/// haven't already been added to the builder. It won't intentionally
100+
/// displace any existing attributes, but it also won't check to avoid
101+
/// overwriting them. Callers should generally apply customizations after
102+
/// making this call.
103+
///
104+
/// This function assumes that the caller is not defining a function that
105+
/// requires special no-builtin treatment.
106+
void addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM,
107+
llvm::AttrBuilder &attrs);
108+
89109
/// Returns the default constructor for a C struct with non-trivially copyable
90110
/// fields, generating it if necessary. The returned function uses the `cdecl`
91111
/// calling convention, returns void, and takes a single argument that is a

clang/lib/CodeGen/CGCall.cpp

Lines changed: 92 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,8 +1700,9 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
17001700
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
17011701
}
17021702

1703-
void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
1704-
bool AttrOnCallSite,
1703+
void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
1704+
bool HasOptnone,
1705+
bool AttrOnCallSite,
17051706
llvm::AttrBuilder &FuncAttrs) {
17061707
// OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
17071708
if (!HasOptnone) {
@@ -1796,6 +1797,8 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
17961797
FuncAttrs.addAttribute("stackrealign");
17971798
if (CodeGenOpts.Backchain)
17981799
FuncAttrs.addAttribute("backchain");
1800+
if (CodeGenOpts.EnableSegmentedStacks)
1801+
FuncAttrs.addAttribute("split-stack");
17991802

18001803
if (CodeGenOpts.SpeculativeLoadHardening)
18011804
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
@@ -1822,13 +1825,21 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
18221825
}
18231826
}
18241827

1825-
void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) {
1828+
void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) {
18261829
llvm::AttrBuilder FuncAttrs;
1827-
ConstructDefaultFnAttrList(F.getName(), F.hasOptNone(),
1828-
/* AttrOnCallSite = */ false, FuncAttrs);
1830+
getDefaultFunctionAttributes(F.getName(), F.hasOptNone(),
1831+
/* AttrOnCallSite = */ false, FuncAttrs);
1832+
// TODO: call GetCPUAndFeaturesAttributes?
18291833
F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
18301834
}
18311835

1836+
void CodeGenModule::addDefaultFunctionDefinitionAttributes(
1837+
llvm::AttrBuilder &attrs) {
1838+
getDefaultFunctionAttributes(/*function name*/ "", /*optnone*/ false,
1839+
/*for call*/ false, attrs);
1840+
GetCPUAndFeaturesAttributes(GlobalDecl(), attrs);
1841+
}
1842+
18321843
static void addNoBuiltinAttributes(llvm::AttrBuilder &FuncAttrs,
18331844
const LangOptions &LangOpts,
18341845
const NoBuiltinAttr *NBA = nullptr) {
@@ -1865,29 +1876,49 @@ static void addNoBuiltinAttributes(llvm::AttrBuilder &FuncAttrs,
18651876
llvm::for_each(NBA->builtinNames(), AddNoBuiltinAttr);
18661877
}
18671878

1879+
/// Construct the IR attribute list of a function or call.
1880+
///
1881+
/// When adding an attribute, please consider where it should be handled:
1882+
///
1883+
/// - getDefaultFunctionAttributes is for attributes that are essentially
1884+
/// part of the global target configuration (but perhaps can be
1885+
/// overridden on a per-function basis). Adding attributes there
1886+
/// will cause them to also be set in frontends that build on Clang's
1887+
/// target-configuration logic, as well as for code defined in library
1888+
/// modules such as CUDA's libdevice.
1889+
///
1890+
/// - ConstructAttributeList builds on top of getDefaultFunctionAttributes
1891+
/// and adds declaration-specific, convention-specific, and
1892+
/// frontend-specific logic. The last is of particular importance:
1893+
/// attributes that restrict how the frontend generates code must be
1894+
/// added here rather than getDefaultFunctionAttributes.
1895+
///
18681896
void CodeGenModule::ConstructAttributeList(
18691897
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
18701898
llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) {
18711899
llvm::AttrBuilder FuncAttrs;
18721900
llvm::AttrBuilder RetAttrs;
18731901

1902+
// Collect function IR attributes from the CC lowering.
1903+
// We'll collect the paramete and result attributes later.
18741904
CallingConv = FI.getEffectiveCallingConvention();
18751905
if (FI.isNoReturn())
18761906
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
1877-
18781907
if (FI.isCmseNSCall())
18791908
FuncAttrs.addAttribute("cmse_nonsecure_call");
18801909

1881-
// If we have information about the function prototype, we can learn
1882-
// attributes from there.
1910+
// Collect function IR attributes from the callee prototype if we have one.
18831911
AddAttributesFromFunctionProtoType(getContext(), FuncAttrs,
18841912
CalleeInfo.getCalleeFunctionProtoType());
18851913

18861914
const Decl *TargetDecl = CalleeInfo.getCalleeDecl().getDecl();
18871915

18881916
bool HasOptnone = false;
1889-
// The NoBuiltinAttr attached to a TargetDecl (only allowed on FunctionDecls).
1917+
// The NoBuiltinAttr attached to the target FunctionDecl.
18901918
const NoBuiltinAttr *NBA = nullptr;
1919+
1920+
// Collect function IR attributes based on declaration-specific
1921+
// information.
18911922
// FIXME: handle sseregparm someday...
18921923
if (TargetDecl) {
18931924
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
@@ -1953,6 +1984,21 @@ void CodeGenModule::ConstructAttributeList(
19531984
FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(),
19541985
NumElemsParam);
19551986
}
1987+
1988+
if (TargetDecl->hasAttr<OpenCLKernelAttr>()) {
1989+
if (getLangOpts().OpenCLVersion <= 120) {
1990+
// OpenCL v1.2 Work groups are always uniform
1991+
FuncAttrs.addAttribute("uniform-work-group-size", "true");
1992+
} else {
1993+
// OpenCL v2.0 Work groups may be whether uniform or not.
1994+
// '-cl-uniform-work-group-size' compile option gets a hint
1995+
// to the compiler that the global work-size be a multiple of
1996+
// the work-group size specified to clEnqueueNDRangeKernel
1997+
// (i.e. work groups are uniform).
1998+
FuncAttrs.addAttribute("uniform-work-group-size",
1999+
llvm::toStringRef(CodeGenOpts.UniformWGSize));
2000+
}
2001+
}
19562002
}
19572003

19582004
// Attach "no-builtins" attributes to:
@@ -1963,71 +2009,68 @@ void CodeGenModule::ConstructAttributeList(
19632009
// * FunctionDecl attributes: __attribute__((no_builtin(...)))
19642010
addNoBuiltinAttributes(FuncAttrs, getLangOpts(), NBA);
19652011

1966-
ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
2012+
// Collect function IR attributes based on global settiings.
2013+
getDefaultFunctionAttributes(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
19672014

1968-
// This must run after constructing the default function attribute list
1969-
// to ensure that the speculative load hardening attribute is removed
1970-
// in the case where the -mspeculative-load-hardening flag was passed.
2015+
// Override some default IR attributes based on declaration-specific
2016+
// information.
19712017
if (TargetDecl) {
19722018
if (TargetDecl->hasAttr<NoSpeculativeLoadHardeningAttr>())
19732019
FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening);
19742020
if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
19752021
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
1976-
}
1977-
1978-
if (CodeGenOpts.EnableSegmentedStacks &&
1979-
!(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
1980-
FuncAttrs.addAttribute("split-stack");
1981-
1982-
// Add NonLazyBind attribute to function declarations when -fno-plt
1983-
// is used.
1984-
if (TargetDecl && CodeGenOpts.NoPLT) {
1985-
if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
1986-
if (!Fn->isDefined() && !AttrOnCallSite) {
1987-
FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind);
2022+
if (TargetDecl->hasAttr<NoSplitStackAttr>())
2023+
FuncAttrs.removeAttribute("split-stack");
2024+
2025+
// Add NonLazyBind attribute to function declarations when -fno-plt
2026+
// is used.
2027+
// FIXME: what if we just haven't processed the function definition
2028+
// yet, or if it's an external definition like C99 inline?
2029+
if (CodeGenOpts.NoPLT) {
2030+
if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
2031+
if (!Fn->isDefined() && !AttrOnCallSite) {
2032+
FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind);
2033+
}
19882034
}
19892035
}
19902036
}
19912037

1992-
if (TargetDecl && TargetDecl->hasAttr<OpenCLKernelAttr>()) {
1993-
if (getLangOpts().OpenCLVersion <= 120) {
1994-
// OpenCL v1.2 Work groups are always uniform
1995-
FuncAttrs.addAttribute("uniform-work-group-size", "true");
1996-
} else {
1997-
// OpenCL v2.0 Work groups may be whether uniform or not.
1998-
// '-cl-uniform-work-group-size' compile option gets a hint
1999-
// to the compiler that the global work-size be a multiple of
2000-
// the work-group size specified to clEnqueueNDRangeKernel
2001-
// (i.e. work groups are uniform).
2002-
FuncAttrs.addAttribute("uniform-work-group-size",
2003-
llvm::toStringRef(CodeGenOpts.UniformWGSize));
2004-
}
2005-
}
2006-
2038+
// Collect non-call-site function IR attributes from declaration-specific
2039+
// information.
20072040
if (!AttrOnCallSite) {
20082041
if (TargetDecl && TargetDecl->hasAttr<CmseNSEntryAttr>())
20092042
FuncAttrs.addAttribute("cmse_nonsecure_entry");
20102043

2011-
bool DisableTailCalls = false;
2044+
// Whether tail calls are enabled.
2045+
auto shouldDisableTailCalls = [&] {
2046+
// Should this be honored in getDefaultFunctionAttributes?
2047+
if (CodeGenOpts.DisableTailCalls)
2048+
return true;
2049+
2050+
if (!TargetDecl)
2051+
return false;
20122052

2013-
if (CodeGenOpts.DisableTailCalls)
2014-
DisableTailCalls = true;
2015-
else if (TargetDecl) {
20162053
if (TargetDecl->hasAttr<DisableTailCallsAttr>() ||
20172054
TargetDecl->hasAttr<AnyX86InterruptAttr>())
2018-
DisableTailCalls = true;
2019-
else if (CodeGenOpts.NoEscapingBlockTailCalls) {
2055+
return true;
2056+
2057+
if (CodeGenOpts.NoEscapingBlockTailCalls) {
20202058
if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl))
20212059
if (!BD->doesNotEscape())
2022-
DisableTailCalls = true;
2060+
return true;
20232061
}
2024-
}
20252062

2063+
return false;
2064+
};
20262065
FuncAttrs.addAttribute("disable-tail-calls",
2027-
llvm::toStringRef(DisableTailCalls));
2066+
llvm::toStringRef(shouldDisableTailCalls()));
2067+
2068+
// CPU/feature overrides. addDefaultFunctionDefinitionAttributes
2069+
// handles these separately to set them based on the global defaults.
20282070
GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs);
20292071
}
20302072

2073+
// Collect attributes from arguments and return values.
20312074
ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI);
20322075

20332076
QualType RetTy = FI.getReturnType();

clang/lib/CodeGen/CodeGenABITypes.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
using namespace clang;
2626
using namespace CodeGen;
2727

28+
void CodeGen::addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM,
29+
llvm::AttrBuilder &attrs) {
30+
CGM.addDefaultFunctionDefinitionAttributes(attrs);
31+
}
32+
2833
const CGFunctionInfo &
2934
CodeGen::arrangeObjCMessageSendSignature(CodeGenModule &CGM,
3035
const ObjCMethodDecl *MD,

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ namespace clang {
246246
for (auto &LM : LinkModules) {
247247
if (LM.PropagateAttrs)
248248
for (Function &F : *LM.Module)
249-
Gen->CGM().AddDefaultFnAttrs(F);
249+
Gen->CGM().addDefaultFunctionDefinitionAttributes(F);
250250

251251
CurLinkModule = LM.Module.get();
252252

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,11 @@ class CodeGenModule : public CodeGenTypeCache {
11701170
/// on the function more conservative. But it's unsafe to call this on a
11711171
/// function which relies on particular fast-math attributes for correctness.
11721172
/// It's up to you to ensure that this is safe.
1173-
void AddDefaultFnAttrs(llvm::Function &F);
1173+
void addDefaultFunctionDefinitionAttributes(llvm::Function &F);
1174+
1175+
/// Like the overload taking a `Function &`, but intended specifically
1176+
/// for frontends that want to build on Clang's target-configuration logic.
1177+
void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs);
11741178

11751179
StringRef getMangledName(GlobalDecl GD);
11761180
StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
@@ -1532,11 +1536,12 @@ class CodeGenModule : public CodeGenTypeCache {
15321536
/// function.
15331537
void SimplifyPersonality();
15341538

1535-
/// Helper function for ConstructAttributeList and AddDefaultFnAttrs.
1536-
/// Constructs an AttrList for a function with the given properties.
1537-
void ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
1538-
bool AttrOnCallSite,
1539-
llvm::AttrBuilder &FuncAttrs);
1539+
/// Helper function for ConstructAttributeList and
1540+
/// addDefaultFunctionDefinitionAttributes. Builds a set of function
1541+
/// attributes to add to a function with the given properties.
1542+
void getDefaultFunctionAttributes(StringRef Name, bool HasOptnone,
1543+
bool AttrOnCallSite,
1544+
llvm::AttrBuilder &FuncAttrs);
15401545

15411546
llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
15421547
StringRef Suffix);

0 commit comments

Comments
 (0)