Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3097,3 +3097,9 @@ let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [SpeculativeLoadHardeningDocs]; } + +def NoSpeculativeLoadHardening : InheritableAttr { + let Spellings = [Clang<"no_speculative_load_hardening">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSpeculativeLoadHardeningDocs]; +} Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3652,3 +3652,20 @@ (even after inlining) end up hardened. }]; } + +def NoSpeculativeLoadHardeningDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + should NOT be enabled for the function body. + + Warning: This attribute may not prevent Speculative Load Hardening from being + enabled for a function which inlines a function that has the + 'speculative_load_hardening' attribute. This is intended to provide a + maximally conservative model where the code that is marked with the + 'speculative_load_hardening' attribute will always (even as inlining) + be hardened. A user of this attribute may want to mark functions called by + a function they do not want to be hardened with the 'noinline' attribute. + }]; +} Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1791,8 +1791,6 @@ if (CodeGenOpts.Backchain) FuncAttrs.addAttribute("backchain"); - // FIXME: The interaction of this attribute with the SLH command line flag - // has not been determined. if (CodeGenOpts.SpeculativeLoadHardening) FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); } @@ -1856,8 +1854,6 @@ FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::Convergent); - if (TargetDecl->hasAttr()) - FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { AddAttributesFromFunctionProtoType( @@ -1902,6 +1898,16 @@ ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs); + // This must run after constructing the default function attribute list + // to ensure that the speculative load hardening attribute is removed + // in the case where the -mspeculative-load-hardening flag was passed. + if (TargetDecl) { + if (TargetDecl->hasAttr()) + FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); + } + if (CodeGenOpts.EnableSegmentedStacks && !(TargetDecl && TargetDecl->hasAttr())) FuncAttrs.addAttribute("split-stack"); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6376,6 +6376,9 @@ case ParsedAttr::AT_SpeculativeLoadHardening: handleSimpleAttribute(S, D, AL); break; + case ParsedAttr::AT_NoSpeculativeLoadHardening: + handleSimpleAttribute(S, D, AL); + break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); break; Index: clang/test/CodeGen/attr-speculative-load-hardening.cpp =================================================================== --- clang/test/CodeGen/attr-speculative-load-hardening.cpp +++ clang/test/CodeGen/attr-speculative-load-hardening.cpp @@ -1,7 +1,23 @@ +// Check that we set the attribute on each function. // RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK1 // RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK2 -// -// Check that we set the attribute on each function. + +// Check that we did not set the attribute on each function +// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK7 +// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK8 + + +// Check that we did not set the attribute on each function despite the +// -mspeculative-load-hardening flag. +// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK3 +// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK4 + + +// Check that we did set the attribute on each function despite the +// -mno-speculative-load-hardening flag. +// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK5 +// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK6 + [[clang::speculative_load_hardening]] int test1() { @@ -11,8 +27,35 @@ int __attribute__((speculative_load_hardening)) test2() { return 42; } -// CHECK1: @{{.*}}test1{{.*}}[[SLH1:#[0-9]+]] -// CHECK1: attributes [[SLH1]] = { {{.*}}speculative_load_hardening{{.*}} } -// CHECK2: @{{.*}}test2{{.*}}[[SLH2:#[0-9]+]] -// CHECK2: attributes [[SLH2]] = { {{.*}}speculative_load_hardening{{.*}} } +[[clang::no_speculative_load_hardening]] +int test3() { + return 42; +} + +int __attribute__((no_speculative_load_hardening)) test4() { + return 42; +} +// CHECK1: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]] +// CHECK1: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK2: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]] +// CHECK2: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } +// +// CHECK7: @{{.*}}test3{{.*}}[[SLH:#[0-9]+]] +// CHECK7-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK8: @{{.*}}test4{{.*}}[[SLH:#[0-9]+]] +// CHECK8-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK3: @{{.*}}test3{{.*}}[[SLH:#[0-9]+]] +// CHECK3-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK4: @{{.*}}test4{{.*}}[[SLH:#[0-9]+]] +// CHECK4-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK5: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]] +// CHECK5: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK6: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]] +// CHECK6: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }