Add some overlooked optnone tests, and tighten up an existing test.

Differential Revision: http://reviews.llvm.org/D15704

llvm-svn: 256762
This commit is contained in:
Paul Robinson 2016-01-04 17:03:58 +00:00
parent 947ca8ac52
commit 9d6940ba09
4 changed files with 353 additions and 2 deletions

View File

@ -0,0 +1,82 @@
// RUN: %clang_cc1 < %s -triple i386-mingw32 -fms-extensions -emit-llvm -x c++ | FileCheck %s
// optnone wins over inlinehint.
// Test that both func1 and func2 are marked optnone and noinline.
// Definition with both optnone and inlinehint.
__attribute__((optnone))
inline int func1(int a) {
return a + a + a + a;
}
// CHECK: @_Z5func1i({{.*}}) [[OPTNONE:#[0-9]+]]
// optnone declaration, inlinehint definition.
__attribute__((optnone))
int func2(int a);
inline int func2(int a) {
return a + a + a + a;
}
// CHECK: @_Z5func2i({{.*}}) [[OPTNONE]]
// Keep alive the definitions of func1 and func2.
int foo() {
int val = func1(1);
return val + func2(2);
}
// optnone wins over minsize.
__attribute__((optnone))
int func3(int a);
__attribute__((minsize))
int func3(int a) {
return a + a + a + a;
}
// Same attribute set as everything else, therefore no 'minsize'.
// CHECK: @_Z5func3i({{.*}}) [[OPTNONE]]
// Verify that noreturn is compatible with optnone.
__attribute__((noreturn))
extern void exit_from_function();
__attribute__((noreturn)) __attribute((optnone))
extern void noreturn_function(int a) { exit_from_function(); }
// CHECK: @_Z17noreturn_functioni({{.*}}) [[NORETURN:#[0-9]+]]
// Verify that __declspec(noinline) is compatible with optnone.
__declspec(noinline) __attribute__((optnone))
void func4() { return; }
// CHECK: @_Z5func4v() [[OPTNONE]]
__declspec(noinline)
extern void func5();
__attribute__((optnone))
void func5() { return; }
// CHECK: @_Z5func5v() [[OPTNONE]]
// Verify also that optnone can be used on dllexport functions.
// Adding attribute optnone on a dllimport function has no effect.
__attribute__((dllimport))
__attribute__((optnone))
int imported_optnone_func(int a);
__attribute__((dllexport))
__attribute__((optnone))
int exported_optnone_func(int a) {
return imported_optnone_func(a); // use of imported func
}
// CHECK: @_Z21exported_optnone_funci({{.*}}) [[OPTNONE]]
// CHECK: declare dllimport {{.*}} @_Z21imported_optnone_funci({{.*}}) [[DLLIMPORT:#[0-9]+]]
// CHECK: attributes [[OPTNONE]] = { noinline {{.*}} optnone
// CHECK: attributes [[NORETURN]] = { noinline noreturn {{.*}} optnone
// CHECK: attributes [[DLLIMPORT]] =
// CHECK-SAME-NOT: optnone

View File

@ -0,0 +1,164 @@
// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -x c++ | FileCheck %s
// Test attribute 'optnone' on methods:
// -- member functions;
// -- static member functions.
// Verify that all methods of struct A are associated to the same attribute set.
// The attribute set shall contain attributes 'noinline' and 'optnone'.
struct A {
// Definition of an optnone static method.
__attribute__((optnone))
static int static_optnone_method(int a) {
return a + a;
}
// CHECK: @_ZN1A21static_optnone_methodEi({{.*}}) [[OPTNONE:#[0-9]+]]
// Definition of an optnone normal method.
__attribute__((optnone))
int optnone_method(int a) {
return a + a + a + a;
}
// CHECK: @_ZN1A14optnone_methodEi({{.*}}) [[OPTNONE]]
// Declaration of an optnone method with out-of-line definition
// that doesn't say optnone.
__attribute__((optnone))
int optnone_decl_method(int a);
// Methods declared without attribute optnone; the definitions will
// have attribute optnone, and we verify optnone wins.
__forceinline static int static_forceinline_method(int a);
__attribute__((always_inline)) int alwaysinline_method(int a);
__attribute__((noinline)) int noinline_method(int a);
__attribute__((minsize)) int minsize_method(int a);
};
void foo() {
A a;
A::static_optnone_method(4);
a.optnone_method(14);
a.optnone_decl_method(12);
A::static_forceinline_method(5);
a.alwaysinline_method(5);
a.noinline_method(6);
a.minsize_method(7);
}
// No attribute here, should still be on the definition.
int A::optnone_decl_method(int a) {
return a;
}
// CHECK: @_ZN1A19optnone_decl_methodEi({{.*}}) [[OPTNONE]]
// optnone implies noinline; therefore attribute noinline is added to
// the set of function attributes.
// forceinline is instead translated as 'always_inline'.
// However 'noinline' wins over 'always_inline' and therefore
// the resulting attributes for this method are: noinline + optnone
__attribute__((optnone))
int A::static_forceinline_method(int a) {
return a + a + a + a;
}
// CHECK: @_ZN1A25static_forceinline_methodEi({{.*}}) [[OPTNONE]]
__attribute__((optnone))
int A::alwaysinline_method(int a) {
return a + a + a + a;
}
// CHECK: @_ZN1A19alwaysinline_methodEi({{.*}}) [[OPTNONE]]
// 'noinline' + 'noinline and optnone' = 'noinline and optnone'
__attribute__((optnone))
int A::noinline_method(int a) {
return a + a + a + a;
}
// CHECK: @_ZN1A15noinline_methodEi({{.*}}) [[OPTNONE]]
// 'optnone' wins over 'minsize'
__attribute__((optnone))
int A::minsize_method(int a) {
return a + a + a + a;
}
// CHECK: @_ZN1A14minsize_methodEi({{.*}}) [[OPTNONE]]
// Test attribute 'optnone' on methods:
// -- pure virtual functions
// -- base virtual and derived virtual
// -- base virtual but not derived virtual
// -- optnone methods redefined in override
// A method defined in override doesn't inherit the function attributes of the
// superclass method.
struct B {
virtual int pure_virtual(int a) = 0;
__attribute__((optnone))
virtual int pure_virtual_with_optnone(int a) = 0;
virtual int base(int a) {
return a + a + a + a;
}
__attribute__((optnone))
virtual int optnone_base(int a) {
return a + a + a + a;
}
__attribute__((optnone))
virtual int only_base_virtual(int a) {
return a + a;
}
};
struct C : public B {
__attribute__((optnone))
virtual int pure_virtual(int a) {
return a + a + a + a;
}
virtual int pure_virtual_with_optnone(int a) {
return a + a + a + a;
}
__attribute__((optnone))
virtual int base(int a) {
return a + a;
}
virtual int optnone_base(int a) {
return a + a;
}
int only_base_virtual(int a) {
return a + a + a + a;
}
};
int bar() {
C c;
int result;
result = c.pure_virtual(3);
result += c.pure_virtual_with_optnone(2);
result += c.base(5);
result += c.optnone_base(7);
result += c.only_base_virtual(9);
return result;
}
// CHECK: @_ZN1C12pure_virtualEi({{.*}}) {{.*}} [[OPTNONE]]
// CHECK: @_ZN1C25pure_virtual_with_optnoneEi({{.*}}) {{.*}} [[NORMAL:#[0-9]+]]
// CHECK: @_ZN1C4baseEi({{.*}}) {{.*}} [[OPTNONE]]
// CHECK: @_ZN1C12optnone_baseEi({{.*}}) {{.*}} [[NORMAL]]
// CHECK: @_ZN1C17only_base_virtualEi({{.*}}) {{.*}} [[NORMAL]]
// CHECK: @_ZN1B4baseEi({{.*}}) {{.*}} [[NORMAL]]
// CHECK: @_ZN1B12optnone_baseEi({{.*}}) {{.*}} [[OPTNONE]]
// CHECK: @_ZN1B17only_base_virtualEi({{.*}}) {{.*}} [[OPTNONE]]
// CHECK: attributes [[NORMAL]] =
// CHECK-SAME-NOT: noinline
// CHECK-SAME-NOT: optnone
// CHECK: attributes [[OPTNONE]] = {{.*}} noinline {{.*}} optnone

View File

@ -90,5 +90,6 @@ int user_of_forceinline_optnone_function() {
// CHECK: @_Z28forceinline_optnone_functionii({{.*}}) [[OPTNONE]]
// CHECK: attributes [[OPTNONE]] = { noinline nounwind optnone {{.*}} }
// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} }
// CHECK: attributes [[NORMAL]] =
// CHECK-SAME-NOT: noinline
// CHECK-SAME-NOT: optnone

View File

@ -0,0 +1,104 @@
// RUN: %clang_cc1 %s -triple %itanium_abi_triple -std=c++11 -emit-llvm -o - | FileCheck %s
// Test optnone on template instantiations.
//-- Effect of optnone on generic add template function.
template <typename T> T template_normal(T a)
{
return a + a;
}
template <typename T> __attribute__((optnone)) T template_optnone(T a)
{
return a + a + a;
}
// This function should cause instantiations of each template, one marked
// with the 'optnone' attribute.
int container(int i)
{
return template_normal<int>(i) + template_optnone<int>(i);
}
// CHECK: @_Z15template_normalIiET_S0_({{.*}}) [[NORMAL:#[0-9]+]]
// CHECK: @_Z16template_optnoneIiET_S0_({{.*}}) [[OPTNONE:#[0-9]+]]
//-- Effect of optnone on a partial specialization.
// FIRST TEST: a method becomes marked with optnone in the specialization.
template <typename T, typename U> class template_normal_base {
public:
T method(T t, U u)
{
return t + static_cast<T>(u);
}
};
template <typename U> class template_normal_base<int, U>
{
public:
__attribute__((optnone)) int method (int t, U u)
{
return t - static_cast<int>(u);
}
};
// This function should cause an instantiation of the full template (whose
// method is not marked optnone) and an instantiation of the partially
// specialized template (whose method is marked optnone).
void container2()
{
int y = 2;
float z = 3.0;
template_normal_base<float, int> class_normal;
template_normal_base<int, float> class_optnone;
float r1 = class_normal.method(z, y);
float r2 = class_optnone.method(y, z);
}
// CHECK: @_ZN20template_normal_baseIfiE6methodEfi({{.*}}) [[NORMAL]]
// CHECK: @_ZN20template_normal_baseIifE6methodEif({{.*}}) [[OPTNONE]]
//-- Effect of optnone on a partial specialization.
// SECOND TEST: a method loses optnone in the specialization.
template <typename T, typename U> class template_optnone_base {
public:
__attribute__((optnone)) T method(T t, U u)
{
return t + static_cast<T>(u);
}
};
template <typename U> class template_optnone_base<int, U>
{
public:
int method (int t, U u)
{
return t - static_cast<int>(u);
}
};
// This function should cause an instantiation of the full template (whose
// method is marked optnone) and an instantiation of the partially
// specialized template (whose method is not marked optnone).
void container3()
{
int y = 2;
float z = 3.0;
template_optnone_base<float, int> class_optnone;
template_optnone_base<int, float> class_normal;
float r1 = class_optnone.method(z, y);
float r2 = class_normal.method(y, z);
}
// CHECK: @_ZN21template_optnone_baseIfiE6methodEfi({{.*}}) [[OPTNONE]]
// CHECK: @_ZN21template_optnone_baseIifE6methodEif({{.*}}) [[NORMAL]]
// CHECK: attributes [[NORMAL]] =
// CHECK-SAME-NOT: optnone
// CHECK: attributes [[OPTNONE]] = {{.*}} optnone