Cleanup the handling of noinline function attributes, -fno-inline,

-fno-inline-functions, -O0, and optnone.

These were really, really tangled together:
- We used the noinline LLVM attribute for -fno-inline
  - But not for -fno-inline-functions (breaking LTO)
  - But we did use it for -finline-hint-functions (yay, LTO is happy!)
  - But we didn't for -O0 (LTO is sad yet again...)
- We had weird structuring of CodeGenOpts with both an inlining
  enumeration and a boolean. They interacted in weird ways and
  needlessly.
- A *lot* of set smashing went on with setting these, and then got worse
  when we considered optnone and other inlining-effecting attributes.
- A bunch of inline affecting attributes were managed in a completely
  different place from -fno-inline.
- Even with -fno-inline we failed to put the LLVM noinline attribute
  onto many generated function definitions because they didn't show up
  as AST-level functions.
- If you passed -O0 but -finline-functions we would run the normal
  inliner pass in LLVM despite it being in the O0 pipeline, which really
  doesn't make much sense.
- Lastly, we used things like '-fno-inline' to manipulate the pass
  pipeline which forced the pass pipeline to be much more
  parameterizable than it really needs to be. Instead we can *just* use
  the optimization level to select a pipeline and control the rest via
  attributes.

Sadly, this causes a bunch of churn in tests because we don't run the
optimizer in the tests and check the contents of attribute sets. It
would be awesome if attribute sets were a bit more FileCheck friendly,
but oh well.

I think this is a significant improvement and should remove the semantic
need to change what inliner pass we run in order to comply with the
requested inlining semantics by relying completely on attributes. It
also cleans up tho optnone and related handling a bit.

One unfortunate aspect of this is that for generating alwaysinline
routines like those in OpenMP we end up removing noinline and then
adding alwaysinline. I tried a bunch of other approaches, but because we
recompute function attributes from scratch and don't have a declaration
here I couldn't find anything substantially cleaner than this.

Differential Revision: https://reviews.llvm.org/D28053

llvm-svn: 290398
This commit is contained in:
Chandler Carruth 2016-12-23 01:24:49 +00:00
parent ccae43a247
commit fcd33149b4
49 changed files with 187 additions and 183 deletions

View File

@ -104,8 +104,6 @@ CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf
CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero
CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated.
CODEGENOPT(NoTrappingMath , 1, 0) ///< Set when -fno-trapping-math is enabled.
CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled.
///< Disables use of the inline keyword.
CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN.
CODEGENOPT(FlushDenorm , 1, 0) ///< Allow FP denorm numbers to be flushed to zero
CODEGENOPT(CorrectlyRoundedDivSqrt, 1, 0) ///< -cl-fp32-correctly-rounded-divide-sqrt
@ -233,7 +231,7 @@ VALUE_CODEGENOPT(DwarfVersion, 3, 0)
CODEGENOPT(EmitCodeView, 1, 0)
/// The kind of inlining to perform.
ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining)
ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NormalInlining)
// Vector functions library to use.
ENUM_CODEGENOPT(VecLib, VectorLibrary, 2, NoLibrary)

View File

@ -44,7 +44,6 @@ protected:
class CodeGenOptions : public CodeGenOptionsBase {
public:
enum InliningMethod {
NoInlining, // Perform no inlining whatsoever.
NormalInlining, // Use the standard function inlining pass.
OnlyHintInlining, // Inline only (implicitly) hinted functions.
OnlyAlwaysInlining // Only run the always inlining pass.

View File

@ -289,9 +289,6 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
if (CodeGenOpts.DisableLLVMPasses)
return;
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining();
PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
// Figure out TargetLibraryInfo. This needs to be added to MPM and FPM
@ -302,26 +299,17 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
std::unique_ptr<TargetLibraryInfoImpl> TLII(
createTLII(TargetTriple, CodeGenOpts));
switch (Inlining) {
case CodeGenOptions::NoInlining:
break;
case CodeGenOptions::NormalInlining:
case CodeGenOptions::OnlyHintInlining: {
PMBuilder.Inliner =
createFunctionInliningPass(OptLevel, CodeGenOpts.OptimizeSize);
break;
}
case CodeGenOptions::OnlyAlwaysInlining:
// Respect always_inline.
if (OptLevel == 0)
// Do not insert lifetime intrinsics at -O0.
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(false);
else
PMBuilder.Inliner = createAlwaysInlinerLegacyPass();
break;
// At O0 and O1 we only run the always inliner which is more efficient. At
// higher optimization levels we run the normal inliner.
if (CodeGenOpts.OptimizationLevel <= 1) {
bool InsertLifetimeIntrinsics = CodeGenOpts.OptimizationLevel != 0;
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
} else {
PMBuilder.Inliner = createFunctionInliningPass(
CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize);
}
PMBuilder.OptLevel = OptLevel;
PMBuilder.OptLevel = CodeGenOpts.OptimizationLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB;
PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;

View File

@ -757,6 +757,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
FnTy, llvm::GlobalValue::InternalLinkage,
IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
Fn->removeFnAttr(llvm::Attribute::NoInline);
Fn->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
// Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
@ -3472,6 +3473,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
".omp_task_privates_map.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskPrivatesMap,
TaskPrivatesMapFnInfo);
TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
CGF.disableDebugInfo();

View File

@ -372,6 +372,7 @@ llvm::Value *CGOpenMPRuntimeNVPTX::emitParallelOrTeamsOutlinedFunction(
CGOpenMPRuntime::emitParallelOrTeamsOutlinedFunction(
D, ThreadIDVar, InnermostKind, CodeGen);
OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
} else
llvm_unreachable("parallel directive is not yet supported for nvptx "

View File

@ -775,27 +775,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
}
// Pass inline keyword to optimizer if it appears explicitly on any
// declaration. Also, in the case of -fno-inline attach NoInline
// attribute to all functions that are not marked AlwaysInline, or
// to all functions that are not marked inline or implicitly inline
// in the case of -finline-hint-functions.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
const CodeGenOptions& CodeGenOpts = CGM.getCodeGenOpts();
if (!CodeGenOpts.NoInline) {
for (auto RI : FD->redecls())
if (RI->isInlineSpecified()) {
Fn->addFnAttr(llvm::Attribute::InlineHint);
break;
}
if (CodeGenOpts.getInlining() == CodeGenOptions::OnlyHintInlining &&
!FD->isInlined() && !Fn->hasFnAttribute(llvm::Attribute::InlineHint))
Fn->addFnAttr(llvm::Attribute::NoInline);
} else if (!FD->hasAttr<AlwaysInlineAttr>())
Fn->addFnAttr(llvm::Attribute::NoInline);
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
if (CGM.getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
CGM.getOpenMPRuntime().emitDeclareSimdFunction(FD, Fn);
}
// Add no-jump-tables value.
Fn->addFnAttr("no-jump-tables",

View File

@ -875,6 +875,13 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::StackProtectReq);
if (!D) {
// If we don't have a declaration to control inlining, the function isn't
// explicitly marked as alwaysinline for semantic reasons, and inlining is
// disabled, mark the function as noinline.
if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
B.addAttribute(llvm::Attribute::NoInline);
F->addAttributes(llvm::AttributeSet::FunctionIndex,
llvm::AttributeSet::get(
F->getContext(),
@ -882,7 +889,23 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
return;
}
if (D->hasAttr<NakedAttr>()) {
if (D->hasAttr<OptimizeNoneAttr>()) {
B.addAttribute(llvm::Attribute::OptimizeNone);
// OptimizeNone implies noinline; we should not be inlining such functions.
B.addAttribute(llvm::Attribute::NoInline);
assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
"OptimizeNone and AlwaysInline on same function!");
// We still need to handle naked functions even though optnone subsumes
// much of their semantics.
if (D->hasAttr<NakedAttr>())
B.addAttribute(llvm::Attribute::Naked);
// OptimizeNone wins over OptimizeForSize and MinSize.
F->removeFnAttr(llvm::Attribute::OptimizeForSize);
F->removeFnAttr(llvm::Attribute::MinSize);
} else if (D->hasAttr<NakedAttr>()) {
// Naked implies noinline: we should not be inlining such functions.
B.addAttribute(llvm::Attribute::Naked);
B.addAttribute(llvm::Attribute::NoInline);
@ -891,41 +914,47 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
} else if (D->hasAttr<NoInlineAttr>()) {
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<AlwaysInlineAttr>() &&
!F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline)) {
!F->hasFnAttribute(llvm::Attribute::NoInline)) {
// (noinline wins over always_inline, and we can't specify both in IR)
B.addAttribute(llvm::Attribute::AlwaysInline);
} else if (CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
// If we're not inlining, then force everything that isn't always_inline to
// carry an explicit noinline attribute.
if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline))
B.addAttribute(llvm::Attribute::NoInline);
} else {
// Otherwise, propagate the inline hint attribute and potentially use its
// absence to mark things as noinline.
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
if (any_of(FD->redecls(), [&](const FunctionDecl *Redecl) {
return Redecl->isInlineSpecified();
})) {
B.addAttribute(llvm::Attribute::InlineHint);
} else if (CodeGenOpts.getInlining() ==
CodeGenOptions::OnlyHintInlining &&
!FD->isInlined() &&
!F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
B.addAttribute(llvm::Attribute::NoInline);
}
}
}
if (D->hasAttr<ColdAttr>()) {
if (!D->hasAttr<OptimizeNoneAttr>())
// Add other optimization related attributes if we are optimizing this
// function.
if (!D->hasAttr<OptimizeNoneAttr>()) {
if (D->hasAttr<ColdAttr>()) {
B.addAttribute(llvm::Attribute::OptimizeForSize);
B.addAttribute(llvm::Attribute::Cold);
}
B.addAttribute(llvm::Attribute::Cold);
}
if (D->hasAttr<MinSizeAttr>())
B.addAttribute(llvm::Attribute::MinSize);
if (D->hasAttr<MinSizeAttr>())
B.addAttribute(llvm::Attribute::MinSize);
}
F->addAttributes(llvm::AttributeSet::FunctionIndex,
llvm::AttributeSet::get(
F->getContext(), llvm::AttributeSet::FunctionIndex, B));
if (D->hasAttr<OptimizeNoneAttr>()) {
// OptimizeNone implies noinline; we should not be inlining such functions.
F->addFnAttr(llvm::Attribute::OptimizeNone);
F->addFnAttr(llvm::Attribute::NoInline);
// OptimizeNone wins over OptimizeForSize, MinSize, AlwaysInline.
F->removeFnAttr(llvm::Attribute::OptimizeForSize);
F->removeFnAttr(llvm::Attribute::MinSize);
assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
"OptimizeNone and AlwaysInline on same function!");
// Attribute 'inlinehint' has no effect on 'optnone' functions.
// Explicitly remove it from the set of function attributes.
F->removeFnAttr(llvm::Attribute::InlineHint);
}
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
F->setAlignment(alignment);

View File

@ -441,22 +441,25 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
Opts.OptimizationLevel = OptimizationLevel;
// We must always run at least the always inlining pass.
Opts.setInlining(
(Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
: CodeGenOptions::OnlyAlwaysInlining);
// -fno-inline-functions overrides OptimizationLevel > 1.
Opts.NoInline = Args.hasArg(OPT_fno_inline);
if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions,
options::OPT_finline_hint_functions,
options::OPT_fno_inline_functions)) {
const Option& InlineOpt = InlineArg->getOption();
if (InlineOpt.matches(options::OPT_finline_functions))
Opts.setInlining(CodeGenOptions::NormalInlining);
else if (InlineOpt.matches(options::OPT_finline_hint_functions))
Opts.setInlining(CodeGenOptions::OnlyHintInlining);
else
Opts.setInlining(CodeGenOptions::OnlyAlwaysInlining);
// At O0 we want to fully disable inlining outside of cases marked with
// 'alwaysinline' that are required for correctness.
Opts.setInlining((Opts.OptimizationLevel == 0)
? CodeGenOptions::OnlyAlwaysInlining
: CodeGenOptions::NormalInlining);
// Explicit inlining flags can disable some or all inlining even at
// optimization levels above zero.
if (Arg *InlineArg = Args.getLastArg(
options::OPT_finline_functions, options::OPT_finline_hint_functions,
options::OPT_fno_inline_functions, options::OPT_fno_inline)) {
if (Opts.OptimizationLevel > 0) {
const Option &InlineOpt = InlineArg->getOption();
if (InlineOpt.matches(options::OPT_finline_functions))
Opts.setInlining(CodeGenOptions::NormalInlining);
else if (InlineOpt.matches(options::OPT_finline_hint_functions))
Opts.setInlining(CodeGenOptions::OnlyHintInlining);
else
Opts.setInlining(CodeGenOptions::OnlyAlwaysInlining);
}
}
if (Arg *A = Args.getLastArg(OPT_fveclib)) {
@ -2188,7 +2191,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// This is the __NO_INLINE__ define, which just depends on things like the
// optimization level and -fno-inline, not actually whether the backend has
// inlining enabled.
Opts.NoInlineDefine = !Opt || Args.hasArg(OPT_fno_inline);
Opts.NoInlineDefine = !Opts.Optimize;
if (Arg *InlineArg = Args.getLastArg(
options::OPT_finline_functions, options::OPT_finline_hint_functions,
options::OPT_fno_inline_functions, options::OPT_fno_inline))
if (InlineArg->getOption().matches(options::OPT_fno_inline))
Opts.NoInlineDefine = true;
Opts.FastMath = Args.hasArg(OPT_ffast_math) ||
Args.hasArg(OPT_cl_fast_relaxed_math);

View File

@ -176,4 +176,4 @@ struct TVC : VX
template <typename T>
TVC<T>::~TVC() {}
// CHECK: attributes [[ATTRGRP]] = { nounwind{{.*}} }
// CHECK: attributes [[ATTRGRP]] = { noinline nounwind{{.*}} }

View File

@ -9,4 +9,4 @@ void g(void) {
// CHECK-NOT: declare void @f() [[NUW]]
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -8,31 +8,31 @@
int HasSanitizeAddress() {
return 1;
}
// CHECK-NOASAN: {{Function Attrs: nounwind$}}
// CHECK-ASAN: Function Attrs: nounwind sanitize_address
// CHECK-KASAN: Function Attrs: nounwind sanitize_address
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: Function Attrs: noinline nounwind sanitize_address
// CHECK-KASAN: Function Attrs: noinline nounwind sanitize_address
__attribute__((no_sanitize("address")))
int NoSanitizeQuoteAddress() {
return 0;
}
// CHECK-NOASAN: {{Function Attrs: nounwind$}}
// CHECK-ASAN: {{Function Attrs: nounwind$}}
// CHECK-KASAN: {{Function Attrs: nounwind sanitize_address$}}
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
__attribute__((no_sanitize_address))
int NoSanitizeAddress() {
return 0;
}
// CHECK-NOASAN: {{Function Attrs: nounwind$}}
// CHECK-ASAN: {{Function Attrs: nounwind$}}
// CHECK-KASAN: {{Function Attrs: nounwind sanitize_address$}}
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
__attribute__((no_sanitize("kernel-address")))
int NoSanitizeKernelAddress() {
return 0;
}
// CHECK-NOASAN: {{Function Attrs: nounwind$}}
// CHECK-ASAN: {{Function Attrs: nounwind sanitize_address$}}
// CHECK-KASAN: {{Function Attrs: nounwind$}}
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}

View File

@ -143,13 +143,13 @@ int global2 = *(int*)((char*)&global1+1);
// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH]]
// ASAN: @__cxx_global_var_init{{.*}}[[WITH]]
// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// BLFILE: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
// BLFILE: attributes [[WITH]] = { noinline nounwind sanitize_address{{.*}} }
// BLFILE: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
// BLFUNC: attributes [[WITH]] = { noinline nounwind sanitize_address{{.*}} }
// BLFUNC: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
// ASAN: attributes [[WITH]] = { noinline nounwind sanitize_address{{.*}} }
// ASAN: attributes [[NOATTR]] = { noinline nounwind{{.*}} }

View File

@ -37,4 +37,4 @@ void test_addrspace(__addr1 S* p1, __addr2 S*p2) {
p1->b = p2->a;
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -77,9 +77,9 @@ int outer_weak(int a) { return inner_weak_a(a); }
// CHECKCC: call arm_aapcs_vfpcc i32 @inner_weak(i32 %{{.*}})
// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner_weak(i32 %a) [[NUW]] {
// CHECKBASIC: attributes [[NUW]] = { nounwind{{.*}} }
// CHECKBASIC: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECKCC: attributes [[NUW]] = { nounwind{{.*}} }
// CHECKCC: attributes [[NUW]] = { noinline nounwind{{.*}} }
void test8_bar() {}
void test8_foo() __attribute__((weak, alias("test8_bar")));

View File

@ -76,4 +76,4 @@ void test5<float>(float arg);
// Oz: attributes [[MINSIZE]] = { minsize{{.*}} }
// OTHER: attributes [[MS]] = { minsize nounwind{{.*}} }
// OTHER: attributes [[MS]] = { minsize{{.*}} }

View File

@ -90,5 +90,5 @@ void __attribute__((section(".bar"))) t22(void) {}
// CHECK: define void @t22() [[NUW]] section ".bar"
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NR]] = { noreturn nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} }

View File

@ -16,4 +16,4 @@ void test10_foo(test10_F3 p1)
p1(0.0);
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -2,8 +2,8 @@
// RUN: %clang_cc1 -triple i686-pc-win32 -emit-llvm %s -o - | FileCheck -check-prefix=NOINLINE %s
// RUN: %clang_cc1 -triple i686-pc-win32 -O3 -fno-inline-functions -emit-llvm %s -o - | FileCheck -check-prefix=NOINLINE %s
// RUN: %clang_cc1 -triple i686-pc-win32 -finline-hint-functions -emit-llvm %s -o - | FileCheck -check-prefix=HINT %s
// RUN: %clang_cc1 -triple i686-pc-win32 -finline-functions -emit-llvm %s -o - | FileCheck -check-prefix=INLINE %s
// RUN: %clang_cc1 -triple i686-pc-win32 -O3 -finline-hint-functions -emit-llvm %s -o - | FileCheck -check-prefix=HINT %s
// RUN: %clang_cc1 -triple i686-pc-win32 -O3 -finline-functions -emit-llvm %s -o - | FileCheck -check-prefix=INLINE %s
inline int inline_hint(int a, int b) { return(a+b); }

View File

@ -11,7 +11,7 @@ void __attribute__((nomips16)) nofoo (void) {
// CHECK: define void @nofoo() [[NOMIPS16:#[0-9]+]]
// CHECK: attributes [[MIPS16]] = { nounwind {{.*}} "mips16" {{.*}} }
// CHECK: attributes [[MIPS16]] = { noinline nounwind {{.*}} "mips16" {{.*}} }
// CHECK: attributes [[NOMIPS16]] = { nounwind {{.*}} "nomips16" {{.*}} }
// CHECK: attributes [[NOMIPS16]] = { noinline nounwind {{.*}} "nomips16" {{.*}} }

View File

@ -25,4 +25,4 @@ void quux(int a1, int a2, int a3) {
// CHECK-LABEL: define x86_stdcallcc void @quux
// CHECK: call void (i32, ...) @qux
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -O2 -disable-llvm-optzns -o - | FileCheck %s
__declspec(selectany) int x1 = 1;
const __declspec(selectany) int x2 = 2;

View File

@ -180,4 +180,4 @@ void bar_long_long(void) {
// CHECK: %[[VAR77:[A-Za-z0-9.]+]] = load i64, i64* %[[VAR76]], align 8
// CHECK: %{{[A-Za-z0-9.]+}} = call i64 @foo_long_long(i64 %[[VAR75]], i64 %[[VAR77]])
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -126,4 +126,4 @@ long long bar_long_long(void) {
// CHECK: extractvalue { i64, i64 } [[VAR8]], 1
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -13,4 +13,4 @@ int f3(void) { return 0; }
unsigned int f4(void) { return 0; }
// CHECK: define zeroext i32 @f4() [[NUW]]
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -54,9 +54,9 @@ int global2 = *(int*)((char*)&global1+1);
// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
// TSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// BL: attributes [[NOATTR]] = { nounwind{{.*}} }
// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// TSAN: attributes [[NOATTR]] = { nounwind{{.*}} }
// TSAN: attributes [[WITH]] = { nounwind sanitize_thread{{.*}} }
// TSAN: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// TSAN: attributes [[WITH]] = { noinline nounwind sanitize_thread{{.*}} }

View File

@ -31,4 +31,4 @@ public:
// TSAN: initialize{{.*}}) [[ATTR:#[0-9]+]]
// TSAN: dealloc{{.*}}) [[ATTR:#[0-9]+]]
// TSAN: cxx_destruct{{.*}}) [[ATTR:#[0-9]+]]
// TSAN: attributes [[ATTR]] = { nounwind {{.*}} "sanitize_thread_no_checking_at_run_time" {{.*}} }
// TSAN: attributes [[ATTR]] = { noinline nounwind {{.*}} "sanitize_thread_no_checking_at_run_time" {{.*}} }

View File

@ -23,7 +23,7 @@ __attribute__((weak)) int test2(void) {
return 0;
}
// CHECK: attributes [[TF]] = { "{{.*}} }
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[TF]] = { noinline "{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECK-NOEXC: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK-NOEXC: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -31,4 +31,4 @@ int test1() { return 10; }
// CHECK at top of file
extern "C" int test2() __attribute__((alias("_Z5test1v")));
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -121,7 +121,7 @@ void j() {
}
// CHECK: attributes [[NONE]] = { {{.*}} }
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECK: attributes [[NUW2]] = { nounwind{{.*}} }

View File

@ -7,4 +7,4 @@ int g();
while (g()) {}
}
// CHECK: attributes [[NR]] = { noreturn nounwind{{.*}} }
// CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} }

View File

@ -46,4 +46,4 @@ namespace test3 {
}
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -43,4 +43,4 @@ void func() {
static A a1, a2;
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -204,8 +204,8 @@ namespace test7 {
// rdar://problem/8090834: this should be nounwind
// CHECK-NOEXC: define internal void @_GLOBAL__sub_I_global_init.cpp() [[NUW:#[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK-NOEXC: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK-NOEXC: attributes [[NUW]] = { noinline nounwind{{.*}} }
// PR21811: attach the appropriate attribute to the global init function
// CHECK-FP: define internal void @_GLOBAL__sub_I_global_init.cpp() [[NUX:#[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK-FP: attributes [[NUX]] = { nounwind {{.*}}"no-frame-pointer-elim-non-leaf"{{.*}} }
// CHECK-FP: attributes [[NUX]] = { noinline nounwind {{.*}}"no-frame-pointer-elim-non-leaf"{{.*}} }

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-functions -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=SUITABLE
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -finline-hint-functions -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=HINTED
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -fno-inline -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=NOINLINE
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -O2 -finline-functions -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=SUITABLE
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -O2 -finline-hint-functions -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=HINTED
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-linux -O2 -fno-inline -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK --check-prefix=NOINLINE
// Force non-trivial implicit constructors/destructors/operators for B by having explicit ones for A
struct A {

View File

@ -5,4 +5,4 @@ int main(int argc, char **argv) {
return 1;
}
// CHECK: attributes #0 = { norecurse{{.*}} }
// CHECK: attributes #0 = { noinline norecurse{{.*}} }

View File

@ -68,4 +68,4 @@ struct S {
void delete_s(S *s) { delete[] s; }
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -11,4 +11,4 @@ void f() throw (int) {
// CHECK: ret void
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -x c++ | FileCheck %s
// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-optzns -emit-llvm -x c++ | FileCheck %s
// Test attribute 'optnone' on methods:
// -- member functions;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-optzns -emit-llvm -o - | FileCheck %s
// Test optnone on both function declarations and function definitions.
// Verify also that we don't generate invalid IR functions with

View File

@ -193,4 +193,4 @@ namespace PR10650 {
// CHECK: store i64
}
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -22,6 +22,6 @@ void g() {
// NO-TSS-NOT: call void @__cxa_guard_release
// NO-TSS: ret void
// WITH-TSS: attributes [[NUW]] = { nounwind{{.*}} }
// WITH-TSS: attributes [[NUW]] = { noinline nounwind{{.*}} }
// NO-TSS: attributes [[NUW]] = { nounwind{{.*}} }
// NO-TSS: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -1,9 +1,5 @@
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o %t
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o %t.opt -O1 -disable-llvm-passes
// RUN: FileCheck %s < %t
// RUN: FileCheck %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-NONOPT %s < %t
// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-NONOPT %s
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - -O1 -disable-llvm-passes | FileCheck --check-prefix=CHECK --check-prefix=CHECK-OPT %s
namespace Test1 {
@ -405,4 +401,5 @@ D::~D() {}
// CHECK-OPT-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
// CHECK-OPT-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
// CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
// CHECK-NONOPT: attributes [[NUW]] = { noinline nounwind uwtable{{.*}} }
// CHECK-OPT: attributes [[NUW]] = { nounwind uwtable{{.*}} }

View File

@ -82,4 +82,4 @@ BB* d() { return y; }
// MSVC: add nsw i32 4, %[[offset]]
// MSVC: }
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -32,4 +32,4 @@ void test0() {
log(1);
}
// CHECK: attributes [[TF]] = { "{{.*}} }
// CHECK: attributes [[TF]] = { noinline "{{.*}} }

View File

@ -94,4 +94,4 @@ void baz(void) {
bar(^(void) { return YES; });
}
// CHECK: attributes [[NUW]] = { {{(norecurse )?}}nounwind{{.*}} }
// CHECK: attributes [[NUW]] = { noinline {{(norecurse )?}}nounwind{{.*}} }

View File

@ -125,5 +125,5 @@ namespace BlockInLambda {
}
// ARC: attributes [[NUW]] = { nounwind{{.*}} }
// MRC: attributes [[NUW]] = { nounwind{{.*}} }
// ARC: attributes [[NUW]] = { noinline nounwind{{.*}} }
// MRC: attributes [[NUW]] = { noinline nounwind{{.*}} }

View File

@ -141,26 +141,26 @@ kernel void flat_work_group_size_32_64_waves_per_eu_2_4_num_sgpr_32_num_vgpr_64(
// CHECK-NOT: "amdgpu-num-sgpr"="0"
// CHECK-NOT: "amdgpu-num-vgpr"="0"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64"
// CHECK-DAG: attributes [[WAVES_PER_EU_2]] = { nounwind "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4]] = { nounwind "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[NUM_SGPR_32]] = { nounwind "amdgpu-num-sgpr"="32"
// CHECK-DAG: attributes [[NUM_VGPR_64]] = { nounwind "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64"
// CHECK-DAG: attributes [[WAVES_PER_EU_2]] = { noinline nounwind "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4]] = { noinline nounwind "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32"
// CHECK-DAG: attributes [[NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_SGPR_32]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_VGPR_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_SGPR_32]] = { nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_VGPR_64]] = { nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_SGPR_32]] = { nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_VGPR_64]] = { nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[NUM_SGPR_32_NUM_VGPR_64]] = { nounwind "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_VGPR_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_VGPR_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32_NUM_VGPR_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32_NUM_VGPR_64]] = { nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"

View File

@ -26,4 +26,4 @@ void f1() {
[I1 alloc];
}
// CHECK: attributes [[F0]] = { ssp{{.*}} }
// CHECK: attributes [[F0]] = { noinline ssp{{.*}} }

View File

@ -21,5 +21,5 @@
// CHECK-IR: {{call.*objc_msgSend}}
// CHECK-IR: ret void
// CHECK-IR: attributes #0 = { nounwind {{.*}} }
// CHECK-IR: attributes #0 = { noinline nounwind {{.*}} }
// CHECK-IR: attributes #1 = { nonlazybind }