[llvm] r256277 - Provide a way to specify inliner's attribute compatibility and merging.

Akira Hatanaka via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 22 12:00:05 PST 2015


Author: ahatanak
Date: Tue Dec 22 14:00:05 2015
New Revision: 256277

URL: http://llvm.org/viewvc/llvm-project?rev=256277&view=rev
Log:
Provide a way to specify inliner's attribute compatibility and merging.

This reapplies r252990 and r252949. I've added member function getKind
to the Attr classes which returns the enum or string of the attribute.

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

Modified:
    llvm/trunk/include/llvm/IR/Attributes.h
    llvm/trunk/include/llvm/IR/Attributes.td
    llvm/trunk/lib/Analysis/InlineCost.cpp
    llvm/trunk/lib/IR/Attributes.cpp
    llvm/trunk/lib/IR/CMakeLists.txt
    llvm/trunk/lib/IR/Makefile
    llvm/trunk/lib/Transforms/IPO/Inliner.cpp
    llvm/trunk/utils/TableGen/Attributes.cpp

Modified: llvm/trunk/include/llvm/IR/Attributes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.h?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Attributes.h (original)
+++ llvm/trunk/include/llvm/IR/Attributes.h Tue Dec 22 14:00:05 2015
@@ -33,6 +33,7 @@ class AttributeSetImpl;
 class AttributeSetNode;
 class Constant;
 template<typename T> struct DenseMapInfo;
+class Function;
 class LLVMContext;
 class Type;
 
@@ -532,6 +533,13 @@ namespace AttributeFuncs {
 /// \brief Which attributes cannot be applied to a type.
 AttrBuilder typeIncompatible(Type *Ty);
 
+/// \returns Return true if the two functions have compatible target-independent
+/// attributes for inlining purposes.
+bool areInlineCompatible(const Function &Caller, const Function &Callee);
+
+/// \brief Merge caller's and callee's attributes.
+void mergeAttributesForInlining(Function &Caller, const Function &Callee);
+
 } // end AttributeFuncs namespace
 
 } // end llvm namespace

Modified: llvm/trunk/include/llvm/IR/Attributes.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.td?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Attributes.td (original)
+++ llvm/trunk/include/llvm/IR/Attributes.td Tue Dec 22 14:00:05 2015
@@ -165,3 +165,28 @@ def LessPreciseFPMAD : StrBoolAttr<"less
 def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">;
 def NoNansFPMath : StrBoolAttr<"no-nans-fp-math">;
 def UnsafeFPMath : StrBoolAttr<"unsafe-fp-math">;
+
+class CompatRule<string F> {
+  // The name of the function called to check the attribute of the caller and
+  // callee and decide whether inlining should be allowed. The function's
+  // signature must match "bool(const Function&, const Function &)", where the
+  // first parameter is the reference to the caller and the second parameter is
+  // the reference to the callee. It must return false if the attributes of the
+  // caller and callee are incompatible, and true otherwise.
+  string CompatFunc = F;
+}
+
+def : CompatRule<"isEqual<SanitizeAddressAttr>">;
+def : CompatRule<"isEqual<SanitizeThreadAttr>">;
+def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
+
+class MergeRule<string F> {
+  // The name of the function called to merge the attributes of the caller and
+  // callee. The function's signature must match
+  // "void(Function&, const Function &)", where the first parameter is the
+  // reference to the caller and the second parameter is the reference to the
+  // callee.
+  string MergeFunc = F;
+}
+
+def : MergeRule<"adjustCallerSSPLevel">;

Modified: llvm/trunk/lib/Analysis/InlineCost.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InlineCost.cpp?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InlineCost.cpp (original)
+++ llvm/trunk/lib/Analysis/InlineCost.cpp Tue Dec 22 14:00:05 2015
@@ -1362,9 +1362,7 @@ static bool functionsHaveCompatibleAttri
                                               Function *Callee,
                                               TargetTransformInfo &TTI) {
   return TTI.areInlineCompatible(Caller, Callee) &&
-         attributeMatches(Caller, Callee, Attribute::SanitizeAddress) &&
-         attributeMatches(Caller, Callee, Attribute::SanitizeMemory) &&
-         attributeMatches(Caller, Callee, Attribute::SanitizeThread);
+         AttributeFuncs::areInlineCompatible(*Caller, *Callee);
 }
 
 InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,

Modified: llvm/trunk/lib/IR/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Attributes.cpp (original)
+++ llvm/trunk/lib/IR/Attributes.cpp Tue Dec 22 14:00:05 2015
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/IR/Attributes.h"
+#include "llvm/IR/Function.h"
 #include "AttributeImpl.h"
 #include "LLVMContextImpl.h"
 #include "llvm/ADT/STLExtras.h"
@@ -1431,3 +1432,80 @@ AttrBuilder AttributeFuncs::typeIncompat
 
   return Incompatible;
 }
+
+template<typename AttrClass>
+static bool isEqual(const Function &Caller, const Function &Callee) {
+  return Caller.getFnAttribute(AttrClass::getKind()) ==
+         Callee.getFnAttribute(AttrClass::getKind());
+}
+
+/// \brief Compute the logical AND of the attributes of the caller and the
+/// callee.
+///
+/// This function sets the caller's attribute to false if the callee's attribute
+/// is false.
+template<typename AttrClass>
+static void setAND(Function &Caller, const Function &Callee) {
+  if (AttrClass::isSet(Caller, AttrClass::getKind()) &&
+      !AttrClass::isSet(Callee, AttrClass::getKind()))
+    AttrClass::set(Caller, AttrClass::getKind(), false);
+}
+
+/// \brief Compute the logical OR of the attributes of the caller and the
+/// callee.
+///
+/// This function sets the caller's attribute to true if the callee's attribute
+/// is true.
+template<typename AttrClass>
+static void setOR(Function &Caller, const Function &Callee) {
+  if (!AttrClass::isSet(Caller, AttrClass::getKind()) &&
+      AttrClass::isSet(Callee, AttrClass::getKind()))
+    AttrClass::set(Caller, AttrClass::getKind(), true);
+}
+
+/// \brief If the inlined function had a higher stack protection level than the
+/// calling function, then bump up the caller's stack protection level.
+static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
+  // If upgrading the SSP attribute, clear out the old SSP Attributes first.
+  // Having multiple SSP attributes doesn't actually hurt, but it adds useless
+  // clutter to the IR.
+  AttrBuilder B;
+  B.addAttribute(Attribute::StackProtect)
+    .addAttribute(Attribute::StackProtectStrong)
+    .addAttribute(Attribute::StackProtectReq);
+  AttributeSet OldSSPAttr = AttributeSet::get(Caller.getContext(),
+                                              AttributeSet::FunctionIndex,
+                                              B);
+
+  if (Callee.hasFnAttribute(Attribute::SafeStack)) {
+    Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
+    Caller.addFnAttr(Attribute::SafeStack);
+  } else if (Callee.hasFnAttribute(Attribute::StackProtectReq) &&
+             !Caller.hasFnAttribute(Attribute::SafeStack)) {
+    Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
+    Caller.addFnAttr(Attribute::StackProtectReq);
+  } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&
+             !Caller.hasFnAttribute(Attribute::SafeStack) &&
+             !Caller.hasFnAttribute(Attribute::StackProtectReq)) {
+    Caller.removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
+    Caller.addFnAttr(Attribute::StackProtectStrong);
+  } else if (Callee.hasFnAttribute(Attribute::StackProtect) &&
+             !Caller.hasFnAttribute(Attribute::SafeStack) &&
+             !Caller.hasFnAttribute(Attribute::StackProtectReq) &&
+             !Caller.hasFnAttribute(Attribute::StackProtectStrong))
+    Caller.addFnAttr(Attribute::StackProtect);
+}
+
+#define GET_ATTR_COMPAT_FUNC
+#include "AttributesCompatFunc.inc"
+
+bool AttributeFuncs::areInlineCompatible(const Function &Caller,
+                                         const Function &Callee) {
+  return hasCompatibleFnAttrs(Caller, Callee);
+}
+
+
+void AttributeFuncs::mergeAttributesForInlining(Function &Caller,
+                                                const Function &Callee) {
+  mergeFnAttrs(Caller, Callee);
+}

Modified: llvm/trunk/lib/IR/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/CMakeLists.txt?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/lib/IR/CMakeLists.txt (original)
+++ llvm/trunk/lib/IR/CMakeLists.txt Tue Dec 22 14:00:05 2015
@@ -1,3 +1,7 @@
+set(LLVM_TARGET_DEFINITIONS AttributesCompatFunc.td)
+tablegen(LLVM AttributesCompatFunc.inc -gen-attrs)
+add_public_tablegen_target(AttributeCompatFuncTableGen)
+
 add_llvm_library(LLVMCore
   AsmWriter.cpp
   Attributes.cpp

Modified: llvm/trunk/lib/IR/Makefile
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Makefile?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Makefile (original)
+++ llvm/trunk/lib/IR/Makefile Tue Dec 22 14:00:05 2015
@@ -11,16 +11,19 @@ LIBRARYNAME = LLVMCore
 BUILD_ARCHIVE = 1
 
 BUILT_SOURCES = $(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen \
-		 $(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc
+		 $(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc \
+		 $(PROJ_OBJ_ROOT)/lib/IR/AttributesCompatFunc.inc
 
 include $(LEVEL)/Makefile.common
 
 GENFILE:=$(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen
 ATTRINCFILE:=$(PROJ_OBJ_ROOT)/include/llvm/IR/Attributes.inc
+ATTRCOMPATFUNCINCFILE:=$(PROJ_OBJ_ROOT)/lib/IR/AttributesCompatFunc.inc
 
 INTRINSICTD  := $(PROJ_SRC_ROOT)/include/llvm/IR/Intrinsics.td
 INTRINSICTDS := $(wildcard $(PROJ_SRC_ROOT)/include/llvm/IR/Intrinsics*.td)
 ATTRIBUTESTD  := $(PROJ_SRC_ROOT)/include/llvm/IR/Attributes.td
+ATTRCOMPATFUNCTD  := $(PROJ_SRC_ROOT)/lib/IR/AttributesCompatFunc.td
 
 $(ObjDir)/Intrinsics.gen.tmp: $(ObjDir)/.dir $(INTRINSICTDS) $(LLVM_TBLGEN)
 	$(Echo) Building Intrinsics.gen.tmp from Intrinsics.td
@@ -40,6 +43,15 @@ $(ATTRINCFILE): $(ObjDir)/Attributes.inc
 	  $(EchoCmd) Updated Attributes.inc because Attributes.inc.tmp \
 	    changed significantly. )
 
+$(ObjDir)/AttributesCompatFunc.inc.tmp: $(ObjDir)/.dir $(ATTRCOMPATFUNCTD) $(LLVM_TBLGEN)
+	$(Echo) Building AttributesCompatFunc.inc.tmp from $(ATTRCOMPATFUNCTD)
+	$(Verb) $(LLVMTableGen) $(call SYSPATH, $(ATTRCOMPATFUNCTD)) -o $(call SYSPATH, $@) -gen-attrs
+
+$(ATTRCOMPATFUNCINCFILE): $(ObjDir)/AttributesCompatFunc.inc.tmp $(PROJ_OBJ_ROOT)/include/llvm/IR/.dir
+	$(Verb) $(CMP) -s $@ $< || ( $(CP) $< $@ && \
+	  $(EchoCmd) Updated AttributesCompatFunc.inc because AttributesCompatFunc.inc.tmp \
+	    changed significantly. )
+
 install-local:: $(GENFILE)
 	$(Echo) Installing $(DESTDIR)$(PROJ_includedir)/llvm/IR/Intrinsics.gen
 	$(Verb) $(DataInstall) $(GENFILE) $(DESTDIR)$(PROJ_includedir)/llvm/IR/Intrinsics.gen
@@ -47,3 +59,7 @@ install-local:: $(GENFILE)
 install-local:: $(ATTRINCFILE)
 	$(Echo) Installing $(DESTDIR)$(PROJ_includedir)/llvm/IR/Attributes.inc
 	$(Verb) $(DataInstall) $(ATTRINCFILE) $(DESTDIR)$(PROJ_includedir)/llvm/IR/Attributes.inc
+
+install-local:: $(ATTRCOMPATFUNCINCFILE)
+	$(Echo) Installing $(DESTDIR)$(PROJ_libdir)/IR/AttributesCompatFunc.inc
+	$(Verb) $(DataInstall) $(ATTRCOMPATFUNCINCFILE) $(DESTDIR)$(PROJ_libdir)/IR/AttributesCompatFunc.inc

Modified: llvm/trunk/lib/Transforms/IPO/Inliner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Inliner.cpp?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Inliner.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Inliner.cpp Tue Dec 22 14:00:05 2015
@@ -86,39 +86,6 @@ void Inliner::getAnalysisUsage(AnalysisU
 typedef DenseMap<ArrayType*, std::vector<AllocaInst*> >
 InlinedArrayAllocasTy;
 
-/// \brief If the inlined function had a higher stack protection level than the
-/// calling function, then bump up the caller's stack protection level.
-static void AdjustCallerSSPLevel(Function *Caller, Function *Callee) {
-  // If upgrading the SSP attribute, clear out the old SSP Attributes first.
-  // Having multiple SSP attributes doesn't actually hurt, but it adds useless
-  // clutter to the IR.
-  AttrBuilder B;
-  B.addAttribute(Attribute::StackProtect)
-    .addAttribute(Attribute::StackProtectStrong)
-    .addAttribute(Attribute::StackProtectReq);
-  AttributeSet OldSSPAttr = AttributeSet::get(Caller->getContext(),
-                                              AttributeSet::FunctionIndex,
-                                              B);
-
-  if (Callee->hasFnAttribute(Attribute::SafeStack)) {
-    Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
-    Caller->addFnAttr(Attribute::SafeStack);
-  } else if (Callee->hasFnAttribute(Attribute::StackProtectReq) &&
-             !Caller->hasFnAttribute(Attribute::SafeStack)) {
-    Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
-    Caller->addFnAttr(Attribute::StackProtectReq);
-  } else if (Callee->hasFnAttribute(Attribute::StackProtectStrong) &&
-             !Caller->hasFnAttribute(Attribute::SafeStack) &&
-             !Caller->hasFnAttribute(Attribute::StackProtectReq)) {
-    Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr);
-    Caller->addFnAttr(Attribute::StackProtectStrong);
-  } else if (Callee->hasFnAttribute(Attribute::StackProtect) &&
-             !Caller->hasFnAttribute(Attribute::SafeStack) &&
-             !Caller->hasFnAttribute(Attribute::StackProtectReq) &&
-             !Caller->hasFnAttribute(Attribute::StackProtectStrong))
-    Caller->addFnAttr(Attribute::StackProtect);
-}
-
 /// If it is possible to inline the specified call site,
 /// do so and update the CallGraph for this operation.
 ///
@@ -146,7 +113,7 @@ static bool InlineCallIfPossible(Pass &P
   if (!InlineFunction(CS, IFI, &AAR, InsertLifetime))
     return false;
 
-  AdjustCallerSSPLevel(Caller, Callee);
+  AttributeFuncs::mergeAttributesForInlining(*Caller, *Callee);
 
   // Look at all of the allocas that we inlined through this call site.  If we
   // have already inlined other allocas through other calls into this function,

Modified: llvm/trunk/utils/TableGen/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/Attributes.cpp?rev=256277&r1=256276&r2=256277&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/Attributes.cpp (original)
+++ llvm/trunk/utils/TableGen/Attributes.cpp Tue Dec 22 14:00:05 2015
@@ -27,6 +27,12 @@ public:
 
 private:
   void emitTargetIndependentEnums(raw_ostream &OS);
+  void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
+
+  void printEnumAttrClasses(raw_ostream &OS,
+                            const std::vector<Record *> &Records);
+  void printStrBoolAttrClasses(raw_ostream &OS,
+                               const std::vector<Record *> &Records);
 
   RecordKeeper &Records;
 };
@@ -46,8 +52,99 @@ void Attributes::emitTargetIndependentEn
   OS << "#endif\n";
 }
 
+void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
+  OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
+  OS << "#undef GET_ATTR_COMPAT_FUNC\n";
+
+  OS << "struct EnumAttr {\n";
+  OS << "  static bool isSet(const Function &Fn,\n";
+  OS << "                    Attribute::AttrKind Kind) {\n";
+  OS << "    return Fn.hasFnAttribute(Kind);\n";
+  OS << "  }\n\n";
+  OS << "  static void set(Function &Fn,\n";
+  OS << "                  Attribute::AttrKind Kind, bool Val) {\n";
+  OS << "    if (Val)\n";
+  OS << "      Fn.addFnAttr(Kind);\n";
+  OS << "    else\n";
+  OS << "      Fn.removeFnAttr(Kind);\n";
+  OS << "  }\n";
+  OS << "};\n\n";
+
+  OS << "struct StrBoolAttr {\n";
+  OS << "  static bool isSet(const Function &Fn,\n";
+  OS << "                    StringRef Kind) {\n";
+  OS << "    auto A = Fn.getFnAttribute(Kind);\n";
+  OS << "    return A.getValueAsString().equals(\"true\");\n";
+  OS << "  }\n\n";
+  OS << "  static void set(Function &Fn,\n";
+  OS << "                  StringRef Kind, bool Val) {\n";
+  OS << "    Fn.addFnAttr(Kind, Val ? \"true\" : \"false\");\n";
+  OS << "  }\n";
+  OS << "};\n\n";
+
+  printEnumAttrClasses(OS ,Records.getAllDerivedDefinitions("EnumAttr"));
+  printStrBoolAttrClasses(OS , Records.getAllDerivedDefinitions("StrBoolAttr"));
+
+  OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
+     << "                                        const Function &Callee) {\n";
+  OS << "  bool Ret = true;\n\n";
+
+  std::vector<Record *> CompatRules =
+      Records.getAllDerivedDefinitions("CompatRule");
+
+  for (auto *Rule : CompatRules) {
+    StringRef FuncName = Rule->getValueAsString("CompatFunc");
+    OS << "  Ret &= " << FuncName << "(Caller, Callee);\n";
+  }
+
+  OS << "\n";
+  OS << "  return Ret;\n";
+  OS << "}\n\n";
+
+  std::vector<Record *> MergeRules =
+      Records.getAllDerivedDefinitions("MergeRule");
+  OS << "static inline void mergeFnAttrs(Function &Caller,\n"
+     << "                                const Function &Callee) {\n";
+
+  for (auto *Rule : MergeRules) {
+    StringRef FuncName = Rule->getValueAsString("MergeFunc");
+    OS << "  " << FuncName << "(Caller, Callee);\n";
+  }
+
+  OS << "}\n\n";
+
+  OS << "#endif\n";
+}
+
+void Attributes::printEnumAttrClasses(raw_ostream &OS,
+                                      const std::vector<Record *> &Records) {
+  OS << "// EnumAttr classes\n";
+  for (const auto *R : Records) {
+    OS << "struct " << R->getName() << "Attr : EnumAttr {\n";
+    OS << "  static enum Attribute::AttrKind getKind() {\n";
+    OS << "    return llvm::Attribute::" << R->getName() << ";\n";
+    OS << "  }\n";
+    OS << "};\n";
+  }
+  OS << "\n";
+}
+
+void Attributes::printStrBoolAttrClasses(raw_ostream &OS,
+                                         const std::vector<Record *> &Records) {
+  OS << "// StrBoolAttr classes\n";
+  for (const auto *R : Records) {
+    OS << "struct " << R->getName() << "Attr : StrBoolAttr {\n";
+    OS << "  static const char *getKind() {\n";
+    OS << "    return \"" << R->getValueAsString("AttrString") << "\";\n";
+    OS << "  }\n";
+    OS << "};\n";
+  }
+  OS << "\n";
+}
+
 void Attributes::emit(raw_ostream &OS) {
   emitTargetIndependentEnums(OS);
+  emitFnAttrCompatCheck(OS, false);
 }
 
 namespace llvm {




More information about the llvm-commits mailing list