sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall.

Type in the LLVM IR may have names but only for the purpose of human
readability (see discussions in https://reviews.llvm.org/D40567,
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20171127/210816.html
and http://lists.llvm.org/pipermail/llvm-dev/2017-December/119585.html).
In the case when the resulting IR is not proposed for reading, for
instance, when compilation produces machine code, the type names are waste
of memory. In some cases, when types are nested in other types, the memory
expenses may be really large.

This change implements new clang option, '--ir-type-names=', which controls
if IR types should be given human readable names. The option may have
values 'use' or 'none', which turn names on or off correspondently. If no such
option was specified, compiler assign names when output may be read by a
human, namely when IR is saved beyond compilation or in debug builds.


Repository:
  rC Clang

https://reviews.llvm.org/D43805

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/pr29160.cpp
  test/CodeGenCXX/type-names.cpp

Index: test/CodeGenCXX/type-names.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/type-names.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm --ir-type-names=use -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm --ir-type-names=none -o - %s | FileCheck %s --check-prefix=UNNAMED
+
+struct C1 {
+  int a;
+  int *b;
+};
+
+C1 var_C1_a;
+C1 var_C1_b[10];
+C1 *var_C1_c;
+int (*var_C1_d)(const C1 &);
+
+struct C1A {
+  int a;
+  int *b;
+};
+
+C1A var_C1A_a;
+
+template<typename T> struct C2 {
+  C1 a;
+  T b;
+  struct Inner {
+  };
+};
+
+C2<short> var_C2_a;
+C2<long long> var_C2_b;
+C2<int>::Inner var_C2_c;
+
+struct C3 {
+  double a;
+  struct C4 {
+    int a;
+    float b;
+  };
+};
+
+C3::C4 var_c4;
+
+namespace {
+struct C5 {
+  int *a;
+};
+}
+
+C5 var_C5_a;
+void *var_C5_b = &var_C5_a;
+
+// CHECK: %struct.C1 = type { i32, i32* }
+// CHECK: %struct.C1A = type { i32, i32* }
+// CHECK: %struct.C2 = type { %struct.C1, i16 }
+// CHECK: %struct.C2.0 = type { %struct.C1, i64 }
+// CHECK: %"struct.C2<int>::Inner" = type { i8 }
+// CHECK: %"struct.C3::C4" = type { i32, float }
+// CHECK: %"struct.(anonymous namespace)::C5" = type { i32* }
+
+// UNNAMED: %0 = type { i32, i32* }
+// UNNAMED: %1 = type { i32, i32* }
+// UNNAMED: %2 = type { %0, i16 }
+// UNNAMED: %3 = type { %0, i64 }
+// UNNAMED: %4 = type { i8 }
+// UNNAMED: %5 = type { i32, float }
+// UNNAMED: %6 = type { i32* }
Index: test/CodeGenCXX/pr29160.cpp
===================================================================
--- test/CodeGenCXX/pr29160.cpp
+++ test/CodeGenCXX/pr29160.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm
+// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu -DNAMELESS --ir-type-names=none %s -o /dev/null -S -emit-llvm
 //
 // This test's failure mode is running ~forever. (For some value of "forever"
 // that's greater than 25 minutes on my machine)
@@ -8,6 +9,7 @@
   template <typename... T>
   static void ignore() {}
   Foo() { ignore<Ts...>(); }
+  struct ABC {};
 };
 
 struct Base {
@@ -39,3 +41,9 @@
 STAMP(Q, P);
 
 int main() { Q q; }
+
+#ifdef NAMELESS
+// Without '--ir-type-names=none' compiler tries to create name for Q::ABC,
+// which is really huge, so compilation never ends.
+Q::ABC var;
+#endif
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -804,6 +804,19 @@
     }
   }
 
+  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("use", CodeGenOptions::IRNameKind::Use)
+        .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
@@ -3279,6 +3279,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()) {
Index: lib/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -884,6 +884,22 @@
                                     std::unique_ptr<PPCallbacks>(CoverageInfo));
   }
 
+  // Specify names for IR types in the cases:
+  // - if it requested explicitly, by option '--ir-type-names=use',
+  // - if compilation produces IR representation, or
+  // - in Debug build.
+  if (CI.getCodeGenOpts().getIRTypeNames()
+                                   == CodeGenOptions::IRNameKind::Unspecified) {
+#ifdef NDEBUG
+    if ((BA == Backend_EmitBC ||
+         BA == Backend_EmitLL ||
+         (BA == Backend_EmitObj &&
+          CI.getCodeGenOpts().getEmbedBitcode() != CodeGenOptions::Embed_Off) ||
+         !LinkModules.empty()))
+#endif
+      CI.getCodeGenOpts().setIRTypeNames(CodeGenOptions::IRNameKind::Use);
+  }
+
   std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
       BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
       CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
Index: include/clang/Frontend/CodeGenOptions.h
===================================================================
--- include/clang/Frontend/CodeGenOptions.h
+++ include/clang/Frontend/CodeGenOptions.h
@@ -107,6 +107,14 @@
     Embed_Marker    // Embed a marker as a placeholder for bitcode.
   };
 
+  /// Should LLVM types be given human-readable names?
+  ///
+  enum class IRNameKind {
+    Unspecified,    ///< No special option was passed.
+    None,           ///< No type names.
+    Use             ///< Types must be named.
+  };
+
   /// 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
@@ -72,6 +72,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)
+
+/// Should LLVM IR types be given human-readable names?
+/// \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
@@ -1729,6 +1729,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<"Whether to use IR type names (option: none, use)">,
+  Values<"none,use">;
 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