forked from OSchip/llvm-project
229 lines
6.0 KiB
C++
229 lines
6.0 KiB
C++
// RUN: %clang_cc1 -fno-elide-constructors -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -fno-elide-constructors -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | opt -verify
|
|
// FIXME: remove the call to "opt" once the tests are running the Clang verifier automatically again.
|
|
|
|
int Bar(int);
|
|
int Baz(int);
|
|
|
|
int Func1(int x) {
|
|
if (x) {
|
|
// CHECK: %call = musttail call i32 @_Z3Bari(i32 %1)
|
|
// CHECK-NEXT: ret i32 %call
|
|
[[clang::musttail]] return Bar(x);
|
|
} else {
|
|
[[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call i32 @_Z3Bazi(i32 %3)
|
|
}
|
|
}
|
|
|
|
int Func2(int x) {
|
|
{
|
|
[[clang::musttail]] return Bar(Bar(x));
|
|
}
|
|
}
|
|
|
|
// CHECK: %call1 = musttail call i32 @_Z3Bari(i32 %call)
|
|
|
|
class Foo {
|
|
public:
|
|
static int StaticMethod(int x);
|
|
int MemberFunction(int x);
|
|
int TailFrom(int x);
|
|
int TailFrom2(int x);
|
|
int TailFrom3(int x);
|
|
};
|
|
|
|
int Foo::TailFrom(int x) {
|
|
[[clang::musttail]] return MemberFunction(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_ZN3Foo14MemberFunctionEi(%class.Foo* nonnull align 1 dereferenceable(1) %this1, i32 %0)
|
|
|
|
int Func3(int x) {
|
|
[[clang::musttail]] return Foo::StaticMethod(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
|
|
|
|
int Func4(int x) {
|
|
Foo foo; // Object with trivial destructor.
|
|
[[clang::musttail]] return foo.StaticMethod(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
|
|
|
|
int (Foo::*pmf)(int);
|
|
|
|
int Foo::TailFrom2(int x) {
|
|
[[clang::musttail]] return ((*this).*pmf)(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull align 1 dereferenceable(1) %this.adjusted, i32 %9)
|
|
|
|
int Foo::TailFrom3(int x) {
|
|
[[clang::musttail]] return (this->*pmf)(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull align 1 dereferenceable(1) %this.adjusted, i32 %9)
|
|
|
|
void ReturnsVoid();
|
|
|
|
void Func5() {
|
|
[[clang::musttail]] return ReturnsVoid();
|
|
}
|
|
|
|
// CHECK: musttail call void @_Z11ReturnsVoidv()
|
|
|
|
class HasTrivialDestructor {};
|
|
|
|
int ReturnsInt(int x);
|
|
|
|
int Func6(int x) {
|
|
HasTrivialDestructor foo;
|
|
[[clang::musttail]] return ReturnsInt(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_Z10ReturnsInti(i32 %0)
|
|
|
|
struct Data {
|
|
int (*fptr)(Data *);
|
|
};
|
|
|
|
int Func7(Data *data) {
|
|
[[clang::musttail]] return data->fptr(data);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 %1(%struct.Data* %2)
|
|
|
|
template <class T>
|
|
T TemplateFunc(T) {
|
|
return 5;
|
|
}
|
|
|
|
int Func9(int x) {
|
|
[[clang::musttail]] return TemplateFunc<int>(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_Z12TemplateFuncIiET_S0_(i32 %0)
|
|
|
|
template <class T>
|
|
int Func10(int x) {
|
|
T t;
|
|
[[clang::musttail]] return Bar(x);
|
|
}
|
|
|
|
int Func11(int x) {
|
|
return Func10<int>(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_Z3Bari(i32 %0)
|
|
|
|
template <class T>
|
|
T Func12(T x) {
|
|
[[clang::musttail]] return ::Bar(x);
|
|
}
|
|
|
|
int Func13(int x) {
|
|
return Func12<int>(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_Z3Bari(i32 %0)
|
|
|
|
int Func14(int x) {
|
|
int vla[x];
|
|
[[clang::musttail]] return Bar(x);
|
|
}
|
|
|
|
// CHECK: %call = musttail call i32 @_Z3Bari(i32 %3)
|
|
|
|
void TrivialDestructorParam(HasTrivialDestructor obj);
|
|
|
|
void Func14(HasTrivialDestructor obj) {
|
|
[[clang::musttail]] return TrivialDestructorParam(obj);
|
|
}
|
|
|
|
// CHECK: musttail call void @_Z22TrivialDestructorParam20HasTrivialDestructor()
|
|
|
|
struct Struct3 {
|
|
void ConstMemberFunction(const int *) const;
|
|
void NonConstMemberFunction(int *i);
|
|
};
|
|
void Struct3::NonConstMemberFunction(int *i) {
|
|
// The parameters are not identical, but they are compatible.
|
|
[[clang::musttail]] return ConstMemberFunction(i);
|
|
}
|
|
|
|
// CHECK: musttail call void @_ZNK7Struct319ConstMemberFunctionEPKi(%struct.Struct3* nonnull align 1 dereferenceable(1) %this1, i32* %0)
|
|
|
|
struct HasNonTrivialCopyConstructor {
|
|
HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);
|
|
};
|
|
HasNonTrivialCopyConstructor ReturnsClassByValue();
|
|
HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {
|
|
[[clang::musttail]] return (((ReturnsClassByValue())));
|
|
}
|
|
|
|
// CHECK: musttail call void @_Z19ReturnsClassByValuev(%struct.HasNonTrivialCopyConstructor* sret(%struct.HasNonTrivialCopyConstructor) align 1 %agg.result)
|
|
|
|
struct HasNonTrivialCopyConstructor2 {
|
|
// Copy constructor works even if it has extra default params.
|
|
HasNonTrivialCopyConstructor2(const HasNonTrivialCopyConstructor &, int DefaultParam = 5);
|
|
};
|
|
HasNonTrivialCopyConstructor2 ReturnsClassByValue2();
|
|
HasNonTrivialCopyConstructor2 TestNonElidableCopyConstructor2() {
|
|
[[clang::musttail]] return (((ReturnsClassByValue2())));
|
|
}
|
|
|
|
// CHECK: musttail call void @_Z20ReturnsClassByValue2v()
|
|
|
|
void TestFunctionPointer(int x) {
|
|
void (*p)(int) = nullptr;
|
|
[[clang::musttail]] return p(x);
|
|
}
|
|
|
|
// CHECK: musttail call void %0(i32 %1)
|
|
|
|
struct LargeWithCopyConstructor {
|
|
LargeWithCopyConstructor(const LargeWithCopyConstructor &);
|
|
char data[32];
|
|
};
|
|
LargeWithCopyConstructor ReturnsLarge();
|
|
LargeWithCopyConstructor TestLargeWithCopyConstructor() {
|
|
[[clang::musttail]] return ReturnsLarge();
|
|
}
|
|
|
|
// CHECK: define dso_local void @_Z28TestLargeWithCopyConstructorv(%struct.LargeWithCopyConstructor* noalias sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
|
|
// CHECK: musttail call void @_Z12ReturnsLargev(%struct.LargeWithCopyConstructor* sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
|
|
|
|
using IntFunctionType = int();
|
|
IntFunctionType *ReturnsIntFunction();
|
|
int TestRValueFunctionPointer() {
|
|
[[clang::musttail]] return ReturnsIntFunction()();
|
|
}
|
|
|
|
// CHECK: musttail call i32 %call()
|
|
|
|
void(FuncWithParens)() {
|
|
[[clang::musttail]] return FuncWithParens();
|
|
}
|
|
|
|
// CHECK: musttail call void @_Z14FuncWithParensv()
|
|
|
|
int TestNonCapturingLambda() {
|
|
auto lambda = []() { return 12; };
|
|
[[clang::musttail]] return (+lambda)();
|
|
}
|
|
|
|
// CHECK: %call = call i32 ()* @"_ZZ22TestNonCapturingLambdavENK3$_0cvPFivEEv"(%class.anon* nonnull align 1 dereferenceable(1) %lambda)
|
|
// CHECK: musttail call i32 %call()
|
|
|
|
class TestVirtual {
|
|
virtual void TailTo();
|
|
virtual void TailFrom();
|
|
};
|
|
|
|
void TestVirtual::TailFrom() {
|
|
[[clang::musttail]] return TailTo();
|
|
}
|
|
|
|
// CHECK: musttail call void %1(%class.TestVirtual* nonnull align 8 dereferenceable(8) %this1)
|