summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/Attr.td7
-rw-r--r--clang/include/clang/Basic/AttrDocs.td16
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp8
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp19
-rw-r--r--clang/test/CodeGen/function-attributes.c7
-rw-r--r--clang/test/Sema/attr-ms-hook-prologue-wrong-arch.c6
-rw-r--r--clang/test/Sema/attr-ms-hook-prologue.c22
7 files changed, 74 insertions, 11 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 7da1efe5ff4..49a3273b77f 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -257,6 +257,7 @@ def TargetMips : TargetArch<["mips", "mipsel"]>;
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 @@ def TypeTagForDatatype : InheritableAttr {
// Microsoft-related attributes
+def MSHookPrologue : InheritableAttr, TargetSpecificAttr<TargetWindowsArches> {
+ let Spellings = [GCC<"ms_hook_prologue">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [MSHookPrologueDocs];
+}
+
def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
let Spellings = [Declspec<"novtable">];
let Subjects = SubjectList<[CXXRecord]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 9b1ddca05a5..4a78f53754f 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -548,6 +548,22 @@ Query for this feature with ``__has_attribute(objc_method_family)``.
}];
}
+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 = [{
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index fa1b58ddd52..1e8ac639931 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -1779,6 +1779,10 @@ void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
llvm::Function *Fn = cast<llvm::Function>(GV);
Fn->setCallingConv(llvm::CallingConv::X86_INTR);
}
+ if (FD->hasAttr<MSHookPrologueAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ Fn->addFnAttr("patchable-function", "ms-hotpatch");
+ }
}
}
@@ -2109,6 +2113,10 @@ public:
llvm::Function *Fn = cast<llvm::Function>(GV);
Fn->setCallingConv(llvm::CallingConv::X86_INTR);
}
+ if (FD->hasAttr<MSHookPrologueAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ Fn->addFnAttr("patchable-function", "ms-hotpatch");
+ }
}
}
};
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index d74cebc718c..5dbe7aa52ea 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1664,15 +1664,6 @@ static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(CA);
}
-static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (checkAttrMutualExclusion<DisableTailCallsAttr>(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 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(),
- Attr.getName()))
+ Attr.getName()) ||
+ checkAttrMutualExclusion<MSHookPrologueAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
@@ -5552,7 +5545,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleHotAttr(S, D, Attr);
break;
case AttributeList::AT_Naked:
- handleNakedAttr(S, D, Attr);
+ handleSimpleAttributeWithExclusions<NakedAttr, DisableTailCallsAttr,
+ MSHookPrologueAttr>(S, D, Attr);
break;
case AttributeList::AT_NoReturn:
handleNoReturnAttr(S, D, Attr);
@@ -5780,6 +5774,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
break;
case AttributeList::AT_LayoutVersion:
handleLayoutVersion(S, D, Attr);
+ case AttributeList::AT_MSHookPrologue:
+ handleSimpleAttributeWithExclusions<MSHookPrologueAttr, NakedAttr,
+ AlwaysInlineAttr>(S, D, Attr);
break;
case AttributeList::AT_MSNoVTable:
handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr);
diff --git a/clang/test/CodeGen/function-attributes.c b/clang/test/CodeGen/function-attributes.c
index 8f682a715d7..d0374c18660 100644
--- a/clang/test/CodeGen/function-attributes.c
+++ b/clang/test/CodeGen/function-attributes.c
@@ -108,11 +108,18 @@ void f20(void) {
_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 }
diff --git a/clang/test/Sema/attr-ms-hook-prologue-wrong-arch.c b/clang/test/Sema/attr-ms-hook-prologue-wrong-arch.c
new file mode 100644
index 00000000000..cd4b591cbb3
--- /dev/null
+++ b/clang/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;
+}
diff --git a/clang/test/Sema/attr-ms-hook-prologue.c b/clang/test/Sema/attr-ms-hook-prologue.c
new file mode 100644
index 00000000000..5417f4aa59c
--- /dev/null
+++ b/clang/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)));
OpenPOWER on IntegriCloud