Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -589,6 +589,9 @@ ATTR_KIND_SANITIZE_HWADDRESS = 55, ATTR_KIND_NOCF_CHECK = 56, ATTR_KIND_OPT_FOR_FUZZING = 57, + ATTR_KIND_OPTIMIZE_LESS = 58, + ATTR_KIND_OPTIMIZE_DEFAULT = 59, + ATTR_KIND_OPTIMIZE_AGGRESSIVE = 60, }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -115,12 +115,21 @@ /// Select optimizations for best fuzzing signal. def OptForFuzzing : EnumAttr<"optforfuzzing">; -/// opt_size. +/// Function optimized for size. def OptimizeForSize : EnumAttr<"optsize">; /// Function must not be optimized. def OptimizeNone : EnumAttr<"optnone">; +/// Function optimized at -O1. +def OptimizeLess : EnumAttr<"optless">; + +/// Function optimized at -O2. +def OptimizeDefault : EnumAttr<"optdefault">; + +/// Function optimized at -O3. +def OptimizeAggressive : EnumAttr<"optaggr">; + /// Function does not access memory. def ReadNone : EnumAttr<"readnone">; Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -34,6 +34,7 @@ #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" #include #include @@ -580,6 +581,22 @@ return hasFnAttribute(Attribute::OptimizeForSize) || optForMinSize(); } + CodeGenOpt::Level getCodeGenOptLevel() const { + if (hasFnAttribute(Attribute::OptimizeNone)) + return CodeGenOpt::None; + + if (hasFnAttribute(Attribute::OptimizeLess)) + return CodeGenOpt::Less; + + if (hasFnAttribute(Attribute::OptimizeDefault)) + return CodeGenOpt::Default; + + if (hasFnAttribute(Attribute::OptimizeAggressive)) + return CodeGenOpt::Aggressive; + + return CodeGenOpt::Default; + } + /// copyAttributesFrom - copy all additional attributes (those not needed to /// create a Function) from the Function Src to this one. void copyAttributesFrom(const Function *Src); Index: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ include/llvm/IR/Module.h @@ -232,6 +232,8 @@ /// @returns a string containing the target triple. const std::string &getTargetTriple() const { return TargetTriple; } + CodeGenOpt::Level getCodeGenOptLevel() const; + /// Get the global data context. /// @returns LLVMContext - a container for LLVM's global information LLVMContext &getContext() const { return Context; } Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -652,6 +652,9 @@ KEYWORD(nounwind); KEYWORD(optforfuzzing); KEYWORD(optnone); + KEYWORD(optless); + KEYWORD(optdefault); + KEYWORD(optaggr); KEYWORD(optsize); KEYWORD(readnone); KEYWORD(readonly); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1137,6 +1137,15 @@ case lltok::kw_optforfuzzing: B.addAttribute(Attribute::OptForFuzzing); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; + case lltok::kw_optless: + B.addAttribute(Attribute::OptimizeLess); + break; + case lltok::kw_optdefault: + B.addAttribute(Attribute::OptimizeDefault); + break; + case lltok::kw_optaggr: + B.addAttribute(Attribute::OptimizeAggressive); + break; case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break; case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break; case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break; @@ -1475,6 +1484,9 @@ case lltok::kw_nounwind: case lltok::kw_optforfuzzing: case lltok::kw_optnone: + case lltok::kw_optless: + case lltok::kw_optdefault: + case lltok::kw_optaggr: case lltok::kw_optsize: case lltok::kw_returns_twice: case lltok::kw_sanitize_address: @@ -1570,6 +1582,9 @@ case lltok::kw_nounwind: case lltok::kw_optforfuzzing: case lltok::kw_optnone: + case lltok::kw_optless: + case lltok::kw_optdefault: + case lltok::kw_optaggr: case lltok::kw_optsize: case lltok::kw_returns_twice: case lltok::kw_sanitize_address: Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -203,6 +203,9 @@ kw_nounwind, kw_optforfuzzing, kw_optnone, + kw_optless, + kw_optdefault, + kw_optaggr, kw_optsize, kw_readnone, kw_readonly, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1162,6 +1162,12 @@ case Attribute::SanitizeHWAddress: return 1ULL << 56; case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::OptForFuzzing: return 1ULL << 58; + case Attribute::OptimizeLess: + return 1ULL << 59; + case Attribute::OptimizeDefault: + return 1ULL << 60; + case Attribute::OptimizeAggressive: + return 1ULL << 61; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1350,6 +1356,12 @@ return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; + case bitc::ATTR_KIND_OPTIMIZE_LESS: + return Attribute::OptimizeLess; + case bitc::ATTR_KIND_OPTIMIZE_DEFAULT: + return Attribute::OptimizeDefault; + case bitc::ATTR_KIND_OPTIMIZE_AGGRESSIVE: + return Attribute::OptimizeAggressive; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -648,6 +648,12 @@ return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE; case Attribute::OptimizeNone: return bitc::ATTR_KIND_OPTIMIZE_NONE; + case Attribute::OptimizeLess: + return bitc::ATTR_KIND_OPTIMIZE_LESS; + case Attribute::OptimizeDefault: + return bitc::ATTR_KIND_OPTIMIZE_DEFAULT; + case Attribute::OptimizeAggressive: + return bitc::ATTR_KIND_OPTIMIZE_AGGRESSIVE; case Attribute::ReadNone: return bitc::ATTR_KIND_READ_NONE; case Attribute::ReadOnly: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -311,6 +311,12 @@ return "optnone"; if (hasAttribute(Attribute::OptimizeForSize)) return "optsize"; + if (hasAttribute(Attribute::OptimizeLess)) + return "optless"; + if (hasAttribute(Attribute::OptimizeDefault)) + return "optdefault"; + if (hasAttribute(Attribute::OptimizeAggressive)) + return "optaggr"; if (hasAttribute(Attribute::ReadNone)) return "readnone"; if (hasAttribute(Attribute::ReadOnly)) Index: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ lib/IR/Module.cpp @@ -88,6 +88,22 @@ delete static_cast *>(NamedMDSymTab); } +CodeGenOpt::Level Module::getCodeGenOptLevel() const { + if (FunctionList.empty()) + return CodeGenOpt::Default; + + CodeGenOpt::Level ModuleLevel = CodeGenOpt::None; + for (const Function &F : *this) { + CodeGenOpt::Level Level = F.getCodeGenOptLevel(); + if (ModuleLevel < Level) + ModuleLevel = Level; + + if (ModuleLevel == CodeGenOpt::Aggressive) + break; + } + return ModuleLevel; +} + std::unique_ptr Module::createRNG(const Pass* P) const { SmallString<32> Salt(P->getPassName()); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1432,6 +1432,9 @@ case Attribute::Cold: case Attribute::OptForFuzzing: case Attribute::OptimizeNone: + case Attribute::OptimizeLess: + case Attribute::OptimizeDefault: + case Attribute::OptimizeAggressive: case Attribute::JumpTable: case Attribute::Convergent: case Attribute::ArgMemOnly: @@ -1690,8 +1693,57 @@ Assert(!Attrs.hasFnAttribute(Attribute::MinSize), "Attributes 'minsize and optnone' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeLess), + "Attributes 'optless and optnone' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeDefault), + "Attributes 'optdefault and optnone' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeAggressive), + "Attributes 'optaggr and optnone' are incompatible!", V); + } + + if (Attrs.hasFnAttribute(Attribute::OptimizeLess)) { + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeNone), + "Attributes 'optnone and optless' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeDefault), + "Attributes 'optdefault and optless' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeAggressive), + "Attributes 'optaggr and optless' are incompatible!", V); + } + + if (Attrs.hasFnAttribute(Attribute::OptimizeDefault)) { + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeNone), + "Attributes 'optnone and optdefault' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeLess), + "Attributes 'optless and optdefault' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeAggressive), + "Attributes 'optaggr and optdefault' are incompatible!", V); + } + + if (Attrs.hasFnAttribute(Attribute::OptimizeAggressive)) { + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeNone), + "Attributes 'optnone and optaggr' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeLess), + "Attributes 'optless and optaggr' are incompatible!", V); + + Assert(!Attrs.hasFnAttribute(Attribute::OptimizeDefault), + "Attributes 'optdefault and optaggr' are incompatible!", V); } + // Assert(Attrs.hasFnAttribute(Attribute::OptimizeNone) || + // Attrs.hasFnAttribute(Attribute::OptimizeLess) || + // Attrs.hasFnAttribute(Attribute::OptimizeDefault) || + // Attrs.hasFnAttribute(Attribute::OptimizeAggressive), + // "Expected one of 'optnone, optless, optdefault or optaggr' on + // function!", V); + if (Attrs.hasFnAttribute(Attribute::JumpTable)) { const GlobalValue *GV = cast(V); Assert(GV->hasGlobalUnnamedAddr(), Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -54,6 +54,11 @@ DumpThinCGSCCs("dump-thin-cg-sccs", cl::init(false), cl::Hidden, cl::desc("Dump the SCCs in the ThinLTO index's callgraph")); +static cl::opt CGOptLevel( + "cg-opt-level", + cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"), + cl::init('2')); + // The values are (type identifier, summary) pairs. typedef DenseMap< GlobalValue::GUID, @@ -801,6 +806,29 @@ /*LivenessFromIndex=*/true)) return Err; + // Update the code generation optimization level based on function level + // attributes (or the command-line option, if specified). + if (CGOptLevel.getNumOccurrences() == 0) + Conf.CGOptLevel = RegularLTO.CombinedModule->getCodeGenOptLevel(); + else { + switch (CGOptLevel) { + case '0': + Conf.CGOptLevel = CodeGenOpt::None; + break; + case '1': + Conf.CGOptLevel = CodeGenOpt::Less; + break; + case '2': + Conf.CGOptLevel = CodeGenOpt::Default; + break; + case '3': + Conf.CGOptLevel = CodeGenOpt::Aggressive; + break; + default: + llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n'; + } + } + // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); Index: lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- lib/Transforms/Utils/CodeExtractor.cpp +++ lib/Transforms/Utils/CodeExtractor.cpp @@ -687,6 +687,9 @@ case Attribute::OptForFuzzing: case Attribute::OptimizeNone: case Attribute::OptimizeForSize: + case Attribute::OptimizeLess: + case Attribute::OptimizeDefault: + case Attribute::OptimizeAggressive: case Attribute::SafeStack: case Attribute::SanitizeAddress: case Attribute::SanitizeMemory: Index: tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- tools/llvm-lto2/llvm-lto2.cpp +++ tools/llvm-lto2/llvm-lto2.cpp @@ -34,11 +34,6 @@ "(default = '-O2')"), cl::Prefix, cl::ZeroOrMore, cl::init('2')); -static cl::opt CGOptLevel( - "cg-opt-level", - cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"), - cl::init('2')); - static cl::list InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("")); @@ -217,23 +212,6 @@ Conf.OptLevel = OptLevel - '0'; Conf.UseNewPM = UseNewPM; - switch (CGOptLevel) { - case '0': - Conf.CGOptLevel = CodeGenOpt::None; - break; - case '1': - Conf.CGOptLevel = CodeGenOpt::Less; - break; - case '2': - Conf.CGOptLevel = CodeGenOpt::Default; - break; - case '3': - Conf.CGOptLevel = CodeGenOpt::Aggressive; - break; - default: - llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n'; - return 1; - } if (FileType.getNumOccurrences()) Conf.CGFileType = FileType;