HaohaiWen updated this revision to Diff 531219.
HaohaiWen added a comment.

Fix sections binding check


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D152785/new/

https://reviews.llvm.org/D152785

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Driver/ToolChains/CommonArgs.cpp
  clang/test/Driver/split-debug.c
  llvm/include/llvm/MC/MCWinCOFFObjectWriter.h
  llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
  llvm/lib/MC/MCAsmBackend.cpp
  llvm/lib/MC/WinCOFFObjectWriter.cpp
  llvm/test/DebugInfo/COFF/dwarf-headers.ll
  llvm/test/DebugInfo/COFF/fission-cu.ll
  llvm/test/DebugInfo/COFF/fission-sections.ll

Index: llvm/test/DebugInfo/COFF/fission-sections.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fission-sections.ll
@@ -0,0 +1,42 @@
+; RUN: llc -split-dwarf-file=baz.dwo -split-dwarf-output=%t.dwo -O0 %s -mtriple=x86_64-unknown-windows-msvc -filetype=obj -o %t
+; RUN: llvm-objdump -h %t | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-objdump -h %t.dwo | FileCheck --check-prefix=DWO %s
+
+; This test is derived from test/DebugInfo/X86/fission-cu.ll
+; But it checks that the output objects have the expected sections
+
+source_filename = "test/DebugInfo/X86/fission-cu.ll"
+
+@a = common global i32 0, align 4, !dbg !0
+
+!llvm.dbg.cu = !{!4}
+!llvm.module.flags = !{!7}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 1, type: !3, isLocal: false, isDefinition: true)
+!2 = !DIFile(filename: "baz.c", directory: "e:\\llvm-project\\tmp")
+!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "baz.dwo", emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5)
+!5 = !{}
+!6 = !{!0}
+!7 = !{i32 1, !"Debug Info Version", i32 3}
+
+; CHECK-LABEL: Sections:
+
+; OBJ:     Idx Name
+; OBJ-NEXT:  0 .text
+; OBJ-NEXT:  1 .data
+; OBJ-NEXT:  2 .bss
+; OBJ-NEXT:  3 .debug_abbrev
+; OBJ-NEXT:  4 .debug_info
+; OBJ-NEXT:  5 .debug_str
+; OBJ-NEXT:  6 .debug_addr
+; OBJ-NEXT:  7 .debug_pubnames
+; OBJ-NEXT:  8 .debug_pubtypes
+; OBJ-NEXT:  9 .debug_line
+
+; DWO:      Idx Name
+; DWO-NEXT:   0 .debug_str.dwo
+; DWO-NEXT:   1 .debug_str_offsets.dwo
+; DWO-NEXT:   2 .debug_info.dwo
+; DWO-NEXT:   3 .debug_abbrev.dwo
Index: llvm/test/DebugInfo/COFF/fission-cu.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fission-cu.ll
@@ -0,0 +1,121 @@
+; RUN: llc -split-dwarf-file=baz.dwo -O0 %s -mtriple=x86_64-unknown-windows-msvc -filetype=obj -o %t
+; RUN: llvm-dwarfdump -v -all %t | FileCheck %s
+; RUN: llvm-readobj --relocations %t | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-objdump -h %t | FileCheck --check-prefix=HDR %s
+
+; This test is derived from test/DebugInfo/X86/fission-cu.ll
+
+source_filename = "test/DebugInfo/X86/fission-cu.ll"
+
+@a = common global i32 0, align 4, !dbg !0
+
+!llvm.dbg.cu = !{!4}
+!llvm.module.flags = !{!7}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 1, type: !3, isLocal: false, isDefinition: true)
+!2 = !DIFile(filename: "baz.c", directory: "e:\\llvm-project\\tmp")
+!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "baz.dwo", emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5)
+!5 = !{}
+; Check that the skeleton compile unit contains the proper attributes:
+; This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list,
+; DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id,
+; DW_AT_ranges_base, DW_AT_addr_base.
+
+; CHECK: .debug_abbrev contents:
+; CHECK: Abbrev table for offset: 0x00000000
+; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_no
+; CHECK: DW_AT_stmt_list DW_FORM_sec_offset
+; CHECK: DW_AT_comp_dir  DW_FORM_strp
+; CHECK: DW_AT_GNU_dwo_name      DW_FORM_strp
+; CHECK: DW_AT_GNU_dwo_id        DW_FORM_data8
+
+; Check that we're using the right forms.
+; CHECK: .debug_abbrev.dwo contents:
+; CHECK: Abbrev table for offset: 0x00000000
+; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes
+; CHECK: DW_AT_producer  DW_FORM_GNU_str_index
+; CHECK: DW_AT_language  DW_FORM_data2
+; CHECK: DW_AT_name      DW_FORM_GNU_str_index
+; CHECK: DW_AT_GNU_dwo_name  DW_FORM_GNU_str_index
+; CHECK-NOT: DW_AT_low_pc
+; CHECK-NOT: DW_AT_stmt_list
+; CHECK-NOT: DW_AT_comp_dir
+; CHECK: DW_AT_GNU_dwo_id        DW_FORM_data8
+
+; CHECK: [2] DW_TAG_variable     DW_CHILDREN_no
+; CHECK: DW_AT_name      DW_FORM_GNU_str_index
+; CHECK: DW_AT_type      DW_FORM_ref4
+; CHECK: DW_AT_external  DW_FORM_flag_present
+; CHECK: DW_AT_decl_file DW_FORM_data1
+; CHECK: DW_AT_decl_line DW_FORM_data1
+; CHECK: DW_AT_location  DW_FORM_exprloc
+
+; CHECK: [3] DW_TAG_base_type    DW_CHILDREN_no
+; CHECK: DW_AT_name      DW_FORM_GNU_str_index
+; CHECK: DW_AT_encoding  DW_FORM_data1
+; CHECK: DW_AT_byte_size DW_FORM_data1
+
+; CHECK: .debug_info contents:
+; CHECK: DW_TAG_compile_unit
+; CHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset]   (0x00000000)
+; CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000000] = "e:\\llvm-project\\tmp")
+; CHECK-NEXT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x00000014] = "baz.dwo")
+; CHECK-NEXT: DW_AT_GNU_dwo_id [DW_FORM_data8]  (0x1f1f859683d49324)
+
+; Check that the rest of the compile units have information.
+; CHECK: .debug_info.dwo contents:
+; CHECK: DW_TAG_compile_unit
+; CHECK: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (00000002) string = "clang version 3.3 (trunk 169021) (llvm/trunk 169020)")
+; CHECK: DW_AT_language [DW_FORM_data2]        (DW_LANG_C99)
+; CHECK: DW_AT_name [DW_FORM_GNU_str_index]    (indexed (00000003) string = "baz.c")
+; CHECK: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (00000004) string = "baz.dwo")
+; CHECK-NOT: DW_AT_low_pc
+; CHECK-NOT: DW_AT_stmt_list
+; CHECK-NOT: DW_AT_comp_dir
+; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8]  (0x1f1f859683d49324)
+; CHECK: DW_TAG_variable
+; CHECK: DW_AT_name [DW_FORM_GNU_str_index]     (indexed (00000000) string = "a")
+; CHECK: DW_AT_type [DW_FORM_ref4]       (cu + 0x{{[0-9a-f]*}} => {[[TYPE:0x[0-9a-f]*]]}
+; CHECK: DW_AT_external [DW_FORM_flag_present]   (true)
+; CHECK: DW_AT_decl_file [DW_FORM_data1] (0x01)
+; CHECK: DW_AT_decl_line [DW_FORM_data1] (1)
+; CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_GNU_addr_index 0x0)
+; CHECK: [[TYPE]]: DW_TAG_base_type
+; CHECK: DW_AT_name [DW_FORM_GNU_str_index]     (indexed (00000001) string = "int")
+
+; CHECK: .debug_str contents:
+; CHECK: 0x00000000: "e:\\llvm-project\\tmp"
+; CHECK: 0x00000014: "baz.dwo"
+
+; CHECK: .debug_str.dwo contents:
+; CHECK: 0x00000000: "a"
+; CHECK: 0x00000002: "int"
+; CHECK: 0x00000006: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)"
+; CHECK: 0x0000003b: "baz.c"
+; CHECK: 0x00000041: "baz.dwo"
+
+; CHECK: .debug_str_offsets.dwo contents:
+; CHECK: 0x00000000: 00000000
+; CHECK: 0x00000004: 00000002
+; CHECK: 0x00000008: 00000006
+; CHECK: 0x0000000c: 0000003b
+; CHECK: 0x00000010: 00000041
+
+; Object file checks
+; For COFF we should have this set of relocations for the debug info section
+;
+; OBJ: .debug_info
+; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_abbrev (6)
+; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_line (26)
+; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (10)
+; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (10)
+; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_addr (20)
+; OBJ-NEXT: }
+
+; HDR-NOT: .debug_aranges
+; HDR-NOT: .rela.{{.*}}.dwo
+
+!6 = !{!0}
+!7 = !{i32 1, !"Debug Info Version", i32 3}
Index: llvm/test/DebugInfo/COFF/dwarf-headers.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/dwarf-headers.ll
@@ -0,0 +1,75 @@
+; RUN: llc -dwarf-version=4 \
+; RUN:     -filetype=obj -O0 -mtriple=x86_64-unknown-windows-msvc < %s \
+; RUN:     | llvm-dwarfdump -v - | FileCheck %s --check-prefix=SINGLE-4
+
+; RUN: llc -split-dwarf-file=foo.dwo -split-dwarf-output=%t.dwo \
+; RUN:     -dwarf-version=4 \
+; RUN:     -filetype=obj -O0 -mtriple=x86_64-unknown-windows-msvc < %s \
+; RUN:     | llvm-dwarfdump -v - | FileCheck %s --check-prefix=O-4
+; RUN: llvm-dwarfdump -v %t.dwo | FileCheck %s --check-prefix=DWO-4
+
+; This test is derived from test/CodeGen/X86/dwarf-headers.ll
+
+; Looking for DWARF headers to be generated correctly.
+; There are 8 variants with 5 formats: v4 CU, v4 TU, v5 normal/partial CU,
+; v5 skeleton/split CU, v5 normal/split TU.  Some v5 variants differ only
+; in the unit_type code, and the skeleton/split CU differs from normal/partial
+; by having one extra field (dwo_id).
+; (v2 thru v4 CUs are all the same, and TUs were invented in v4,
+; so we don't bother checking older versions.)
+
+; Test case built from:
+;struct S {
+;  int s1;
+;};
+;
+;S s;
+
+; Verify the v4 non-split headers.
+; Note that we check the exact offset of the DIEs because that tells us
+; the length of the header.
+;
+; SINGLE-4: .debug_info contents:
+; SINGLE-4: 0x00000000: Compile Unit: {{.*}} version = 0x0004, abbr_offset
+; SINGLE-4: 0x0000000b: DW_TAG_compile_unit
+
+; Verify the v4 split headers.
+;
+; O-4: .debug_info contents:
+; O-4: 0x00000000: Compile Unit: {{.*}} version = 0x0004, abbr_offset
+; O-4: 0x0000000b: DW_TAG_compile_unit
+;
+; DWO-4: .debug_info.dwo contents:
+; DWO-4: 0x00000000: Compile Unit: {{.*}} version = 0x0004, abbr_offset
+; DWO-4: 0x0000000b: DW_TAG_compile_unit
+
+
+; ModuleID = 't.cpp'
+source_filename = "t.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%struct.S = type { i32 }
+
+@"?s@@3US@@A" = dso_local global %struct.S zeroinitializer, align 4, !dbg !0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!9, !10, !11, !12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "s", linkageName: "?s@@3US@@A", scope: !2, file: !3, line: 5, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 17.0.0 (https://github.com/llvm/llvm-project.git f1106ef6c9d14d5b516ec352279aeee8f9d12818)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.cpp", directory: "e:\\llvm-project\\foo")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !6, identifier: ".?AUS@@")
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "s1", scope: !5, file: !3, line: 2, baseType: !8, size: 32)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !{i32 7, !"Dwarf Version", i32 4}
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!11 = !{i32 1, !"wchar_size", i32 2}
+!12 = !{i32 8, !"PIC Level", i32 2}
+!13 = !{i32 7, !"uwtable", i32 2}
+!14 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!15 = !{!"clang version 17.0.0 (https://github.com/llvm/llvm-project.git f1106ef6c9d14d5b516ec352279aeee8f9d12818)"}
Index: llvm/lib/MC/WinCOFFObjectWriter.cpp
===================================================================
--- llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -121,6 +121,10 @@
   SmallVector<COFFSymbol *, 1> OffsetSymbols;
 };
 
+bool isDwoSection(const MCSection &Sec) {
+  return Sec.getName().endswith(".dwo");
+}
+
 class WinCOFFObjectWriter;
 
 class WinCOFFWriter {
@@ -154,7 +158,14 @@
   MCSectionCOFF *AddrsigSection = nullptr;
   MCSectionCOFF *CGProfileSection = nullptr;
 
-  WinCOFFWriter(WinCOFFObjectWriter &OWriter, raw_pwrite_stream &OS);
+  enum DwoMode {
+    AllSections,
+    NonDwoOnly,
+    DwoOnly,
+  } Mode;
+
+  WinCOFFWriter(WinCOFFObjectWriter &OWriter, raw_pwrite_stream &OS,
+                DwoMode Mode);
 
   void reset();
   void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout);
@@ -200,13 +211,22 @@
   friend class WinCOFFWriter;
 
   std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter;
-  std::unique_ptr<WinCOFFWriter> ObjWriter;
+  std::unique_ptr<WinCOFFWriter> ObjWriter, DwoWriter;
 
 public:
   WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
                       raw_pwrite_stream &OS)
       : TargetObjectWriter(std::move(MOTW)),
-        ObjWriter(std::make_unique<WinCOFFWriter>(*this, OS)) {}
+        ObjWriter(std::make_unique<WinCOFFWriter>(*this, OS,
+                                                  WinCOFFWriter::AllSections)) {
+  }
+  WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
+                      raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS)
+      : TargetObjectWriter(std::move(MOTW)),
+        ObjWriter(std::make_unique<WinCOFFWriter>(*this, OS,
+                                                  WinCOFFWriter::NonDwoOnly)),
+        DwoWriter(std::make_unique<WinCOFFWriter>(*this, DwoOS,
+                                                  WinCOFFWriter::DwoOnly)) {}
 
   // MCObjectWriter interface implementation.
   void reset() override;
@@ -239,8 +259,8 @@
 // WinCOFFWriter class implementation
 
 WinCOFFWriter::WinCOFFWriter(WinCOFFObjectWriter &OWriter,
-                             raw_pwrite_stream &OS)
-    : OWriter(OWriter), W(OS, support::little) {
+                             raw_pwrite_stream &OS, DwoMode Mode)
+    : OWriter(OWriter), W(OS, support::little), Mode(Mode) {
   Header.Machine = OWriter.TargetObjectWriter->getMachine();
   // Some relocations on ARM64 (the 21 bit ADRP relocations) have a slightly
   // limited range for the immediate offset (+/- 1 MB); create extra offset
@@ -818,12 +838,18 @@
                                              const MCAsmLayout &Layout) {
   // "Define" each section & symbol. This creates section & symbol
   // entries in the staging area.
-  for (const auto &Section : Asm)
+  for (const auto &Section : Asm) {
+    if ((Mode == NonDwoOnly && isDwoSection(Section)) ||
+        (Mode == DwoOnly && !isDwoSection(Section)))
+      continue;
     defineSection(static_cast<const MCSectionCOFF &>(Section), Layout);
+  }
 
-  for (const MCSymbol &Symbol : Asm.symbols())
-    if (!Symbol.isTemporary())
-      DefineSymbol(Symbol, Asm, Layout);
+  if (Mode != DwoOnly) {
+    for (const MCSymbol &Symbol : Asm.symbols())
+      if (!Symbol.isTemporary())
+        DefineSymbol(Symbol, Asm, Layout);
+  }
 }
 
 void WinCOFFWriter::recordRelocation(MCAssembler &Asm,
@@ -998,7 +1024,8 @@
 
   setWeakDefaultNames();
   assignSectionNumbers();
-  createFileSymbols(Asm);
+  if (Mode != DwoOnly)
+    createFileSymbols(Asm);
 
   for (auto &Symbol : Symbols) {
     // Update section number & offset for symbols that have them.
@@ -1068,7 +1095,7 @@
   }
 
   // Create the contents of the .llvm_addrsig section.
-  if (OWriter.EmitAddrsigSection) {
+  if (Mode != DwoOnly && OWriter.EmitAddrsigSection) {
     auto Frag = new MCDataFragment(AddrsigSection);
     Frag->setLayoutOrder(0);
     raw_svector_ostream OS(Frag->getContents());
@@ -1089,7 +1116,7 @@
   }
 
   // Create the contents of the .llvm.call-graph-profile section.
-  if (CGProfileSection) {
+  if (Mode != DwoOnly && CGProfileSection) {
     auto *Frag = new MCDataFragment(CGProfileSection);
     Frag->setLayoutOrder(0);
     raw_svector_ostream OS(Frag->getContents());
@@ -1122,8 +1149,12 @@
   sections::iterator IE = Sections.end();
   MCAssembler::iterator J = Asm.begin();
   MCAssembler::iterator JE = Asm.end();
-  for (; I != IE && J != JE; ++I, ++J)
-    assert((**I).MCSection == &*J && "Wrong bound MCSection");
+  for (; I != IE && J != JE; ++I, ++J) {
+    while (J != JE && ((Mode == NonDwoOnly && isDwoSection(*J)) ||
+                       (Mode == DwoOnly && !isDwoSection(*J))))
+      J++;
+    assert(J != JE && (**I).MCSection == &*J && "Wrong bound MCSection");
+  }
 #endif
 
   // Write section contents.
@@ -1152,6 +1183,8 @@
 
 void WinCOFFObjectWriter::reset() {
   ObjWriter->reset();
+  if (DwoWriter)
+    DwoWriter->reset();
   MCObjectWriter::reset();
 }
 
@@ -1188,6 +1221,8 @@
   }
 
   ObjWriter->executePostLayoutBinding(Asm, Layout);
+  if (DwoWriter)
+    DwoWriter->executePostLayoutBinding(Asm, Layout);
 }
 
 void WinCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
@@ -1195,13 +1230,19 @@
                                            const MCFragment *Fragment,
                                            const MCFixup &Fixup, MCValue Target,
                                            uint64_t &FixedValue) {
+  assert(!isDwoSection(*Fragment->getParent()) &&
+         "No relocation in Dwo sections");
   ObjWriter->recordRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue);
 }
 
 uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
                                           const MCAsmLayout &Layout) {
-  return ObjWriter->writeObject(Asm, Layout);
+  uint64_t TotalSize = ObjWriter->writeObject(Asm, Layout);
+  if (DwoWriter)
+    TotalSize += DwoWriter->writeObject(Asm, Layout);
+  return TotalSize;
 }
+
 MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_)
     : Machine(Machine_) {}
 
@@ -1215,3 +1256,9 @@
     std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) {
   return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS);
 }
+
+std::unique_ptr<MCObjectWriter> llvm::createWinCOFFDwoObjectWriter(
+    std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS,
+    raw_pwrite_stream &DwoOS) {
+  return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS, DwoOS);
+}
Index: llvm/lib/MC/MCAsmBackend.cpp
===================================================================
--- llvm/lib/MC/MCAsmBackend.cpp
+++ llvm/lib/MC/MCAsmBackend.cpp
@@ -68,8 +68,11 @@
   case Triple::Wasm:
     return createWasmDwoObjectWriter(
         cast<MCWasmObjectTargetWriter>(std::move(TW)), OS, DwoOS);
+  case Triple::COFF:
+    return createWinCOFFDwoObjectWriter(
+        cast<MCWinCOFFObjectTargetWriter>(std::move(TW)), OS, DwoOS);
   default:
-    report_fatal_error("dwo only supported with ELF and Wasm");
+    report_fatal_error("dwo only supported with ELF Wasm and COFF");
   }
 }
 
Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
===================================================================
--- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -39,6 +39,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/COFF.h"
 #include "llvm/Object/Decompressor.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Object/ObjectFile.h"
@@ -1890,9 +1891,14 @@
         S.Data = Data;
       }
 
-      if (RelocatedSection != Obj.section_end() && Name.contains(".dwo"))
+      if (RelocatedSection != Obj.section_end() && Name.contains(".dwo")) {
+        // Each section in COFF can directly contain relocations.
+        if (isa<COFFObjectFile>(&Obj) && Section.relocations().empty())
+          continue;
+
         HandleWarning(
             createError("Unexpected relocations for dwo section " + Name));
+      }
 
       if (RelocatedSection == Obj.section_end() ||
           (RelocAction == DWARFContext::ProcessDebugRelocations::Ignore))
Index: llvm/include/llvm/MC/MCWinCOFFObjectWriter.h
===================================================================
--- llvm/include/llvm/MC/MCWinCOFFObjectWriter.h
+++ llvm/include/llvm/MC/MCWinCOFFObjectWriter.h
@@ -51,6 +51,10 @@
 std::unique_ptr<MCObjectWriter>
 createWinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
                           raw_pwrite_stream &OS);
+
+std::unique_ptr<MCObjectWriter>
+createWinCOFFDwoObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
+                             raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS);
 } // end namespace llvm
 
 #endif // LLVM_MC_MCWINCOFFOBJECTWRITER_H
Index: clang/test/Driver/split-debug.c
===================================================================
--- clang/test/Driver/split-debug.c
+++ clang/test/Driver/split-debug.c
@@ -16,6 +16,7 @@
 
 // RUN: %clang -### -c -target wasm32 -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=SPLIT
 // RUN: %clang -### -c -target amdgcn-amd-amdhsa -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=SPLIT
+// RUN: %clang_cl -### -c -target x86_64-unknown-windows-msvc -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=SPLIT
 
 /// -gsplit-dwarf is a no-op on a non-ELF platform.
 // RUN: %clang -### -c -target x86_64-apple-darwin  -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=DARWIN
@@ -51,12 +52,14 @@
 // SINGLE-NOT: "-split-dwarf-output"
 
 // RUN: %clang -### -c -target x86_64 -gsplit-dwarf=single -g -o %tfoo.o %s 2>&1 | FileCheck %s --check-prefix=SINGLE_WITH_FILENAME
+// RUN: %clang_cl -### -c -target x86_64-unknown-windows-msvc -gsplit-dwarf=single -g -o %tfoo.o %s 2>&1 | FileCheck %s --check-prefix=SINGLE_WITH_FILENAME
 
 // SINGLE_WITH_FILENAME: "-split-dwarf-file" "{{.*}}foo.o"
 // SINGLE_WITH_FILENAME-NOT: "-split-dwarf-output"
 
 /// If linking is the final phase, the .dwo filename is derived from -o (if specified) or "a".
 // RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s -o obj/out 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK
+// RUN: %clang_cl -### --target=x86_64-unknown-windows-msvc -gsplit-dwarf -g %s -o obj/out 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK
 // RUN: %clang -### --target=x86_64-unknown-linux-gnu -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=SPLIT_LINK_A
 
 // SPLIT_LINK:      "-dumpdir" "obj/out-"
Index: clang/lib/Driver/ToolChains/CommonArgs.cpp
===================================================================
--- clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1284,7 +1284,7 @@
   if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) {
     T = A->getValue();
   } else {
-    Arg *FinalOutput = Args.getLastArg(options::OPT_o);
+    Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o);
     if (FinalOutput && Args.hasArg(options::OPT_c)) {
       T = FinalOutput->getValue();
       llvm::sys::path::remove_filename(T);
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5639,7 +5639,8 @@
   // can propagate it to the backend.
   bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) &&
                     (TC.getTriple().isOSBinFormatELF() ||
-                     TC.getTriple().isOSBinFormatWasm()) &&
+                     TC.getTriple().isOSBinFormatWasm() ||
+                     TC.getTriple().isOSBinFormatCOFF()) &&
                     (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
                      isa<BackendJobAction>(JA));
   if (SplitDWARF) {
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -3895,12 +3895,13 @@
     // `-dumpdir x-` to cc1. If -o is unspecified, use
     // stem(getDefaultImageName()) (usually stem("a.out") = "a").
     if (!Args.hasArg(options::OPT_dumpdir)) {
+      Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o);
       Arg *Arg = Args.MakeSeparateArg(
           nullptr, getOpts().getOption(options::OPT_dumpdir),
-          Args.MakeArgString(Args.getLastArgValue(
-                                 options::OPT_o,
-                                 llvm::sys::path::stem(getDefaultImageName())) +
-                             "-"));
+          Args.MakeArgString(
+              (FinalOutput ? FinalOutput->getValue()
+                           : llvm::sys::path::stem(getDefaultImageName())) +
+              "-"));
       Arg->claim();
       Args.append(Arg);
     }
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1164,7 +1164,7 @@
   Flags<[NoXarchOption, RenderAsInput]>,
   HelpText<"Directory to output dSYM's (if any) to">, MetaVarName<"<dir>">;
 // GCC style -dumpdir. We intentionally don't implement the less useful -dumpbase{,-ext}.
-def dumpdir : Separate<["-"], "dumpdir">, Flags<[CC1Option]>,
+def dumpdir : Separate<["-"], "dumpdir">, Flags<[CC1Option, CoreOption]>,
   MetaVarName<"<dumppfx>">,
   HelpText<"Use <dumpfpx> as a prefix to form auxiliary and dump file names">;
 def dumpmachine : Flag<["-"], "dumpmachine">;
@@ -3386,11 +3386,13 @@
   CodeGenOpts<"DebugColumnInfo">, DefaultTrue,
   NegFlag<SetFalse, [CC1Option]>, PosFlag<SetTrue>, BothFlags<[CoreOption]>>,
   Group<g_flags_Group>;
-def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>;
+def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>,
+  Flags<[CoreOption]>;
 def gsplit_dwarf_EQ : Joined<["-"], "gsplit-dwarf=">, Group<g_flags_Group>,
-  HelpText<"Set DWARF fission mode">,
+  Flags<[CoreOption]>, HelpText<"Set DWARF fission mode">,
   Values<"split,single">;
-def gno_split_dwarf : Flag<["-"], "gno-split-dwarf">, Group<g_flags_Group>;
+def gno_split_dwarf : Flag<["-"], "gno-split-dwarf">, Group<g_flags_Group>,
+  Flags<[CoreOption]>;
 def gsimple_template_names : Flag<["-"], "gsimple-template-names">, Group<g_flags_Group>;
 def gsimple_template_names_EQ
     : Joined<["-"], "gsimple-template-names=">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to