zequanwu created this revision.
zequanwu added reviewers: pcc, aaron.ballman, rnk, rsmith.
Herald added subscribers: dexonsmith, jdoerfert, hiraditya.
zequanwu requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Functions or variables with this attribute will not have 
local_unnamed_addr/unnamed_addr in IR. So, they will show up in 
address-significant table.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D98295

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/test/CodeGenCXX/attr-addrsig.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/Sema/attr-addrsig.c
  llvm/include/llvm/IR/GlobalValue.h
  llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
  llvm/lib/IR/AsmWriter.cpp
  llvm/lib/IR/Core.cpp
  llvm/lib/Transforms/IPO/GlobalOpt.cpp

Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp
===================================================================
--- llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -2107,9 +2107,11 @@
     return false;
 
   bool Changed = false;
-  if (!GS.IsCompared && !GV.hasGlobalUnnamedAddr()) {
-    auto NewUnnamedAddr = GV.hasLocalLinkage() ? GlobalValue::UnnamedAddr::Global
-                                               : GlobalValue::UnnamedAddr::Local;
+  if (!GS.IsCompared && !GV.hasGlobalUnnamedAddr() &&
+      GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::Addrsig) {
+    auto NewUnnamedAddr = GV.hasLocalLinkage()
+                              ? GlobalValue::UnnamedAddr::Global
+                              : GlobalValue::UnnamedAddr::Local;
     if (NewUnnamedAddr != GV.getUnnamedAddr()) {
       GV.setUnnamedAddr(NewUnnamedAddr);
       NumUnnamed++;
Index: llvm/lib/IR/Core.cpp
===================================================================
--- llvm/lib/IR/Core.cpp
+++ llvm/lib/IR/Core.cpp
@@ -1991,6 +1991,7 @@
 
 LLVMUnnamedAddr LLVMGetUnnamedAddress(LLVMValueRef Global) {
   switch (unwrap<GlobalValue>(Global)->getUnnamedAddr()) {
+  case GlobalVariable::UnnamedAddr::Addrsig:
   case GlobalVariable::UnnamedAddr::None:
     return LLVMNoUnnamedAddr;
   case GlobalVariable::UnnamedAddr::Local:
Index: llvm/lib/IR/AsmWriter.cpp
===================================================================
--- llvm/lib/IR/AsmWriter.cpp
+++ llvm/lib/IR/AsmWriter.cpp
@@ -3487,6 +3487,7 @@
 
 static StringRef getUnnamedAddrEncoding(GlobalVariable::UnnamedAddr UA) {
   switch (UA) {
+  case GlobalVariable::UnnamedAddr::Addrsig:
   case GlobalVariable::UnnamedAddr::None:
     return "";
   case GlobalVariable::UnnamedAddr::Local:
Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
===================================================================
--- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1117,6 +1117,7 @@
 
 static unsigned getEncodedUnnamedAddr(const GlobalValue &GV) {
   switch (GV.getUnnamedAddr()) {
+  case GlobalValue::UnnamedAddr::Addrsig:
   case GlobalValue::UnnamedAddr::None:   return 0;
   case GlobalValue::UnnamedAddr::Local:  return 2;
   case GlobalValue::UnnamedAddr::Global: return 1;
Index: llvm/include/llvm/IR/GlobalValue.h
===================================================================
--- llvm/include/llvm/IR/GlobalValue.h
+++ llvm/include/llvm/IR/GlobalValue.h
@@ -188,6 +188,7 @@
   unsigned getAddressSpace() const;
 
   enum class UnnamedAddr {
+    Addrsig,
     None,
     Local,
     Global,
@@ -203,7 +204,8 @@
   /// table. It should probably not be used in optimizations, as the value may
   /// have uses outside the module; use hasGlobalUnnamedAddr() instead.
   bool hasAtLeastLocalUnnamedAddr() const {
-    return getUnnamedAddr() != UnnamedAddr::None;
+    return getUnnamedAddr() != UnnamedAddr::Addrsig &&
+           getUnnamedAddr() != UnnamedAddr::None;
   }
 
   UnnamedAddr getUnnamedAddr() const {
@@ -212,6 +214,8 @@
   void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = unsigned(Val); }
 
   static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) {
+    if (A == UnnamedAddr::Addrsig || B == UnnamedAddr::Addrsig)
+      return UnnamedAddr::Addrsig;
     if (A == UnnamedAddr::None || B == UnnamedAddr::None)
       return UnnamedAddr::None;
     if (A == UnnamedAddr::Local || B == UnnamedAddr::Local)
Index: clang/test/Sema/attr-addrsig.c
===================================================================
--- /dev/null
+++ 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}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ 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)
Index: clang/test/CodeGenCXX/attr-addrsig.cpp
===================================================================
--- /dev/null
+++ 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-NOT: @i3 = {{.*}}unnamed_addr
+// CHECK-NOT: @i4 = {{.*}}unnamed_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-NOT: @_Z3f1v{{.*}}unnamed_addr
+[[clang::addrsig]] void f3(int i);
+void f3(int i);
+// CHECK-NOT: @_Z4f1v{{.*}}unnamed_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({{.*}}) #1
+// CHECK-DAG: declare void @_ZN1BD1Ev({{.*}}) #3
+// CHECK-DAG: declare void @_ZN1B2f1Ev({{.*}}) #1
+// CHECK-DAG: declare void @_ZN1B2f2Ev({{.*}}) #1
+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();
+}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2054,6 +2054,9 @@
     if (MD->isVirtual())
       F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
 
+  if (FD->hasAttr<AddrsigAttr>())
+    F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Addrsig);
+
   // 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<AnnotateAttr>())
     AddGlobalAnnotations(D, GV);
 
+  if (D->hasAttr<AddrsigAttr>())
+    GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Addrsig);
+
   // Set the llvm linkage type as appropriate.
   llvm::GlobalValue::LinkageTypes Linkage =
       getLLVMLinkageVarDefinition(D, GV->isConstant());
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ 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";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ 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">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to