Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1652,6 +1652,13 @@ let Documentation = [AnyX86InterruptDocs]; } +def AnyX86NoCallerSavedRegisters : InheritableAttr, + TargetSpecificAttr { + let Spellings = [GNU<"no_caller_saved_registers">]; + let Subjects = SubjectList<[FunctionLike], WarnDiag, "ExpectedFunction">; + let Documentation = [AnyX86NoCallerSavedRegistersDocs]; +} + def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr { let Spellings = [GNU<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2170,6 +2170,20 @@ }]; } +def AnyX86NoCallerSavedRegistersDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved. +The compiler generates proper function entry and exit sequences to +save and restore any modified registers. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call clobbered registers. + }]; +} + def SwiftCallDocs : Documentation { let Category = DocCatVariable; let Content = [{ Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1673,6 +1673,8 @@ RetAttrs.addAttribute(llvm::Attribute::NoAlias); if (TargetDecl->hasAttr()) RetAttrs.addAttribute(llvm::Attribute::NonNull); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute("no_caller_saved_registers"); HasAnyX86InterruptAttr = TargetDecl->hasAttr(); HasOptnone = TargetDecl->hasAttr(); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5910,6 +5910,10 @@ handleTypeTagForDatatypeAttr(S, D, Attr); break; + case AttributeList::AT_AnyX86NoCallerSavedRegisters: + handleSimpleAttribute(S, D, Attr); + break; + case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute(S, D, Attr); break; Index: test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp =================================================================== --- test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp +++ test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 %s -emit-llvm -o - | FileCheck %s + +// CHECK: foo{{[^#]*}}#[[ATTRS:[0-9]+]] +__attribute__((no_caller_saved_registers)) void foo() {} +namespace S { +// CHECK: bar{{[^#]*}}#[[ATTRS]] +__attribute__((no_caller_saved_registers)) void bar(int *a) { foo(); } +} + +struct St { + static void baz(int *a) __attribute__((no_caller_saved_registers)) { S::bar(a); } +}; + +__attribute((no_caller_saved_registers)) void (*foobar)(void); + +// CHECK-LABEL: @main +int main(int argc, char **argv) { + St::baz(&argc); + // CHECK: [[FOOBAR:%.+]] = load void ()*, void ()** @{{.*}}foobar{{.*}}, + // CHECK-NEXT: call void [[FOOBAR]]() #[[ATTRS1:.+]] + foobar(); + return 0; +} + +// CHECK: baz{{[^#]*}}#[[ATTRS]] + +// CHECK: attributes #[[ATTRS]] = { +// CHECK-SAME: "no_caller_saved_registers" +// CHECK-SAME: } +// CHECK: attributes #[[ATTRS1]] = { "no_caller_saved_registers" } Index: test/SemaCXX/attr-x86-no_caller_saved_registers.cpp =================================================================== --- test/SemaCXX/attr-x86-no_caller_saved_registers.cpp +++ test/SemaCXX/attr-x86-no_caller_saved_registers.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s + +struct a { + int b __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' attribute only applies to functions}} + static void foo(int *a) __attribute__((no_caller_saved_registers)) {} +}; + +struct a test __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' attribute only applies to functions}} + +__attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-error {{'no_caller_saved_registers' attribute takes no arguments}} + +__attribute__((no_caller_saved_registers)) void foo(int *) {} + +int main(int argc, char **argv) { + a::foo(&argc); + foo(&argc); + return 0; +}