diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1345,6 +1345,13 @@ let SimpleHandler = 1; } +def Addrsig : InheritableAttr { + let Spellings = [Clang<"addrsig">]; + let Documentation = [AddrsigDocs]; + let Subjects = SubjectList<[Function, Var]>; + let SimpleHandler = 1; +} + def FastCall : DeclOrTypeAttr { let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">, Keyword<"_fastcall">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -443,6 +443,18 @@ }]; } +def AddrsigDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Functions or variables attached with ``addrsig`` will be put into the +address-significant table, which disables identical code folding (ICF) on +setions in it (only useful when linking with lld). For the COFF port of lld, the +default icf (``/OPT:safeicf``) will fold code sections regardless the existance +of address-significant table. So, ``/OPT:safeicf`` is needed if you don't want +code sections folding when they are in the table. + }]; +} + def AssertCapabilityDocs : Documentation { let Category = DocCatFunction; let Heading = "assert_capability, assert_shared_capability"; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2054,6 +2054,9 @@ if (MD->isVirtual()) F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + if (FD->hasAttr()) + F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Significant); + // Don't emit entries for function declarations in the cross-DSO mode. This // is handled with better precision by the receiving DSO. But if jump tables // are non-canonical then we need type metadata in order to produce the local @@ -4294,6 +4297,9 @@ if (D->hasAttr()) AddGlobalAnnotations(D, GV); + if (D->hasAttr()) + GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Significant); + // Set the llvm linkage type as appropriate. llvm::GlobalValue::LinkageTypes Linkage = getLLVMLinkageVarDefinition(D, GV->isConstant()); diff --git a/clang/test/CodeGenCXX/attr-addrsig.cpp b/clang/test/CodeGenCXX/attr-addrsig.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-addrsig.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -O2 -o - | FileCheck %s + +// CHECK: @i1 = {{.*}}unnamed_addr +// CHECK-NEXT: @i2 = {{.*}}unnamed_addr +int i1; +int i2 = 0; + +// CHECK: @i3 = {{.*}}significant_addr +// CHECK-NEXT: @i4 = {{.*}}significant_addr +[[clang::addrsig]] int i3; +[[clang::addrsig]] int i4 = 0; + +// CHECK-DAG: declare void @_Z2f1i{{.*}}unnamed_addr +void f1(int i); +// CHECK-DAG: define dso_local i32 @_Z2f2i{{.*}}unnamed_addr +int f2(int i) { + f1(i); + return i * 2; +} + +// CHECK-DAG: declare void @_Z2f3i{{.*}}significant_addr +[[clang::addrsig]] void f3(int i); +void f3(int i); +// CHECK-DAG: define dso_local i32 @_Z2f4i{{.*}}significant_addr +[[clang::addrsig]] int f4(int i) { + f3(i); + return i * 2; +} + + +// CHECK-DAG: declare void @_ZN1AC1Ev{{.*}}unnamed_addr +// CHECK-DAG: declare void @_ZN1AD1Ev{{.*}}unnamed_addr +// CHECK-DAG: declare void @_ZN1A2f1Ev{{.*}}unnamed_addr +// CHECK-DAG: declare void @_ZN1A2f2Ev{{.*}}unnamed_addr + +// CHECK-DAG: declare void @_ZN1BC1Ev{{.*}}significant_addr +// CHECK-DAG: declare void @_ZN1BD1Ev{{.*}}significant_addr +// CHECK-DAG: declare void @_ZN1B2f1Ev{{.*}}significant_addr +// CHECK-DAG: declare void @_ZN1B2f2Ev{{.*}}significant_addr +struct A { + A(); + ~A(); + void f1(); + virtual void f2(); +}; + +struct B { + [[clang::addrsig]] B(); + [[clang::addrsig]] ~B(); + [[clang::addrsig]] void f1(); + [[clang::addrsig]] virtual void f2(); +}; + +void test() { + A a; + B b; + a.f1(); + a.f2(); + b.f1(); + b.f2(); +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -10,6 +10,7 @@ // CHECK-NEXT: AVRSignal (SubjectMatchRule_function) // CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace) // CHECK-NEXT: AcquireHandle (SubjectMatchRule_function, SubjectMatchRule_type_alias, SubjectMatchRule_variable_is_parameter) +// CHECK-NEXT: Addrsig (SubjectMatchRule_function, SubjectMatchRule_variable) // CHECK-NEXT: Alias (SubjectMatchRule_function, SubjectMatchRule_variable_is_global) // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias) // CHECK-NEXT: AllocSize (SubjectMatchRule_function) diff --git a/clang/test/Sema/attr-addrsig.c b/clang/test/Sema/attr-addrsig.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-addrsig.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +__attribute__((addrsig)) int i; + +__attribute__((addrsig)) void f(); +__attribute__((addrsig)) void g() {} + +struct __attribute__((addrsig)) A {}; // expected-warning {{'addrsig' attribute only applies to functions and variables}}