Skip to content

Commit c7dfb76

Browse files
committed
Provide a way to specify inliner's attribute compatibility and merging.
This reapplies r252949. I've changed the type of FuncName to be std::string instead of StringRef in emitFnAttrCompatCheck. Original commit message for r252949: Provide a way to specify inliner's attribute compatibility and merging rules using table-gen. NFC. This commit adds new classes CompatRule and MergeRule to Attributes.td, which are used to generate code to check attribute compatibility and merge attributes of the caller and callee. rdar://problem/19836465 llvm-svn: 252990
1 parent 8bb168b commit c7dfb76

File tree

9 files changed

+230
-45
lines changed

9 files changed

+230
-45
lines changed

llvm/include/llvm/IR/Attributes.h

+8
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class AttributeSetImpl;
3333
class AttributeSetNode;
3434
class Constant;
3535
template<typename T> struct DenseMapInfo;
36+
class Function;
3637
class LLVMContext;
3738
class Type;
3839

@@ -527,6 +528,13 @@ namespace AttributeFuncs {
527528
/// \brief Which attributes cannot be applied to a type.
528529
AttrBuilder typeIncompatible(Type *Ty);
529530

531+
/// \returns Return true if the two functions have compatible target-independent
532+
/// attributes for inlining purposes.
533+
bool areInlineCompatible(const Function &Caller, const Function &Callee);
534+
535+
/// \brief Merge caller's and callee's attributes.
536+
void mergeAttributesForInlining(Function &Caller, const Function &Callee);
537+
530538
} // end AttributeFuncs namespace
531539

532540
} // end llvm namespace

llvm/include/llvm/IR/Attributes.td

+25
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,28 @@ def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">;
158158
def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">;
159159
def NoNansFPMath : StrBoolAttr<"no-nans-fp-math">;
160160
def UnsafeFPMath : StrBoolAttr<"unsafe-fp-math">;
161+
162+
class CompatRule<string F> {
163+
// The name of the function called to check the attribute of the caller and
164+
// callee and decide whether inlining should be allowed. The function's
165+
// signature must match "bool(const Function&, const Function &)", where the
166+
// first parameter is the reference to the caller and the second parameter is
167+
// the reference to the callee. It must return false if the attributes of the
168+
// caller and callee are incompatible, and true otherwise.
169+
string CompatFunc = F;
170+
}
171+
172+
def : CompatRule<"isEqual<SanitizeAddressAttr>">;
173+
def : CompatRule<"isEqual<SanitizeThreadAttr>">;
174+
def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
175+
176+
class MergeRule<string F> {
177+
// The name of the function called to merge the attributes of the caller and
178+
// callee. The function's signature must match
179+
// "void(Function&, const Function &)", where the first parameter is the
180+
// reference to the caller and the second parameter is the reference to the
181+
// callee.
182+
string MergeFunc = F;
183+
}
184+
185+
def : MergeRule<"adjustCallerSSPLevel">;

llvm/lib/Analysis/InlineCost.cpp

+1-10
Original file line numberDiff line numberDiff line change
@@ -1349,22 +1349,13 @@ InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, int Threshold) {
13491349
return getInlineCost(CS, CS.getCalledFunction(), Threshold);
13501350
}
13511351

1352-
/// \brief Test that two functions either have or have not the given attribute
1353-
/// at the same time.
1354-
template<typename AttrKind>
1355-
static bool attributeMatches(Function *F1, Function *F2, AttrKind Attr) {
1356-
return F1->getFnAttribute(Attr) == F2->getFnAttribute(Attr);
1357-
}
1358-
13591352
/// \brief Test that there are no attribute conflicts between Caller and Callee
13601353
/// that prevent inlining.
13611354
static bool functionsHaveCompatibleAttributes(Function *Caller,
13621355
Function *Callee,
13631356
TargetTransformInfo &TTI) {
13641357
return TTI.areInlineCompatible(Caller, Callee) &&
1365-
attributeMatches(Caller, Callee, Attribute::SanitizeAddress) &&
1366-
attributeMatches(Caller, Callee, Attribute::SanitizeMemory) &&
1367-
attributeMatches(Caller, Callee, Attribute::SanitizeThread);
1358+
AttributeFuncs::areInlineCompatible(*Caller, *Callee);
13681359
}
13691360

13701361
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,

llvm/lib/IR/Attributes.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//===----------------------------------------------------------------------===//
1515

1616
#include "llvm/IR/Attributes.h"
17+
#include "llvm/IR/Function.h"
1718
#include "AttributeImpl.h"
1819
#include "LLVMContextImpl.h"
1920
#include "llvm/ADT/STLExtras.h"
@@ -1407,3 +1408,80 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
14071408

14081409
return Incompatible;
14091410
}
1411+
1412+
template<typename AttrClass>
1413+
static bool isEqual(const Function &Caller, const Function &Callee) {
1414+
return Caller.getFnAttribute(AttrClass::Kind) ==
1415+
Callee.getFnAttribute(AttrClass::Kind);
1416+
}
1417+
1418+
/// \brief Compute the logical AND of the attributes of the caller and the
1419+
/// callee.
1420+
///
1421+
/// This function sets the caller's attribute to false if the callee's attribute
1422+
/// is false.
1423+
template<typename AttrClass>
1424+
static void setAND(Function &Caller, const Function &Callee) {
1425+
if (AttrClass::isSet(Caller, AttrClass::Kind) &&
1426+
!AttrClass::isSet(Callee, AttrClass::Kind))
1427+
AttrClass::set(Caller, AttrClass::Kind, false);
1428+
}
1429+
1430+
/// \brief Compute the logical OR of the attributes of the caller and the
1431+
/// callee.
1432+
///
1433+
/// This function sets the caller's attribute to true if the callee's attribute
1434+
/// is true.
1435+
template<typename AttrClass>
1436+
static void setOR(Function &Caller, const Function &Callee) {
1437+
if (!AttrClass::isSet(Caller, AttrClass::Kind) &&
1438+
AttrClass::isSet(Callee, AttrClass::Kind))
1439+
AttrClass::set(Caller, AttrClass::Kind, true);
1440+
}
1441+
1442+
/// \brief If the inlined function had a higher stack protection level than the
1443+
/// calling function, then bump up the caller's stack protection level.
1444+
static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
1445+
// If upgrading the SSP attribute, clear out the old SSP Attributes first.
1446+
// Having multiple SSP attributes doesn't actually hurt, but it adds useless
1447+
// clutter to the IR.
1448+
AttrBuilder B;
1449+
B.addAttribute(Attribute::StackProtect)
1450+
.addAttribute(Attribute::StackProtectStrong)
1451+
.addAttribute(Attribute::StackProtectReq);
1452+
AttributeSet OldSSPAttr = AttributeSet::get(Caller.getContext(),
1453+
AttributeSet::FunctionIndex,
1454+
B);
1455+
1456+
if (Callee.hasFnAttribute(Attribute::SafeStack)) {
1457+
Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
1458+
Caller.addFnAttr(Attribute::SafeStack);
1459+
} else if (Callee.hasFnAttribute(Attribute::StackProtectReq) &&
1460+
!Caller.hasFnAttribute(Attribute::SafeStack)) {
1461+
Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
1462+
Caller.addFnAttr(Attribute::StackProtectReq);
1463+
} else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&
1464+
!Caller.hasFnAttribute(Attribute::SafeStack) &&
1465+
!Caller.hasFnAttribute(Attribute::StackProtectReq)) {
1466+
Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
1467+
Caller.addFnAttr(Attribute::StackProtectStrong);
1468+
} else if (Callee.hasFnAttribute(Attribute::StackProtect) &&
1469+
!Caller.hasFnAttribute(Attribute::SafeStack) &&
1470+
!Caller.hasFnAttribute(Attribute::StackProtectReq) &&
1471+
!Caller.hasFnAttribute(Attribute::StackProtectStrong))
1472+
Caller.addFnAttr(Attribute::StackProtect);
1473+
}
1474+
1475+
#define GET_ATTR_COMPAT_FUNC
1476+
#include "AttributesCompatFunc.inc"
1477+
1478+
bool AttributeFuncs::areInlineCompatible(const Function &Caller,
1479+
const Function &Callee) {
1480+
return hasCompatibleFnAttrs(Caller, Callee);
1481+
}
1482+
1483+
1484+
void AttributeFuncs::mergeAttributesForInlining(Function &Caller,
1485+
const Function &Callee) {
1486+
mergeFnAttrs(Caller, Callee);
1487+
}

llvm/lib/IR/AttributesCompatFunc.td

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include "llvm/IR/Attributes.td"

llvm/lib/IR/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
set(LLVM_TARGET_DEFINITIONS AttributesCompatFunc.td)
2+
tablegen(LLVM AttributesCompatFunc.inc -gen-attrs)
3+
add_public_tablegen_target(AttributeCompatFuncTableGen)
4+
15
add_llvm_library(LLVMCore
26
AsmWriter.cpp
37
Attributes.cpp

llvm/lib/IR/Makefile

+17-1
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ LIBRARYNAME = LLVMCore
1111
BUILD_ARCHIVE = 1
1212

1313
BUILT_SOURCES = $(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen \
14-
$(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc
14+
$(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc \
15+
$(PROJ_OBJ_ROOT)/lib/IR/AttributesCompatFunc.inc
1516

1617
include $(LEVEL)/Makefile.common
1718

1819
GENFILE:=$(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen
1920
ATTRINCFILE:=$(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc
21+
ATTRCOMPATFUNCINCFILE:=$(PROJ_OBJ_ROOT)/lib/IR/AttributesCompatFunc.inc
2022

2123
INTRINSICTD := $(PROJ_SRC_ROOT)/include/llvm/IR/Intrinsics.td
2224
INTRINSICTDS := $(wildcard $(PROJ_SRC_ROOT)/include/llvm/IR/Intrinsics*.td)
2325
ATTRIBUTESTD := $(PROJ_SRC_ROOT)/include/llvm/IR/Attributes.td
26+
ATTRCOMPATFUNCTD := $(PROJ_SRC_ROOT)/lib/IR/AttributesCompatFunc.td
2427

2528
$(ObjDir)/Intrinsics.gen.tmp: $(ObjDir)/.dir $(INTRINSICTDS) $(LLVM_TBLGEN)
2629
$(Echo) Building Intrinsics.gen.tmp from Intrinsics.td
@@ -40,10 +43,23 @@ $(ATTRINCFILE): $(ObjDir)/Attributes.inc.tmp $(PROJ_OBJ_ROOT)/include/llvm/IR/.d
4043
$(EchoCmd) Updated Attributes.inc because Attributes.inc.tmp \
4144
changed significantly. )
4245

46+
$(ObjDir)/AttributesCompatFunc.inc.tmp: $(ObjDir)/.dir $(ATTRCOMPATFUNCTD) $(LLVM_TBLGEN)
47+
$(Echo) Building AttributesCompatFunc.inc.tmp from $(ATTRCOMPATFUNCTD)
48+
$(Verb) $(LLVMTableGen) $(call SYSPATH, $(ATTRCOMPATFUNCTD)) -o $(call SYSPATH, $@) -gen-attrs
49+
50+
$(ATTRCOMPATFUNCINCFILE): $(ObjDir)/AttributesCompatFunc.inc.tmp $(PROJ_OBJ_ROOT)/include/llvm/IR/.dir
51+
$(Verb) $(CMP) -s $@ $< || ( $(CP) $< $@ && \
52+
$(EchoCmd) Updated AttributesCompatFunc.inc because AttributesCompatFunc.inc.tmp \
53+
changed significantly. )
54+
4355
install-local:: $(GENFILE)
4456
$(Echo) Installing $(DESTDIR)$(PROJ_includedir)/llvm/IR/Intrinsics.gen
4557
$(Verb) $(DataInstall) $(GENFILE) $(DESTDIR)$(PROJ_includedir)/llvm/IR/Intrinsics.gen
4658

4759
install-local:: $(ATTRINCFILE)
4860
$(Echo) Installing $(DESTDIR)$(PROJ_includedir)/llvm/IR/Attributes.inc
4961
$(Verb) $(DataInstall) $(ATTRINCFILE) $(DESTDIR)$(PROJ_includedir)/llvm/IR/Attributes.inc
62+
63+
install-local:: $(ATTRCOMPATFUNCINCFILE)
64+
$(Echo) Installing $(DESTDIR)$(PROJ_libdir)/IR/AttributesCompatFunc.inc
65+
$(Verb) $(DataInstall) $(ATTRCOMPATFUNCINCFILE) $(DESTDIR)$(PROJ_libdir)/IR/AttributesCompatFunc.inc

llvm/lib/Transforms/IPO/Inliner.cpp

+1-34
Original file line numberDiff line numberDiff line change
@@ -86,39 +86,6 @@ void Inliner::getAnalysisUsage(AnalysisUsage &AU) const {
8686
typedef DenseMap<ArrayType*, std::vector<AllocaInst*> >
8787
InlinedArrayAllocasTy;
8888

89-
/// \brief If the inlined function had a higher stack protection level than the
90-
/// calling function, then bump up the caller's stack protection level.
91-
static void AdjustCallerSSPLevel(Function *Caller, Function *Callee) {
92-
// If upgrading the SSP attribute, clear out the old SSP Attributes first.
93-
// Having multiple SSP attributes doesn't actually hurt, but it adds useless
94-
// clutter to the IR.
95-
AttrBuilder B;
96-
B.addAttribute(Attribute::StackProtect)
97-
.addAttribute(Attribute::StackProtectStrong)
98-
.addAttribute(Attribute::StackProtectReq);
99-
AttributeSet OldSSPAttr = AttributeSet::get(Caller->getContext(),
100-
AttributeSet::FunctionIndex,
101-
B);
102-
103-
if (Callee->hasFnAttribute(Attribute::SafeStack)) {
104-
Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
105-
Caller->addFnAttr(Attribute::SafeStack);
106-
} else if (Callee->hasFnAttribute(Attribute::StackProtectReq) &&
107-
!Caller->hasFnAttribute(Attribute::SafeStack)) {
108-
Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
109-
Caller->addFnAttr(Attribute::StackProtectReq);
110-
} else if (Callee->hasFnAttribute(Attribute::StackProtectStrong) &&
111-
!Caller->hasFnAttribute(Attribute::SafeStack) &&
112-
!Caller->hasFnAttribute(Attribute::StackProtectReq)) {
113-
Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
114-
Caller->addFnAttr(Attribute::StackProtectStrong);
115-
} else if (Callee->hasFnAttribute(Attribute::StackProtect) &&
116-
!Caller->hasFnAttribute(Attribute::SafeStack) &&
117-
!Caller->hasFnAttribute(Attribute::StackProtectReq) &&
118-
!Caller->hasFnAttribute(Attribute::StackProtectStrong))
119-
Caller->addFnAttr(Attribute::StackProtect);
120-
}
121-
12289
/// If it is possible to inline the specified call site,
12390
/// do so and update the CallGraph for this operation.
12491
///
@@ -146,7 +113,7 @@ static bool InlineCallIfPossible(Pass &P, CallSite CS, InlineFunctionInfo &IFI,
146113
if (!InlineFunction(CS, IFI, &AAR, InsertLifetime))
147114
return false;
148115

149-
AdjustCallerSSPLevel(Caller, Callee);
116+
AttributeFuncs::mergeAttributesForInlining(*Caller, *Callee);
150117

151118
// Look at all of the allocas that we inlined through this call site. If we
152119
// have already inlined other allocas through other calls into this function,

llvm/utils/TableGen/Attributes.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ class Attributes {
2727

2828
private:
2929
void emitTargetIndependentEnums(raw_ostream &OS);
30+
void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
31+
32+
void printEnumAttrClasses(raw_ostream &OS,
33+
const std::vector<Record *> &Records);
34+
void printStrBoolAttrClasses(raw_ostream &OS,
35+
const std::vector<Record *> &Records);
3036

3137
RecordKeeper &Records;
3238
};
@@ -46,8 +52,97 @@ void Attributes::emitTargetIndependentEnums(raw_ostream &OS) {
4652
OS << "#endif\n";
4753
}
4854

55+
void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
56+
OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
57+
OS << "#undef GET_ATTR_COMPAT_FUNC\n";
58+
59+
OS << "struct EnumAttr {\n";
60+
OS << " static bool isSet(const Function &Fn,\n";
61+
OS << " Attribute::AttrKind Kind) {\n";
62+
OS << " return Fn.hasFnAttribute(Kind);\n";
63+
OS << " }\n\n";
64+
OS << " static void set(Function &Fn,\n";
65+
OS << " Attribute::AttrKind Kind, bool Val) {\n";
66+
OS << " if (Val)\n";
67+
OS << " Fn.addFnAttr(Kind);\n";
68+
OS << " else\n";
69+
OS << " Fn.removeFnAttr(Kind);\n";
70+
OS << " }\n";
71+
OS << "};\n\n";
72+
73+
OS << "struct StrBoolAttr {\n";
74+
OS << " static bool isSet(const Function &Fn,\n";
75+
OS << " StringRef Kind) {\n";
76+
OS << " auto A = Fn.getFnAttribute(Kind);\n";
77+
OS << " return A.getValueAsString().equals(\"true\");\n";
78+
OS << " }\n\n";
79+
OS << " static void set(Function &Fn,\n";
80+
OS << " StringRef Kind, bool Val) {\n";
81+
OS << " Fn.addFnAttr(Kind, Val ? \"true\" : \"false\");\n";
82+
OS << " }\n";
83+
OS << "};\n\n";
84+
85+
printEnumAttrClasses(OS ,Records.getAllDerivedDefinitions("EnumAttr"));
86+
printStrBoolAttrClasses(OS , Records.getAllDerivedDefinitions("StrBoolAttr"));
87+
88+
OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
89+
<< " const Function &Callee) {\n";
90+
OS << " bool Ret = true;\n\n";
91+
92+
const std::vector<Record *> &CompatRules =
93+
Records.getAllDerivedDefinitions("CompatRule");
94+
95+
for (auto *Rule : CompatRules) {
96+
std::string FuncName = Rule->getValueAsString("CompatFunc");
97+
OS << " Ret &= " << FuncName << "(Caller, Callee);\n";
98+
}
99+
100+
OS << "\n";
101+
OS << " return Ret;\n";
102+
OS << "}\n\n";
103+
104+
const std::vector<Record *> &MergeRules =
105+
Records.getAllDerivedDefinitions("MergeRule");
106+
OS << "static inline void mergeFnAttrs(Function &Caller,\n"
107+
<< " const Function &Callee) {\n";
108+
109+
for (auto *Rule : MergeRules) {
110+
std::string FuncName = Rule->getValueAsString("MergeFunc");
111+
OS << " " << FuncName << "(Caller, Callee);\n";
112+
}
113+
114+
OS << "}\n\n";
115+
116+
OS << "#endif\n";
117+
}
118+
119+
void Attributes::printEnumAttrClasses(raw_ostream &OS,
120+
const std::vector<Record *> &Records) {
121+
OS << "// EnumAttr classes\n";
122+
for (const auto *R : Records) {
123+
OS << "struct " << R->getName() << "Attr : EnumAttr {\n";
124+
OS << " constexpr static const enum Attribute::AttrKind Kind = ";
125+
OS << "Attribute::" << R->getName() << ";\n";
126+
OS << "};\n";
127+
}
128+
OS << "\n";
129+
}
130+
131+
void Attributes::printStrBoolAttrClasses(raw_ostream &OS,
132+
const std::vector<Record *> &Records) {
133+
OS << "// StrBoolAttr classes\n";
134+
for (const auto *R : Records) {
135+
OS << "struct " << R->getName() << "Attr : StrBoolAttr {\n";
136+
OS << " constexpr static const char * const Kind = \"";
137+
OS << R->getValueAsString("AttrString") << "\";\n";
138+
OS << "};\n";
139+
}
140+
OS << "\n";
141+
}
142+
49143
void Attributes::emit(raw_ostream &OS) {
50144
emitTargetIndependentEnums(OS);
145+
emitFnAttrCompatCheck(OS, false);
51146
}
52147

53148
namespace llvm {

0 commit comments

Comments
 (0)