Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -257,6 +257,7 @@ def TargetMSP430 : TargetArch<["msp430"]>; def TargetX86 : TargetArch<["x86"]>; def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; +def TargetWindowsArches : TargetArch<["x86", "x86_64", "arm", "thumb"]>; def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> { let OSes = ["Win32"]; } @@ -2069,6 +2070,12 @@ // Microsoft-related attributes +def MSHookPrologue : InheritableAttr, TargetSpecificAttr { + let Spellings = [GCC<"ms_hook_prologue">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MSHookPrologueDocs]; +} + def MSNoVTable : InheritableAttr, TargetSpecificAttr { let Spellings = [Declspec<"novtable">]; let Subjects = SubjectList<[CXXRecord]>; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -548,6 +548,22 @@ }]; } +def MSHookPrologueDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``ms_hook_prologue`` attribute marks a function as "hotpatchable" according +to conventions used on Windows. Specifically, enough space will be ensured +in the prologue for a short jump, and an architecturally dependently sized +patch space will be reserved prior to the entry point. See the documentation +for the `/HOTPATCH`_ switch on MSDN. + +This attribute cannot be used in conjunction with the ``naked``, +``always_inline``, or ``__forceinline`` attributes. + +.. _`/HOTPATCH`: https://msdn.microsoft.com/en-us/library/ms173507.aspx + }]; +} + def NoDebugDocs : Documentation { let Category = DocCatVariable; let Content = [{ Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -1783,6 +1783,10 @@ llvm::Function *Fn = cast(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); } + if (FD->hasAttr()) { + llvm::Function *Fn = cast(GV); + Fn->addFnAttr("patchable-function", "ms-hotpatch"); + } } } @@ -2113,6 +2117,10 @@ llvm::Function *Fn = cast(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); } + if (FD->hasAttr()) { + llvm::Function *Fn = cast(GV); + Fn->addFnAttr("patchable-function", "ms-hotpatch"); + } } } }; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -1664,15 +1664,6 @@ D->addAttr(CA); } -static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { if (hasDeclarator(D)) return; @@ -3673,7 +3664,9 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (checkAttrMutualExclusion(S, D, Attr.getRange(), - Attr.getName())) + Attr.getName()) || + checkAttrMutualExclusion(S, D, Attr.getRange(), + Attr.getName())) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( @@ -5552,7 +5545,8 @@ handleHotAttr(S, D, Attr); break; case AttributeList::AT_Naked: - handleNakedAttr(S, D, Attr); + handleSimpleAttributeWithExclusions(S, D, Attr); break; case AttributeList::AT_NoReturn: handleNoReturnAttr(S, D, Attr); @@ -5780,6 +5774,9 @@ break; case AttributeList::AT_LayoutVersion: handleLayoutVersion(S, D, Attr); + case AttributeList::AT_MSHookPrologue: + handleSimpleAttributeWithExclusions(S, D, Attr); break; case AttributeList::AT_MSNoVTable: handleSimpleAttribute(S, D, Attr); Index: test/CodeGen/function-attributes.c =================================================================== --- test/CodeGen/function-attributes.c +++ test/CodeGen/function-attributes.c @@ -108,11 +108,18 @@ _setjmp(0); } +// CHECK-LABEL: define void @f21 +// CHECK: [[HOTPATCH:#[0-9]+]] +// CHECK: { +void __attribute__((ms_hook_prologue)) f21(void) { +} + // CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} } // CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} } // CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} } // CHECK: attributes [[ALIGN]] = { nounwind optsize alignstack=16{{.*}} } // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} } +// CHECK: attributes [[HOTPATCH]] = { nounwind optsize{{.*}}"patchable-function"="ms-hotpatch"{{.*}} } // CHECK: attributes [[NR]] = { noreturn optsize } // CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone } // CHECK: attributes [[RT_CALL]] = { optsize returns_twice } Index: test/Sema/attr-ms-hook-prologue-wrong-arch.c =================================================================== --- /dev/null +++ test/Sema/attr-ms-hook-prologue-wrong-arch.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple s390x-unknown-linux -fms-extensions -fsyntax-only -verify %s + +// expected-warning@+1{{unknown attribute 'ms_hook_prologue' ignored}} +int __attribute__((ms_hook_prologue)) foo(int a, int b) { + return a+b; +} Index: test/Sema/attr-ms-hook-prologue.c =================================================================== --- /dev/null +++ test/Sema/attr-ms-hook-prologue.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple i386-pc-linux -fms-extensions -fsyntax-only -verify %s + +int __attribute__((ms_hook_prologue)) foo(int a, int b) { + return a+b; +} + +// expected-note@+2{{conflicting attribute is here}} +// expected-error@+1{{'naked' and 'ms_hook_prologue' attributes are not compatible}} +__declspec(naked) int __attribute__((ms_hook_prologue)) bar(int a, int b) { +} + +// expected-note@+2{{conflicting attribute is here}} +// expected-error@+1{{'__forceinline' and 'ms_hook_prologue' attributes are not compatible}} +__forceinline int __attribute__((ms_hook_prologue)) baz(int a, int b) { + return a-b; +} + +// expected-warning@+1{{'ms_hook_prologue' attribute only applies to functions}} +int x __attribute__((ms_hook_prologue)); + +// expected-error@+1{{'ms_hook_prologue' attribute takes no arguments}} +int f(int a, int b) __attribute__((ms_hook_prologue(2)));