sepavloff updated this revision to Diff 125761.
sepavloff added a comment.

Updated patch

- old type names are generated always if --ir-type-names is not specified,
- added new value of --ir-type-names, none, to suppress type names,
- value of --ir-type-names is stored in module properties.


Repository:
  rC Clang

https://reviews.llvm.org/D40567

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/template-types.cpp

Index: test/CodeGenCXX/template-types.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/template-types.cpp
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -S -emit-llvm --ir-type-names=none -o - | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang_cc1 %s -S -emit-llvm --ir-type-names=terse -o - | FileCheck %s --check-prefix=CHECK-TERSE
+// RUN: %clang_cc1 %s -S -emit-llvm --ir-type-names=full -o - | FileCheck %s --check-prefix=CHECK-FULL
+
+struct Empty {};
+template<typename T> struct ABC {
+  T v;
+};
+struct Opaque;
+template<typename T> class OpaqueClass;
+
+ABC<int> var_1;
+ABC<ABC<short> > var_2;
+ABC<Empty> var_3;
+ABC<Opaque> *var_4;
+OpaqueClass<int> *var_5;
+OpaqueClass<Empty> *var_6;
+OpaqueClass<Opaque> *var_7;
+OpaqueClass<OpaqueClass<int> > *var_8;
+
+
+//------ without option '--ir-type-names'
+
+// CHECK: %struct.ABC = type { i32 }
+// CHECK: %struct.ABC.0 = type { %struct.ABC.1 }
+// CHECK: %struct.ABC.1 = type { i16 }
+// CHECK: %struct.ABC.2 = type { %struct.Empty }
+// CHECK: %struct.Empty = type { i8 }
+// CHECK: %class.OpaqueClass = type opaque
+// CHECK: %class.OpaqueClass.4 = type opaque
+// CHECK: %class.OpaqueClass.5 = type opaque
+// CHECK: %class.OpaqueClass.6 = type opaque
+
+// CHECK: @var_1 = global %struct.ABC zeroinitializer
+// CHECK: @var_2 = global %struct.ABC.0 zeroinitializer
+// CHECK: @var_3 = global %struct.ABC.2 zeroinitializer
+// CHECK: @var_4 = global %struct.ABC.3* null
+// CHECK: @var_5 = global %class.OpaqueClass* null
+// CHECK: @var_6 = global %class.OpaqueClass.4* null
+// CHECK: @var_7 = global %class.OpaqueClass.5* null
+// CHECK: @var_8 = global %class.OpaqueClass.6* null
+
+// CHECK-NOT: !{{[0-9]+}} = !{{{.*}} !"type_names"
+
+
+//------ with option '--ir-type-names=none'
+
+// CHECK-NONE: %0 = type { i32 }
+// CHECK-NONE: %1 = type { %2 }
+// CHECK-NONE: %2 = type { i16 }
+// CHECK-NONE: %3 = type { %4 }
+// CHECK-NONE: %4 = type { i8 }
+// CHECK-NONE: %5 = type opaque
+// CHECK-NONE: %6 = type opaque
+// CHECK-NONE: %7 = type opaque
+// CHECK-NONE: %8 = type opaque
+// CHECK-NONE: %9 = type opaque
+
+// CHECK-NONE: @var_1 = global %0 zeroinitializer
+// CHECK-NONE: @var_2 = global %1 zeroinitializer
+// CHECK-NONE: @var_3 = global %3 zeroinitializer
+// CHECK-NONE: @var_4 = global %5* null
+// CHECK-NONE: @var_5 = global %6* null
+// CHECK-NONE: @var_6 = global %7* null
+// CHECK-NONE: @var_7 = global %8* null
+// CHECK-NONE: @var_8 = global %9* null
+
+// CHECK-NONE: !{{[0-9]+}} = !{{{.*}} !"type_names", i32 1}
+
+
+//------ with option '--ir-type-names=terse'
+
+// CHECK-TERSE: %struct.ABC = type { i32 }
+// CHECK-TERSE: %struct.ABC.0 = type { %struct.ABC.1 }
+// CHECK-TERSE: %struct.ABC.1 = type { i16 }
+// CHECK-TERSE: %struct.ABC.2 = type { %struct.Empty }
+// CHECK-TERSE: %struct.Empty = type { i8 }
+// CHECK-TERSE: %class.OpaqueClass = type opaque
+// CHECK-TERSE: %class.OpaqueClass.4 = type opaque
+// CHECK-TERSE: %class.OpaqueClass.5 = type opaque
+// CHECK-TERSE: %class.OpaqueClass.6 = type opaque
+
+// CHECK-TERSE: @var_1 = global %struct.ABC zeroinitializer
+// CHECK-TERSE: @var_2 = global %struct.ABC.0 zeroinitializer
+// CHECK-TERSE: @var_3 = global %struct.ABC.2 zeroinitializer
+// CHECK-TERSE: @var_4 = global %struct.ABC.3* null
+// CHECK-TERSE: @var_5 = global %class.OpaqueClass* null
+// CHECK-TERSE: @var_6 = global %class.OpaqueClass.4* null
+// CHECK-TERSE: @var_7 = global %class.OpaqueClass.5* null
+// CHECK-TERSE: @var_8 = global %class.OpaqueClass.6* null
+
+// CHECK-TERSE: !{{[0-9]+}} = !{{{.*}} !"type_names", i32 2}
+
+
+//------ with option '--ir-type-names=full'
+
+// CHECK-FULL: %"struct.ABC<int>" = type { i32 }
+// CHECK-FULL: %"struct.ABC<ABC<short> >" = type { %"struct.ABC<short>" }
+// CHECK-FULL: %"struct.ABC<short>" = type { i16 }
+// CHECK-FULL: %"struct.ABC<Empty>" = type { %struct.Empty }
+// CHECK-FULL: %struct.Empty = type { i8 }
+// CHECK-FULL: %"struct.ABC<Opaque>" = type opaque
+// CHECK-FULL: %"class.OpaqueClass<int>" = type opaque
+// CHECK-FULL: %"class.OpaqueClass<Empty>" = type opaque
+// CHECK-FULL: %"class.OpaqueClass<Opaque>" = type opaque
+// CHECK-FULL: %"class.OpaqueClass<OpaqueClass<int> >" = type opaque
+
+// CHECK-FULL: @var_1 = global %"struct.ABC<int>" zeroinitializer
+// CHECK-FULL: @var_2 = global %"struct.ABC<ABC<short> >" zeroinitializer
+// CHECK-FULL: @var_3 = global %"struct.ABC<Empty>" zeroinitializer
+// CHECK-FULL: @var_4 = global %"struct.ABC<Opaque>"* null
+// CHECK-FULL: @var_5 = global %"class.OpaqueClass<int>"* null
+// CHECK-FULL: @var_6 = global %"class.OpaqueClass<Empty>"* null
+// CHECK-FULL: @var_7 = global %"class.OpaqueClass<Opaque>"* null
+// CHECK-FULL: @var_8 = global %"class.OpaqueClass<OpaqueClass<int> >"* null
+
+// CHECK-FULL:  !{{[0-9]+}} = !{{{.*}} !"type_names", i32 3}
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -778,6 +778,20 @@
     }
   }
 
+  if (Arg *A = Args.getLastArg(OPT_ir_type_names_EQ)) {
+    StringRef Name = A->getValue();
+    auto Info = llvm::StringSwitch<CodeGenOptions::IRNameKind>(Name)
+        .Case("none", CodeGenOptions::IRNameKind::None)
+        .Case("terse", CodeGenOptions::IRNameKind::Terse)
+        .Case("full", CodeGenOptions::IRNameKind::Full)
+        .Default(CodeGenOptions::IRNameKind::Unspecified);
+    if (Info == CodeGenOptions::IRNameKind::Unspecified) {
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+      Success = false;
+    } else
+      Opts.setIRTypeNames(Info);
+  }
+
   Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
   Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
   Opts.InstrumentFunctionsAfterInlining =
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3195,6 +3195,8 @@
   if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
     CmdArgs.push_back("-fembed-bitcode=marker");
 
+  Args.AddLastArg(CmdArgs, options::OPT_ir_type_names_EQ);
+
   // We normally speed up the clang process a bit by skipping destructors at
   // exit, but when we're generating diagnostics we can rely on some of the
   // cleanup.
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -51,10 +51,13 @@
 void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
                                      llvm::StructType *Ty,
                                      StringRef suffix) {
+  if (getCodeGenOpts().getIRTypeNames() == CodeGenOptions::IRNameKind::None)
+    return;
+
   SmallString<256> TypeName;
   llvm::raw_svector_ostream OS(TypeName);
   OS << RD->getKindName() << '.';
-  
+
   // Name the codegen type after the typedef name
   // if there is no tag type name available
   if (RD->getIdentifier()) {
@@ -64,6 +67,12 @@
       RD->printQualifiedName(OS);
     else
       RD->printName(OS);
+    if (getCodeGenOpts().getIRTypeNames() == CodeGenOptions::IRNameKind::Full)
+      if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+        const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+        printTemplateArgumentList(OS, TemplateArgs.asArray(),
+                                  RD->getASTContext().getPrintingPolicy());
+      }
   } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
     // FIXME: We should not have to check for a null decl context here.
     // Right now we do it because the implicit Obj-C decls don't have one.
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -492,6 +492,11 @@
     getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
   }
 
+  // Opaque type resolution made by IR linker relies on IR type names.
+  if (CodeGenOpts.getIRTypeNames() != CodeGenOptions::IRNameKind::Unspecified)
+    getModule().addModuleFlag(llvm::Module::Error, "type_names",
+                           static_cast<uint32_t>(CodeGenOpts.getIRTypeNames()));
+
   if (CodeGenOpts.SanitizeCfiCrossDso) {
     // Indicate that we want cross-DSO control flow integrity checks.
     getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1);
Index: include/clang/Frontend/CodeGenOptions.h
===================================================================
--- include/clang/Frontend/CodeGenOptions.h
+++ include/clang/Frontend/CodeGenOptions.h
@@ -106,6 +106,19 @@
     Embed_Marker    // Embed a marker as a placeholder for bitcode.
   };
 
+  /// Describes what kind of names should be specified for LLVM types.
+  ///
+  /// For example, LLVM structure types corresponding to template class
+  /// specializations may be assigned names with template arguments (as
+  /// "struct.Foo<int>") or name with only version suffix (as "Foo.123").
+  ///
+  enum class IRNameKind {
+    Unspecified,    ///< No special option was passed.
+    None,           ///< No type names.
+    Terse,          ///< Only minimal names.
+    Full,           ///< Full names (with template parameters).
+  };
+
   /// The code model to use (-mcmodel).
   std::string CodeModel;
 
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -71,6 +71,11 @@
 CODEGENOPT(EmulatedTLS       , 1, 0) ///< Set when -femulated-tls is enabled.
 /// \brief Embed Bitcode mode (off/all/bitcode/marker).
 ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
+
+/// What kind of names should be specified for LLVM IR types.
+/// \see CodeGenOptions::IRNameKind.
+ENUM_CODEGENOPT(IRTypeNames, IRNameKind, 4, IRNameKind::Unspecified)
+
 CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
                                         ///< are required.
 CODEGENOPT(FunctionSections  , 1, 0) ///< Set when -ffunction-sections is enabled.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1671,6 +1671,10 @@
     MetaVarName<"<file>">, HelpText<"Include file before parsing">, Flags<[CC1Option]>;
 def include_pch : Separate<["-"], "include-pch">, Group<clang_i_Group>, Flags<[CC1Option]>,
   HelpText<"Include precompiled header file">, MetaVarName<"<file>">;
+def ir_type_names_EQ : Joined<["--"], "ir-type-names=">,
+  Flags<[CC1Option, HelpHidden]>,
+  HelpText<"Encoding of IR type names (option: none, terse, full)">,
+  Values<"none,terse,full">;
 def relocatable_pch : Flag<["-", "--"], "relocatable-pch">, Flags<[CC1Option]>,
   HelpText<"Whether to build a relocatable precompiled header">;
 def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>, Flags<[CC1Option]>,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to