Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -33,6 +33,7 @@ class AttributeSetNode; class Constant; template struct DenseMapInfo; +class Function; class LLVMContext; class Type; @@ -64,60 +65,8 @@ enum AttrKind { // IR-Level Attributes None, ///< No attributes have been set - Alignment, ///< Alignment of parameter (5 bits) - ///< stored as log2 of alignment with +1 bias - ///< 0 means unaligned (different from align(1)) - AlwaysInline, ///< inline=always - Builtin, ///< Callee is recognized as a builtin, despite - ///< nobuiltin attribute on its declaration. - ByVal, ///< Pass structure by value - InAlloca, ///< Pass structure in an alloca - Cold, ///< Marks function as being in a cold path. - Convergent, ///< Can only be moved to control-equivalent blocks - InlineHint, ///< Source said inlining was desirable - InReg, ///< Force argument to be passed in register - JumpTable, ///< Build jump-instruction tables and replace refs. - MinSize, ///< Function must be optimized for size first - Naked, ///< Naked function - Nest, ///< Nested function static chain - NoAlias, ///< Considered to not alias after call - NoBuiltin, ///< Callee isn't recognized as a builtin - NoCapture, ///< Function creates no aliases of pointer - NoDuplicate, ///< Call cannot be duplicated - NoImplicitFloat, ///< Disable implicit floating point insts - NoInline, ///< inline=never - NonLazyBind, ///< Function is called early and/or - ///< often, so lazy binding isn't worthwhile - NonNull, ///< Pointer is known to be not null - Dereferenceable, ///< Pointer is known to be dereferenceable - DereferenceableOrNull, ///< Pointer is either null or dereferenceable - NoRedZone, ///< Disable redzone - NoReturn, ///< Mark the function as not returning - NoUnwind, ///< Function doesn't unwind stack - OptimizeForSize, ///< opt_size - OptimizeNone, ///< Function must not be optimized. - ReadNone, ///< Function does not access memory - ReadOnly, ///< Function only reads from memory - ArgMemOnly, ///< Funciton can access memory only using pointers - ///< based on its arguments. - Returned, ///< Return value is always equal to this argument - ReturnsTwice, ///< Function can return twice - SExt, ///< Sign extended before/after call - StackAlignment, ///< Alignment of stack for function (3 bits) - ///< stored as log2 of alignment with +1 bias 0 - ///< means unaligned (different from - ///< alignstack=(1)) - StackProtect, ///< Stack protection. - StackProtectReq, ///< Stack protection required. - StackProtectStrong, ///< Strong Stack protection. - SafeStack, ///< Safe Stack protection. - StructRet, ///< Hidden pointer to structure to return - SanitizeAddress, ///< AddressSanitizer is on. - SanitizeThread, ///< ThreadSanitizer is on. - SanitizeMemory, ///< MemorySanitizer is on. - UWTable, ///< Function must be in a unwind table - ZExt, ///< Zero extended before/after call - + #define GET_ATTR_ENUM + #include "llvm/IR/Attributes.inc" EndAttrKinds ///< Sentinal value useful for loops }; private: @@ -572,9 +521,20 @@ namespace AttributeFuncs { +/// \brief Return true if the attributes of the caller and callee are equal. +bool Equal(Attribute CallerAttr, Attribute CalleeAttr); + +/// \brief Return true if the CallerAttr's value is false or attributes of the +/// caller and callee are equal. +bool FalseOrEqual(Attribute CallerAttr, Attribute CalleeAttr); + /// \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); + } // end AttributeFuncs namespace } // end llvm namespace Index: include/llvm/IR/Attributes.td =================================================================== --- /dev/null +++ include/llvm/IR/Attributes.td @@ -0,0 +1,167 @@ +/// Attribute base class. +class Attr { + // String representation of this attribute in the IR. + string AttrString = S; + + // 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(Attribute, Attribute)", where the first + // parameter is the caller's attribute and the second parameter is the + // callee's attribute. It must return false if the attributes of the caller + // and callee are incompatible, and true otherwise. "None" is used if the + // attribute doesn't affect the inlining decision. + string InlineCompatFunc = F; +} + +/// Enum attribute. +class EnumAttr : Attr; + +/// String attribute. +class StrAttr : Attr; + +/// Target-independent enum attributes. + +/// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias. +/// 0 means unaligned (different from align(1)). +def Alignment : EnumAttr<"align", "None">; + +/// inline=always. +def AlwaysInline : EnumAttr<"alwaysinline", "None">; + +/// Funciton can access memory only using pointers based on its arguments. +def ArgMemOnly : EnumAttr<"argmemonly", "None">; + +/// Callee is recognized as a builtin, despite nobuiltin attribute on its +/// declaration. +def Builtin : EnumAttr<"builtin", "None">; + +/// Pass structure by value. +def ByVal : EnumAttr<"byval", "None">; + +/// Marks function as being in a cold path. +def Cold : EnumAttr<"cold", "None">; + +/// Can only be moved to control-equivalent blocks. +def Convergent : EnumAttr<"convergent", "None">; + +/// Pointer is known to be dereferenceable. +def Dereferenceable : EnumAttr<"dereferenceable", "None">; + +/// Pointer is either null or dereferenceable. +def DereferenceableOrNull : EnumAttr<"dereferenceable_or_null", "None">; + +/// Pass structure in an alloca. +def InAlloca : EnumAttr<"inalloca", "None">; + +/// Source said inlining was desirable. +def InlineHint : EnumAttr<"inlinehint", "None">; + +/// Force argument to be passed in register. +def InReg : EnumAttr<"inreg", "None">; + +/// Build jump-instruction tables and replace refs. +def JumpTable : EnumAttr<"jumptable", "None">; + +/// Function must be optimized for size first. +def MinSize : EnumAttr<"minsize", "None">; + +/// Naked function. +def Naked : EnumAttr<"naked", "None">; + +/// Nested function static chain. +def Nest : EnumAttr<"nest", "None">; + +/// Considered to not alias after call. +def NoAlias : EnumAttr<"noalias", "None">; + +/// Callee isn't recognized as a builtin. +def NoBuiltin : EnumAttr<"nobuiltin", "None">; + +/// Function creates no aliases of pointer. +def NoCapture : EnumAttr<"nocapture", "None">; + +/// Call cannot be duplicated. +def NoDuplicate : EnumAttr<"noduplicate", "None">; + +/// Disable implicit floating point insts. +def NoImplicitFloat : EnumAttr<"noimplicitfloat", "None">; + +/// inline=never. +def NoInline : EnumAttr<"noinline", "None">; + +/// Function is called early and/or often, so lazy binding isn't worthwhile. +def NonLazyBind : EnumAttr<"nonlazybind", "None">; + +/// Pointer is known to be not null. +def NonNull : EnumAttr<"nonnull", "None">; + +/// Disable redzone. +def NoRedZone : EnumAttr<"noredzone", "None">; + +/// Mark the function as not returning. +def NoReturn : EnumAttr<"noreturn", "None">; + +/// Function doesn't unwind stack. +def NoUnwind : EnumAttr<"nounwind", "None">; + +/// opt_size. +def OptimizeForSize : EnumAttr<"optsize", "None">; + +/// Function must not be optimized. +def OptimizeNone : EnumAttr<"optnone", "None">; + +/// Function does not access memory. +def ReadNone : EnumAttr<"readnone", "None">; + +/// Function only reads from memory. +def ReadOnly : EnumAttr<"readonly", "None">; + +/// Return value is always equal to this argument. +def Returned : EnumAttr<"returned", "None">; + +/// Function can return twice. +def ReturnsTwice : EnumAttr<"returns_twice", "None">; + +/// Safe Stack protection. +def SafeStack : EnumAttr<"safestack", "None">; + +/// Sign extended before/after call. +def SExt : EnumAttr<"signext", "None">; + +/// Alignment of stack for function (3 bits) stored as log2 of alignment with +/// +1 bias 0 means unaligned (different from alignstack=(1)). +def StackAlignment : EnumAttr<"alignstack", "None">; + +/// Stack protection. +def StackProtect : EnumAttr<"ssp", "None">; + +/// Stack protection required. +def StackProtectReq : EnumAttr<"sspreq", "None">; + +/// Strong Stack protection. +def StackProtectStrong : EnumAttr<"sspstrong", "None">; + +/// Hidden pointer to structure to return. +def StructRet : EnumAttr<"sret", "None">; + +/// AddressSanitizer is on. +def SanitizeAddress : EnumAttr<"sanitize_address", "AttributeFuncs::Equal">; + +/// ThreadSanitizer is on. +def SanitizeThread : EnumAttr<"sanitize_thread", "AttributeFuncs::Equal">; + +/// MemorySanitizer is on. +def SanitizeMemory : EnumAttr<"sanitize_memory", "AttributeFuncs::Equal">; + +/// Function must be in a unwind table. +def UWTable : EnumAttr<"uwtable", "None">; + +/// Zero extended before/after call. +def ZExt : EnumAttr<"zeroext", "None">; + +/// Target-independent string attributes. +def LessPreciseFPMAD : StrAttr<"less-precise-fpmad", + "AttributeFuncs::FalseOrEqual">; +def NoInfsFPMath : StrAttr<"no-infs-fp-math", "AttributeFuncs::FalseOrEqual">; +def NoNansFPMath : StrAttr<"no-nans-fp-math", "AttributeFuncs::FalseOrEqual">; +def UnsafeFPMath : StrAttr<"unsafe-fp-math", "AttributeFuncs::FalseOrEqual">; \ No newline at end of file Index: include/llvm/IR/CMakeLists.txt =================================================================== --- include/llvm/IR/CMakeLists.txt +++ include/llvm/IR/CMakeLists.txt @@ -1,5 +1,6 @@ -set(LLVM_TARGET_DEFINITIONS Intrinsics.td) +set(LLVM_TARGET_DEFINITIONS Attributes.td) +tablegen(LLVM Attributes.inc -gen-attr) +set(LLVM_TARGET_DEFINITIONS Intrinsics.td) tablegen(LLVM Intrinsics.gen -gen-intrinsic) - add_public_tablegen_target(intrinsics_gen) Index: lib/Analysis/IPA/InlineCost.cpp =================================================================== --- lib/Analysis/IPA/InlineCost.cpp +++ lib/Analysis/IPA/InlineCost.cpp @@ -1361,9 +1361,7 @@ 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, Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -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" @@ -1406,3 +1407,22 @@ return Incompatible; } + +bool AttributeFuncs::Equal(Attribute CallerAttr, Attribute CalleeAttr) { + return CallerAttr == CalleeAttr; +} + +bool AttributeFuncs::FalseOrEqual(Attribute CallerAttr, Attribute CalleeAttr) { + StringRef CallerVal = CallerAttr.getValueAsString(); + StringRef CalleeVal = CalleeAttr.getValueAsString(); + + return CallerVal == "false" || CallerVal == CalleeVal; +} + +#define GET_ATTR_COMPAT_FUNC +#include "AttributesCompatFunc.inc" + +bool AttributeFuncs::areInlineCompatible(const Function &Caller, + const Function &Callee) { + return hasCompatibleFnAttrs(Caller, Callee); +} Index: lib/IR/AttributesCompatFunc.td =================================================================== --- /dev/null +++ lib/IR/AttributesCompatFunc.td @@ -0,0 +1 @@ +include "llvm/IR/Attributes.td" Index: lib/IR/CMakeLists.txt =================================================================== --- lib/IR/CMakeLists.txt +++ lib/IR/CMakeLists.txt @@ -1,3 +1,7 @@ +set(LLVM_TARGET_DEFINITIONS AttributesCompatFunc.td) +tablegen(LLVM AttributesCompatFunc.inc -gen-attr) +add_public_tablegen_target(AttributeCompatFuncTableGen) + add_llvm_library(LLVMCore AsmWriter.cpp Attributes.cpp Index: lib/IR/Makefile =================================================================== --- lib/IR/Makefile +++ lib/IR/Makefile @@ -10,14 +10,20 @@ LIBRARYNAME = LLVMCore BUILD_ARCHIVE = 1 -BUILT_SOURCES = $(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen +BUILT_SOURCES = $(PROJ_OBJ_ROOT)/include/llvm/IR/Intrinsics.gen \ + $(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 @@ -28,6 +34,32 @@ $(EchoCmd) Updated Intrinsics.gen because Intrinsics.gen.tmp \ changed significantly. ) +$(ObjDir)/Attributes.inc.tmp: $(ObjDir)/.dir $(ATTRIBUTESTD) $(LLVM_TBLGEN) + $(Echo) Building Attributes.inc.tmp from $(ATTRIBUTESTD) + $(Verb) $(LLVMTableGen) $(call SYSPATH, $(ATTRIBUTESTD)) -o $(call SYSPATH, $@) -gen-attr + +$(ATTRINCFILE): $(ObjDir)/Attributes.inc.tmp $(PROJ_OBJ_ROOT)/include/llvm/IR/.dir + $(Verb) $(CMP) -s $@ $< || ( $(CP) $< $@ && \ + $(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-attr + +$(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 + +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 Index: test/Transforms/Inline/attributes.ll =================================================================== --- test/Transforms/Inline/attributes.ll +++ test/Transforms/Inline/attributes.ll @@ -160,3 +160,33 @@ ; CHECK-NEXT: @test_target_features_callee1 ; CHECK-NEXT: ret i32 } + +define i32 @less-precise-fpmad_callee0(i32 %i) "less-precise-fpmad"="true" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 + ; CHECK-LABEL: @less-precise-fpmad_callee0( + ; CHECK-NEXT: @noattr_callee + ; CHECK-NEXT: ret i32 +} + +define i32 @test_less-precise-fpmad0(i32 %i) "less-precise-fpmad"="false" { + %1 = call i32 @less-precise-fpmad_callee0(i32 %i) + ret i32 %1 + ; CHECK-LABEL: @test_less-precise-fpmad0( + ; CHECK-NOT: @less-precise-fpmad_callee0 +} + +define i32 @less-precise-fpmad_callee1(i32 %i) "less-precise-fpmad"="false" { + %1 = call i32 @noattr_callee(i32 %i) + ret i32 %1 + ; CHECK-LABEL: @less-precise-fpmad_callee1( + ; CHECK-NOT: @noattr_callee +} + +define i32 @test_less-precise-fpmad1(i32 %i) "less-precise-fpmad"="true" { + %1 = call i32 @less-precise-fpmad_callee1(i32 %i) + ret i32 %1 + ; CHECK-LABEL: @test_less-precise-fpmad1( + ; CHECK-NEXT: @less-precise-fpmad_callee1 + ; CHECK-NEXT: ret i32 +} Index: utils/TableGen/Attribute.cpp =================================================================== --- /dev/null +++ utils/TableGen/Attribute.cpp @@ -0,0 +1,103 @@ +//===- Attribute.cpp - Generate attributes --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include +#include +#include +using namespace llvm; + +#define DEBUG_TYPE "attr-enum" + +namespace { + +class Attribute { +public: + Attribute(RecordKeeper &R) : Records(R) {} + void emit(raw_ostream &OS); + +private: + void emitTargetIndependentEnums(raw_ostream &OS); + void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); + + RecordKeeper &Records; +}; + +} // End anonymous namespace. + +static bool isStringAttr(const Record &A) { + return A.isSubClassOf("StrAttr"); +} + +void Attribute::emitTargetIndependentEnums(raw_ostream &OS) { + OS << "#ifdef GET_ATTR_ENUM\n"; + OS << "#undef GET_ATTR_ENUM\n"; + + const std::vector &Attrs = + Records.getAllDerivedDefinitions("Attr"); + + for (auto A : Attrs) + if (!isStringAttr(*A)) + OS << A->getName() << ",\n"; + + OS << "#endif\n"; +} + +static std::string getAttrKey(const Record &A) { + if (isStringAttr(A)) + return '"' + A.getValueAsString("AttrString") + '"'; + return std::string("Attribute::") + A.getName(); +} + +void Attribute::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { + OS << "#ifdef GET_ATTR_COMPAT_FUNC\n"; + OS << "#undef GET_ATTR_COMPAT_FUNC\n"; + + OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n" + << " const Function &Callee) {\n"; + + OS << " Attribute CallerAttr, CalleeAttr;\n\n"; + + const std::vector &Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (const auto *A : Attrs) { + StringRef FuncName = A->getValueAsString("InlineCompatFunc"); + + if (FuncName == "None") + continue; + + OS << " CallerAttr = Caller.getFnAttribute("; + OS << getAttrKey(*A) << ");\n"; + OS << " CalleeAttr = Callee.getFnAttribute("; + OS << getAttrKey(*A) << ");\n\n"; + OS << " if (!" + FuncName + "(CallerAttr, CalleeAttr))\n"; + OS << " return false;\n\n"; + } + + OS << " return true;\n"; + OS << "}\n"; + + OS << "#endif\n"; +} + +void Attribute::emit(raw_ostream &OS) { + emitTargetIndependentEnums(OS); + emitFnAttrCompatCheck(OS, false); +} + +namespace llvm { + +void EmitAttribute(RecordKeeper &RK, raw_ostream &OS) { + Attribute(RK).emit(OS); +} + +} // End llvm namespace. Index: utils/TableGen/CMakeLists.txt =================================================================== --- utils/TableGen/CMakeLists.txt +++ utils/TableGen/CMakeLists.txt @@ -4,6 +4,7 @@ AsmMatcherEmitter.cpp AsmWriterEmitter.cpp AsmWriterInst.cpp + Attribute.cpp CallingConvEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp Index: utils/TableGen/TableGen.cpp =================================================================== --- utils/TableGen/TableGen.cpp +++ utils/TableGen/TableGen.cpp @@ -41,7 +41,8 @@ PrintEnums, PrintSets, GenOptParserDefs, - GenCTags + GenCTags, + GenAttribute }; namespace { @@ -85,6 +86,8 @@ "Generate option definitions"), clEnumValN(GenCTags, "gen-ctags", "Generate ctags-compatible index"), + clEnumValN(GenAttribute, "gen-attr", + "Generate attribute"), clEnumValEnd)); cl::opt @@ -165,6 +168,9 @@ case GenCTags: EmitCTags(Records, OS); break; + case GenAttribute: + EmitAttribute(Records, OS); + break; } return false; Index: utils/TableGen/TableGenBackends.h =================================================================== --- utils/TableGen/TableGenBackends.h +++ utils/TableGen/TableGenBackends.h @@ -78,6 +78,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); void EmitCTags(RecordKeeper &RK, raw_ostream &OS); +void EmitAttribute(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace