Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3086,3 +3086,10 @@ let Subjects = SubjectList<[Var]>; let Documentation = [AlwaysDestroyDocs]; } + +def SpeculativeLoadHardening : InheritableAttr { + let Spellings = [GNU<"speculative_load_hardening">, + CXX11<"", "speculative_load_hardening", 201811>]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [SpeculativeLoadHardeningDocs]; +} Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3604,3 +3604,30 @@ ``-std=c89``, ``-std=c94``, or ``-fgnu89-inline``. }]; } + +def SpeculativeLoadHardeningDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +This attribute indicates that +`Speculative Load Hardening `_ +should be enabled for the function body. This is a best-effort attempt to +mitigate all known speculative execution information leak vulnerabilities +that are based on the fundamental principles of modern processors' +speculative execution. These vulnerabilities are classified as "Spectre +variant #1" vulnerabilities typically. Notably, this does not attempt to +mitigate any vulnerabilities where the speculative execution and/or +prediction devices of specific processors can be *completely* undermined +(such as "Branch Target Injection", a.k.a, "Spectre variant #2"). Instead, +this is a target-independent request to harden against the completely +generic risk posed by speculative execution to incorrectly load secret data, +making it available to some micro-architectural side-channel for information +leak. For a processor without any speculative execution or predictors, this +is expected to be a no-op. + +When inlining, the attribute is sticky. Inlining a function that carries +this attribute will cause the caller to gain the attribute. This is intended +to provide a maximally conservative model where the code in a function +annotated with this attribute will always (even after inlining) end up +hardened. + }]; +} Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1850,6 +1850,8 @@ 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( Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6365,6 +6365,9 @@ case ParsedAttr::AT_Section: handleSectionAttr(S, D, AL); break; + case ParsedAttr::AT_SpeculativeLoadHardening: + handleSimpleAttribute(S, D, AL); + break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); break; Index: clang/test/CodeGen/attr-speculative-load-hardening.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-speculative-load-hardening.cpp @@ -0,0 +1,18 @@ +// 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. + +[[speculative_load_hardening]] +int test1() { + return 42; +} + +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{{.*}} } Index: clang/test/SemaCXX/attr-speculative-load-hardening.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/attr-speculative-load-hardening.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +int i __attribute__((speculative_load_hardening)); // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + +void f1() __attribute__((speculative_load_hardening)); +void f2() __attribute__((speculative_load_hardening(1))); // expected-error {{'speculative_load_hardening' attribute takes no arguments}} + +template +void tf1() __attribute__((speculative_load_hardening)); + +int f3(int __attribute__((speculative_load_hardening)), int); // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + +struct A { + int f __attribute__((speculative_load_hardening)); // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + void mf1() __attribute__((speculative_load_hardening)); + static void mf2() __attribute__((speculative_load_hardening)); +}; + +int ci [[speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + +[[speculative_load_hardening]] void cf1(); +[[speculative_load_hardening(1)]] void cf2(); // expected-error {{'speculative_load_hardening' attribute takes no arguments}} + +template +[[speculative_load_hardening]] +void ctf1(); + +int cf3(int c[[speculative_load_hardening]], int); // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + +struct CA { + int f [[speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}} + [[speculative_load_hardening]] void mf1(); + [[speculative_load_hardening]] static void mf2(); +};