/// is optimized and passed to the backend.
class CompileOptions {
public:
+ enum InliningMethod {
+ NoInlining, // Perform no inlining whatsoever.
+ NormalInlining, // Use the standard function inlining pass.
+ OnlyAlwaysInlining // Only run the always inlining pass.
+ };
+
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
unsigned OptimizeSize : 1; /// If -Os is specified.
unsigned DebugInfo : 1; /// Should generate deubg info (-g).
unsigned UnitAtATime : 1; /// Unused. For mirroring GCC
/// optimization selection.
- unsigned InlineFunctions : 1; /// Should functions be inlined?
unsigned SimplifyLibCalls : 1; /// Should standard library calls be
/// treated specially.
unsigned UnrollLoops : 1; /// Control whether loops are unrolled.
unsigned TimePasses : 1; /// Set when -ftime-report is enabled.
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
+ /// Inlining - The kind of inlining to perform.
+ InliningMethod Inlining;
+
/// CPU - An optional CPU to target.
std::string CPU;
OptimizeSize = 0;
DebugInfo = 0;
UnitAtATime = 1;
- InlineFunctions = SimplifyLibCalls = UnrollLoops = 0;
+ SimplifyLibCalls = UnrollLoops = 0;
VerifyModule = 1;
TimePasses = 0;
NoCommon = 0;
+ Inlining = NoInlining;
}
};
PM->add(createPruneEHPass()); // Remove dead EH info
PM->add(createFunctionAttrsPass()); // Set readonly/readnone attrs
}
- if (CompileOpts.InlineFunctions)
+ switch (CompileOpts.Inlining) {
+ case CompileOptions::NoInlining:
+ break;
+ case CompileOptions::NormalInlining:
PM->add(createFunctionInliningPass()); // Inline small functions
- else
+ break;
+ case CompileOptions::OnlyAlwaysInlining:
PM->add(createAlwaysInlinerPass()); // Respect always_inline
+ break;
+ }
if (CompileOpts.OptimizationLevel > 2)
PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args
if (CompileOpts.SimplifyLibCalls)
if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
PM->add(createConstantMergePass()); // Merge dup global constants
} else {
- PM->add(createAlwaysInlinerPass());
+ switch (CompileOpts.Inlining) {
+ case CompileOptions::NoInlining:
+ break;
+ case CompileOptions::NormalInlining:
+ PM->add(createFunctionInliningPass()); // Inline small functions
+ break;
+ case CompileOptions::OnlyAlwaysInlining:
+ PM->add(createAlwaysInlinerPass()); // Respect always_inline
+ break;
+ }
}
}
--- /dev/null
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep '@f0' %t | count 0 &&
+// RUN: clang-cc -disable-llvm-optzns -emit-llvm -o %t %s &&
+// RUN: grep '@f0' %t | count 2
+
+//static int f0() {
+static int __attribute__((always_inline)) f0() {
+ return 1;
+}
+
+int f1() {
+ return f0();
+}
static llvm::cl::opt<bool>
OptSize("Os", llvm::cl::desc("Optimize for size"));
+static llvm::cl::opt<bool>
+DisableLLVMOptimizations("disable-llvm-optzns",
+ llvm::cl::desc("Don't run LLVM optimization passes"));
+
static llvm::cl::opt<bool>
NoCommon("fno-common",
llvm::cl::desc("Compile common globals like normal definitions"),
const llvm::StringMap<bool> &Features) {
Opts.OptimizeSize = OptSize;
Opts.DebugInfo = GenerateDebugInfo;
- if (OptSize) {
- // -Os implies -O2
- // FIXME: Diagnose conflicting options.
- Opts.OptimizationLevel = 2;
+
+ if (DisableLLVMOptimizations) {
+ Opts.OptimizationLevel = 0;
+ Opts.Inlining = CompileOptions::NoInlining;
} else {
- Opts.OptimizationLevel = OptLevel;
+ if (OptSize) {
+ // -Os implies -O2
+ Opts.OptimizationLevel = 2;
+ } else {
+ Opts.OptimizationLevel = OptLevel;
+ }
+
+ // We must always run at least the always inlining pass.
+ if (Opts.OptimizationLevel > 1)
+ Opts.Inlining = CompileOptions::NormalInlining;
+ else
+ Opts.Inlining = CompileOptions::OnlyAlwaysInlining;
}
// FIXME: There are llvm-gcc options to control these selectively.
- Opts.InlineFunctions = (Opts.OptimizationLevel > 1);
Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize);
Opts.SimplifyLibCalls = !LangOpts.NoBuiltin;