Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -254,6 +254,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"]; } @@ -2029,6 +2030,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 @@ -494,6 +494,19 @@ }]; } +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. + +.. _`/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 @@ -1749,6 +1749,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"); + } } } @@ -2079,6 +2083,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 @@ -1663,15 +1663,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; @@ -3672,7 +3663,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( @@ -5525,7 +5518,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); @@ -5748,6 +5742,10 @@ break; // Microsoft attributes: + case AttributeList::AT_MSHookPrologue: + handleSimpleAttributeWithExclusions(S, D, Attr); + break; case AttributeList::AT_MSNoVTable: handleSimpleAttribute(S, D, Attr); break; 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.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)));