From edea169440f3e509af537e44352a1fb12155dd82 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 19 May 2014 22:14:34 +0000 Subject: [PATCH] Implement the no_split_stack attribute. This is a GNU attribute that allows split stacks to be turned off on a per-function basis. Differential Revision: http://reviews.llvm.org/D3817 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209167 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 6 +++++ include/clang/Basic/AttrDocs.td | 9 ++++++++ lib/CodeGen/CGCall.cpp | 3 ++- lib/Sema/SemaDeclAttr.cpp | 3 +++ test/CodeGen/split-stacks.c | 14 +++++++++--- test/CodeGenCXX/split-stacks.cpp | 33 +++++++++++++++++++++++++++ test/SemaCXX/attr-no-split-stack.cpp | 34 ++++++++++++++++++++++++++++ 7 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 test/CodeGenCXX/split-stacks.cpp create mode 100644 test/SemaCXX/attr-no-split-stack.cpp diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 5c5e597993..a243994e20 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -823,6 +823,12 @@ def NoMips16 : InheritableAttr, TargetSpecificAttr { let Documentation = [Undocumented]; } +def NoSplitStack : InheritableAttr { + let Spellings = [GCC<"no_split_stack">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSplitStackDocs]; +} + def NonNull : InheritableAttr { let Spellings = [GCC<"nonnull">]; let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag, diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index a5eb25c1d9..a0c2028512 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -371,6 +371,15 @@ of the condition. }]; } +def NoSplitStackDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``no_split_stack`` attribute disables the emission of the split stack +preamble for a particular function. It has no effect if ``-fsplit-stack`` +is not specified. + }]; +} + def ObjCRequiresSuperDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 61bf985278..e477a54c67 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -1117,7 +1117,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs.addAttribute(llvm::Attribute::NoRedZone); if (CodeGenOpts.NoImplicitFloat) FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat); - if (CodeGenOpts.EnableSegmentedStacks) + if (CodeGenOpts.EnableSegmentedStacks && + !(TargetDecl && TargetDecl->hasAttr())) FuncAttrs.addAttribute("split-stack"); if (AttrOnCallSite) { diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 2e97a8aa9d..b7c1d5d15b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -4180,6 +4180,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoCommon: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_NoSplitStack: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_NonNull: if (ParmVarDecl *PVD = dyn_cast(D)) handleNonNullAttrParameter(S, PVD, Attr); diff --git a/test/CodeGen/split-stacks.c b/test/CodeGen/split-stacks.c index 98112467a5..bf4cf0f026 100644 --- a/test/CodeGen/split-stacks.c +++ b/test/CodeGen/split-stacks.c @@ -5,13 +5,21 @@ int foo() { return 0; } +__attribute__((no_split_stack)) +int nosplit() { + return 0; +} + int main() { return foo(); } -// CHECK-SEGSTK: define i32 @foo() #0 { -// CHECK-SEGSTK: define i32 @main() #0 { -// CHECK-SEGSTK: #0 = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK: define i32 @foo() [[SS:#[0-9]+]] { +// CHECK-SEGSTK: define i32 @nosplit() [[NSS:#[0-9]+]] { +// CHECK-SEGSTK: define i32 @main() [[SS]] { +// CHECK-SEGSTK-NOT: [[NSS]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK: [[SS]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK-NOT: [[NSS]] = { {{.*}} "split-stack" {{.*}} } // CHECK-NOSEGSTK: define i32 @foo() #0 { // CHECK-NOSEGSTK: define i32 @main() #0 { diff --git a/test/CodeGenCXX/split-stacks.cpp b/test/CodeGenCXX/split-stacks.cpp new file mode 100644 index 0000000000..3e120344d6 --- /dev/null +++ b/test/CodeGenCXX/split-stacks.cpp @@ -0,0 +1,33 @@ +// RUN: %clang -target x86_64-linux-gnu -fsplit-stack -S -std=c++11 %s -emit-llvm -o - | FileCheck -check-prefix=CHECK-SEGSTK %s +// RUN: %clang -target x86_64-linux-gnu -S -std=c++11 %s -emit-llvm -o - | FileCheck -check-prefix=CHECK-NOSEGSTK %s + +int foo() { + return 0; +} + +template +[[gnu::no_split_stack]] +int tnosplit() { + return 0; +} + +[[gnu::no_split_stack]] +int nosplit() { + return tnosplit(); +} + +// CHECK-SEGSTK: define i32 @_Z3foov() [[SS:#[0-9]+]] { +// CHECK-SEGSTK: define i32 @_Z7nosplitv() [[NSS1:#[0-9]+]] { +// CHECK-SEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] { +// CHECK-SEGSTK-NOT: [[NSS1]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK-NOT: [[NSS2]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK: [[SS]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK-NOT: [[NSS1]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-SEGSTK-NOT: [[NSS2]] = { {{.*}} "split-stack" {{.*}} } + +// CHECK-NOSEGSTK: define i32 @_Z3foov() [[NSS0:#[0-9]+]] { +// CHECK-NOSEGSTK: define i32 @_Z7nosplitv() [[NSS1:#[0-9]+]] { +// CHECK-NOSEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] { +// CHECK-NOSEGSTK-NOT: [[NSS1]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-NOSEGSTK-NOT: [[NSS2]] = { {{.*}} "split-stack" {{.*}} } +// CHECK-NOSEGSTK-NOT: [[NSS3]] = { {{.*}} "split-stack" {{.*}} } diff --git a/test/SemaCXX/attr-no-split-stack.cpp b/test/SemaCXX/attr-no-split-stack.cpp new file mode 100644 index 0000000000..3575e9983f --- /dev/null +++ b/test/SemaCXX/attr-no-split-stack.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +int i __attribute__((no_split_stack)); // expected-error {{'no_split_stack' attribute only applies to functions}} + +void f1() __attribute__((no_split_stack)); +void f2() __attribute__((no_split_stack(1))); // expected-error {{'no_split_stack' attribute takes no arguments}} + +template +void tf1() __attribute__((no_split_stack)); + +int f3(int __attribute__((no_split_stack)), int); // expected-error{{'no_split_stack' attribute only applies to functions}} + +struct A { + int f __attribute__((no_split_stack)); // expected-error{{'no_split_stack' attribute only applies to functions}} + void mf1() __attribute__((no_split_stack)); + static void mf2() __attribute__((no_split_stack)); +}; + +int ci [[gnu::no_split_stack]]; // expected-error {{'no_split_stack' attribute only applies to functions}} + +[[gnu::no_split_stack]] void cf1(); +[[gnu::no_split_stack(1)]] void cf2(); // expected-error {{'no_split_stack' attribute takes no arguments}} + +template +[[gnu::no_split_stack]] +void ctf1(); + +int cf3(int c[[gnu::no_split_stack]], int); // expected-error{{'no_split_stack' attribute only applies to functions}} + +struct CA { + int f [[gnu::no_split_stack]]; // expected-error{{'no_split_stack' attribute only applies to functions}} + [[gnu::no_split_stack]] void mf1(); + [[gnu::no_split_stack]] static void mf2(); +}; -- 2.40.0