r306347 - AST: enhance mangling for blocks with MS ABI

Saleem Abdulrasool via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 26 16:28:42 PDT 2017


Author: compnerd
Date: Mon Jun 26 16:28:42 2017
New Revision: 306347

URL: http://llvm.org/viewvc/llvm-project?rev=306347&view=rev
Log:
AST: enhance mangling for blocks with MS ABI

When generating the decorated name for a static variable inside a
BlockDecl, construct a scope for the block invocation function that
homes the parameter. This allows for arbitrary nesting of the blocks
even if the variables are shadowed. Furthermore, using this for the name
allows for undname to properly undecorated the name for us. It shows up
as the synthetic __block_invocation function that the compiler emitted
in the local scope.

Added:
    cfe/trunk/test/CodeGenCXX/msabi-blocks.cpp
Modified:
    cfe/trunk/lib/AST/MicrosoftMangle.cpp

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=306347&r1=306346&r2=306347&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Mon Jun 26 16:28:42 2017
@@ -966,16 +966,71 @@ void MicrosoftCXXNameMangler::mangleNest
     }
 
     if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
-      DiagnosticsEngine &Diags = Context.getDiags();
-      unsigned DiagID =
-          Diags.getCustomDiagID(DiagnosticsEngine::Error,
-                                "cannot mangle a local inside this block yet");
-      Diags.Report(BD->getLocation(), DiagID);
-
-      // FIXME: This is completely, utterly, wrong; see ItaniumMangle
-      // for how this should be done.
-      Out << "__block_invoke" << Context.getBlockId(BD, false);
-      Out << '@';
+      auto Discriminate =
+          [](StringRef Name, const unsigned Discriminator,
+             const unsigned ParameterDiscriminator) -> std::string {
+        std::string Buffer;
+        llvm::raw_string_ostream Stream(Buffer);
+        Stream << Name;
+        if (Discriminator)
+          Stream << '_' << Discriminator;
+        if (ParameterDiscriminator)
+          Stream << '_' << ParameterDiscriminator;
+        return Stream.str();
+      };
+
+      unsigned Discriminator = BD->getBlockManglingNumber();
+      if (!Discriminator)
+        Discriminator = Context.getBlockId(BD, /*Local=*/false);
+
+      // Mangle the parameter position as a discriminator to deal with unnamed
+      // parameters.  Rather than mangling the unqualified parameter name,
+      // always use the position to give a uniform mangling.
+      unsigned ParameterDiscriminator = 0;
+      if (const auto *MC = BD->getBlockManglingContextDecl())
+        if (const auto *P = dyn_cast<ParmVarDecl>(MC))
+          if (const auto *F = dyn_cast<FunctionDecl>(P->getDeclContext()))
+            ParameterDiscriminator =
+                F->getNumParams() - P->getFunctionScopeIndex();
+
+      DC = getEffectiveDeclContext(BD);
+
+      Out << '?';
+      mangleSourceName(Discriminate("_block_invoke", Discriminator,
+                                    ParameterDiscriminator));
+      // If we have a block mangling context, encode that now.  This allows us
+      // to discriminate between named static data initializers in the same
+      // scope.  This is handled differently from parameters, which use
+      // positions to discriminate between multiple instances.
+      if (const auto *MC = BD->getBlockManglingContextDecl())
+        if (!isa<ParmVarDecl>(MC))
+          if (const auto *ND = dyn_cast<NamedDecl>(MC))
+            mangleUnqualifiedName(ND);
+      // MS ABI and Itanium manglings are in inverted scopes.  In the case of a
+      // RecordDecl, mangle the entire scope hierachy at this point rather than
+      // just the unqualified name to get the ordering correct.
+      if (const auto *RD = dyn_cast<RecordDecl>(DC))
+        mangleName(RD);
+      else
+        Out << '@';
+      // void __cdecl
+      Out << "YAX";
+      // struct __block_literal *
+      Out << 'P';
+      // __ptr64
+      if (PointersAre64Bit)
+        Out << 'E';
+      Out << 'A';
+      mangleArtificalTagType(TTK_Struct,
+                             Discriminate("__block_literal", Discriminator,
+                                          ParameterDiscriminator));
+      Out << "@Z";
+
+      // If the effective context was a Record, we have fully mangled the
+      // qualified name and do not need to continue.
+      if (isa<RecordDecl>(DC))
+        break;
+      continue;
     } else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
       mangleObjCMethodName(Method);
     } else if (isa<NamedDecl>(DC)) {

Added: cfe/trunk/test/CodeGenCXX/msabi-blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/msabi-blocks.cpp?rev=306347&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/msabi-blocks.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/msabi-blocks.cpp Mon Jun 26 16:28:42 2017
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X86
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X64
+
+extern int e(void);
+
+void (^b)() = ^{
+  static int i = 0;
+};
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke@@YAXPAU__block_literal@@@Z at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke@@YAXPEAU__block_literal@@@Z at 4HA" ={{.*}} global i32 0
+
+void f(void) {
+  static int i = 0;
+  ^{ static int i = e(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+
+  ^{ static int i = e(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_2@@YAXPAU__block_literal_2@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_2@@YAXPEAU__block_literal_2@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+
+  ^{ ^{ static int i = e(); }(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_3@@YAXPAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPAU__block_literal_4@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_3@@YAXPEAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPEAU__block_literal_4@@@Z?1??f@@YAXXZ at 4HA" ={{.*}} global i32 0
+}
+
+
+template <typename>
+void g(void) {
+  ^{ static int i = e(); }();
+}
+
+template void g<char>(void);
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g at D@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g at D@@YAXXZ at 4HA" ={{.*}} global i32 0
+
+template void g<int>(void);
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g at H@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g at H@@YAXXZ at 4HA" ={{.*}} global i32 0
+
+inline void h(void) {
+  ^{ static int i = e(); }();
+}
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2??h@@YAXXZ at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2??h@@YAXXZ at 4HA" ={{.*}} global i32 0
+
+struct s {
+  int i = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1 at 0s@@YAXPAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1 at 0s@@YAXPEAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+
+  int j = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1 at j@s@@YAXPAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1 at j@s@@YAXPEAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+
+  void m(int i = ^{ static int i = e(); return ++i; }(),
+         int j = ^{ static int i = e(); return ++i; }()) {}
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??m at s@@QAEXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??m at s@@QAEXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??m at s@@QEAAXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??m at s@@QEAAXHH at Z@4HA" ={{.*}} global i32 0
+
+  void n(int = ^{ static int i = e(); return ++i; }(),
+         int = ^{ static int i = e(); return ++i; }()) {}
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??n at s@@QAEXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??n at s@@QAEXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??n at s@@QEAAXHH at Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??n at s@@QEAAXHH at Z@4HA" ={{.*}} global i32 0
+
+};
+
+struct t {
+  struct u {
+    int i = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1 at 0u@t@@YAXPAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1 at 0u@t@@YAXPEAU__block_literal_1@@@Z at 4HA" ={{.*}} global i32 0
+
+  };
+};
+
+void j(void) {
+  h();
+  struct s s;
+  s.m();
+  s.n();
+  struct t::u t;
+}
+
+#if 0
+template <typename T>
+struct v {
+  static T i;
+};
+
+template <typename T>
+T v<T>::i = ^{ static T i = T(); return i; }();
+
+template class v<char>;
+template class v<int>;
+#endif
+




More information about the cfe-commits mailing list