[llvm] [dsymutil][llvm-dwarfutil] Add command line option --deterministic. (PR #83020)

via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 26 07:47:53 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: Alexey Lapshin (avl-llvm)

<details>
<summary>Changes</summary>

This patch adds command line option --deterministic <level name> to the dsymutil and llvm-dwarfutil. This option allows generating non-deterministic output in exchange for more parallelism.

--deterministic <level name>
    Specify the desired level of output determinism.
    Valid names are 'full', 'trusted' and 'none'. Defaults to 'full'

   'full'    Generated output should always be deterministic
             (despite of any assumptions).
   'trusted' Generated output should be deterministic
             assuming input DWARF is consistent.
   'none'    Generated output may not be deterministic.
   
   Note: 'full' mode is equal to 'trusted' currently. Patch implementing 'full' functionality would be submitted separately.

---

Patch is 22.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83020.diff


18 Files Affected:

- (modified) llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h (+2-1) 
- (modified) llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h (+10-1) 
- (modified) llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.h (+3-2) 
- (modified) llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h (+1-1) 
- (modified) llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h (+2-4) 
- (modified) llvm/lib/DWARFLinker/Parallel/DWARFLinkerTypeUnit.cpp (+8-4) 
- (modified) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test (+15-5) 
- (modified) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test (+16-4) 
- (added) llvm/test/tools/llvm-dwarfutil/ELF/X86/deterministic.test (+146) 
- (modified) llvm/test/tools/llvm-dwarfutil/help.test (+1) 
- (modified) llvm/tools/dsymutil/DwarfLinkerForBinary.cpp (+1) 
- (modified) llvm/tools/dsymutil/LinkUtils.h (+4) 
- (modified) llvm/tools/dsymutil/Options.td (+6) 
- (modified) llvm/tools/dsymutil/dsymutil.cpp (+26) 
- (modified) llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (+1) 
- (modified) llvm/tools/llvm-dwarfutil/Options.h (+4) 
- (modified) llvm/tools/llvm-dwarfutil/Options.td (+5) 
- (modified) llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp (+21) 


``````````diff
diff --git a/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h
index b1d3f03394f5ec..753f8bdb411e21 100644
--- a/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h
@@ -264,7 +264,8 @@ class DWARFLinker : public DWARFLinkerBase {
   }
 
   /// Allow generating valid, but non-deterministic output.
-  void setAllowNonDeterministicOutput(bool) override { /* Nothing to do. */
+  void setDeterministicLevel(DeterministicLevel Level) override {
+    /* Nothing to do. Output of classic dwarflinker is always deterministic. */
   }
 
   /// Set whether to keep the enclosing function for a static variable.
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
index 5c811b668f0a31..7a9155fe833485 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h
@@ -70,6 +70,15 @@ getSectionName(DebugSectionKind SectionKind) {
 /// Recognise the table name and match it with the DebugSectionKind.
 std::optional<DebugSectionKind> parseDebugTableName(StringRef Name);
 
+/// Specify level of determinism for generated output.
+enum class DeterministicLevel : uint8_t {
+  Full,    // Generated output should always be deterministic(despite any
+           // assumptions).
+  Trusted, // Generated output should be deterministic assuming input DWARF is
+           // consistent.
+  None     // Generated output may not be deterministic.
+};
+
 /// The base interface for DWARFLinker implementations.
 class DWARFLinkerBase {
 public:
@@ -121,7 +130,7 @@ class DWARFLinkerBase {
   virtual void setUpdateIndexTablesOnly(bool Update) = 0;
   /// Allows generating non-deterministic output in exchange for more
   /// parallelism.
-  virtual void setAllowNonDeterministicOutput(bool) = 0;
+  virtual void setDeterministicLevel(DeterministicLevel) = 0;
   /// Set whether to keep the enclosing function for a static variable.
   virtual void setKeepFunctionForStatic(bool KeepFunctionForStatic) = 0;
   /// Use specified number of threads for parallel files linking.
diff --git a/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.h b/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.h
index 6a6bd08570d7da..835573f8173633 100644
--- a/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.h
+++ b/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.h
@@ -105,8 +105,9 @@ class DIEAttributeCloner {
     Use_DW_FORM_strp =
         (InUnit.getVersion() < 5) ||
         (OutUnit.isTypeUnit() &&
-         ((InUnit.getGlobalData().getOptions().Threads != 1) &&
-          !InUnit.getGlobalData().getOptions().AllowNonDeterministicOutput));
+         InUnit.getGlobalData().getOptions().Threads != 1 &&
+         InUnit.getGlobalData().getOptions().DesiredDeterministicLevel !=
+             DeterministicLevel::None);
   }
 
   /// Clone string attribute.
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
index 38c261a8106fcd..dad6806bb46a2a 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerGlobalData.h
@@ -50,7 +50,7 @@ struct DWARFLinkerOptions {
   bool KeepFunctionForStatic = false;
 
   /// Allow to generate valid, but non deterministic output.
-  bool AllowNonDeterministicOutput = false;
+  DeterministicLevel DesiredDeterministicLevel = DeterministicLevel::Full;
 
   /// Number of threads.
   unsigned Threads = 1;
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
index 7c17c5b79c7c18..c1ddab962aa925 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h
@@ -80,10 +80,8 @@ class DWARFLinkerImpl : public DWARFLinker {
   }
 
   /// Allow generating valid, but non-deterministic output.
-  void
-  setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override {
-    GlobalData.Options.AllowNonDeterministicOutput =
-        AllowNonDeterministicOutput;
+  void setDeterministicLevel(DeterministicLevel Level) override {
+    GlobalData.Options.DesiredDeterministicLevel = Level;
   }
 
   /// Set to keep the enclosing function for a static variable.
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerTypeUnit.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerTypeUnit.cpp
index 3030aa2c39b234..3ebe995cf47b57 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerTypeUnit.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerTypeUnit.cpp
@@ -137,7 +137,8 @@ void TypeUnit::prepareDataForTreeCreation() {
 
   llvm::parallel::TaskGroup TG;
 
-  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+  if (GlobalData.getOptions().DesiredDeterministicLevel !=
+      DeterministicLevel::None) {
     TG.spawn([&]() {
       // Sort types to have a deterministic output.
       Types.sortTypes();
@@ -145,7 +146,8 @@ void TypeUnit::prepareDataForTreeCreation() {
   }
 
   TG.spawn([&]() {
-    if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+    if (GlobalData.getOptions().DesiredDeterministicLevel !=
+        DeterministicLevel::None) {
       // Sort decl type patches to have a deterministic output.
       std::function<bool(const DebugTypeDeclFilePatch &LHS,
                          const DebugTypeDeclFilePatch &RHS)>
@@ -190,7 +192,8 @@ void TypeUnit::prepareDataForTreeCreation() {
         });
   });
 
-  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+  if (GlobalData.getOptions().DesiredDeterministicLevel !=
+      DeterministicLevel::None) {
     // Sort patches to have a deterministic output.
     TG.spawn([&]() {
       forEach([&](SectionDescriptor &OutSection) {
@@ -212,7 +215,8 @@ void TypeUnit::prepareDataForTreeCreation() {
     });
   }
 
-  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+  if (GlobalData.getOptions().DesiredDeterministicLevel !=
+      DeterministicLevel::None) {
     // Sort patches to have a deterministic output.
     TG.spawn([&]() {
       forEach([&](SectionDescriptor &OutSection) {
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
index 4b82e40412f5a6..95a07d58d134d9 100644
--- a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
@@ -1,11 +1,21 @@
-# RUN: dsymutil --linker=parallel -f -o %t1.o -oso-prepend-path=%p/ -y %s
+# RUN: dsymutil --deterministic full --linker=parallel -f -o %t1.o -oso-prepend-path=%p/ -y %s
 # RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
-# RUN: dsymutil --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1
-# RUN: dsymutil --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2
+# RUN: dsymutil --deterministic full --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1
+# RUN: dsymutil --deterministic full --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2
 # RUN: diff %t1 %t2
-# RUN: dsymutil --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3
+# RUN: dsymutil --deterministic full --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3
 # RUN: diff %t1 %t3
-# RUN: dsymutil --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4
+# RUN: dsymutil --deterministic full --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4
+# RUN: diff %t1 %t4
+
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o %t1.o -oso-prepend-path=%p/ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2
+# RUN: diff %t1 %t2
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3
+# RUN: diff %t1 %t3
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4
 # RUN: diff %t1 %t4
 
 # This test checks that generated output does not differ between runs.
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
index daa8c0ca80931b..5b47ae5e13bfa9 100644
--- a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
@@ -1,9 +1,21 @@
-# RUN: dsymutil --linker=parallel -f -o %t1.o -oso-prepend-path=%p/../ -y %s
+# RUN: dsymutil --deterministic full --linker=parallel -f -o %t1.o -oso-prepend-path=%p/../ -y %s
 # RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
-# RUN: dsymutil --linker=parallel -f -o %t2.o -oso-prepend-path=%p/../ -y %s
-# RUN: dsymutil --linker=parallel -f -o %t3.o -oso-prepend-path=%p/../ -y %s \
+# RUN: dsymutil --deterministic full --linker=parallel -f -o %t2.o -oso-prepend-path=%p/../ -y %s
+# RUN: dsymutil --deterministic full --linker=parallel -f -o %t3.o -oso-prepend-path=%p/../ -y %s \
 # RUN:   --num-threads 1
-# RUN: dsymutil --linker=parallel -f -o %t4.o -oso-prepend-path=%p/../ -y %s \
+# RUN: dsymutil --deterministic full --linker=parallel -f -o %t4.o -oso-prepend-path=%p/../ -y %s \
+# RUN:   --num-threads 3
+# ### Following comparision will fail if files do not match
+# RUN: diff %t1.o %t2.o
+# RUN: diff %t1.o %t3.o
+# RUN: diff %t1.o %t4.o
+
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o %t1.o -oso-prepend-path=%p/../ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o %t2.o -oso-prepend-path=%p/../ -y %s
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o %t3.o -oso-prepend-path=%p/../ -y %s \
+# RUN:   --num-threads 1
+# RUN: dsymutil --deterministic trusted --linker=parallel -f -o %t4.o -oso-prepend-path=%p/../ -y %s \
 # RUN:   --num-threads 3
 # ### Following comparision will fail if files do not match
 # RUN: diff %t1.o %t2.o
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/deterministic.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/deterministic.test
new file mode 100644
index 00000000000000..32f39b3a00f4ee
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/deterministic.test
@@ -0,0 +1,146 @@
+## This test checks that debug info stays correct with
+## any value of deterministic option.
+
+# RUN: yaml2obj %s -o %t.o
+
+# RUN: llvm-dwarfutil --linker parallel --deterministic full %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+
+# RUN: llvm-dwarfutil --linker parallel --deterministic full --no-odr %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+
+# RUN: llvm-dwarfutil --linker parallel --deterministic trusted %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+
+# RUN: llvm-dwarfutil --linker parallel --deterministic trusted --no-odr %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+#
+# # RUN: llvm-dwarfutil --linker parallel --deterministic none %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+
+# RUN: llvm-dwarfutil --linker parallel --deterministic none --no-odr %t.o - | llvm-dwarfdump --verify - | FileCheck %s
+
+# CHECK: Verifying
+# CHECK: No errors.
+
+--- !ELF
+FileHeader:
+  Class:    ELFCLASS64
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    Size:            0x1b
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+            - Value:  0x1000
+            - Value:  0x1b
+        - AbbrCode: 3
+          Values:
+            - CStr: class1
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 3
+          Values:
+            - CStr: class2
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 3
+          Values:
+            - CStr: class3
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 8
+          Values:
+            - CStr: int
+        - AbbrCode: 2
+          Values:
+            - CStr: foo1
+            - Value:  0x1000
+            - Value:  0x10
+            - Value:  0x0000002a
+        - AbbrCode: 2
+          Values:
+            - CStr: foo2
+            - Value:  0x0
+            - Value:  0x100
+            - Value:  0x00000040
+        - AbbrCode: 0
+...
diff --git a/llvm/test/tools/llvm-dwarfutil/help.test b/llvm/test/tools/llvm-dwarfutil/help.test
index 7fc1cc17682e70..d939324bd35537 100644
--- a/llvm/test/tools/llvm-dwarfutil/help.test
+++ b/llvm/test/tools/llvm-dwarfutil/help.test
@@ -7,6 +7,7 @@
 # CHECK: OVERVIEW: llvm-dwarfutil is a tool to copy and manipulate debug info
 # CHECK: USAGE: {{.*}}llvm-dwarfutil{{.*}} [options] <input file> <output file>
 # CHECK: OPTIONS:
+# CHECK:   --deterministic
 # CHECK:   --garbage-collection
 # CHECK:   --help
 # CHECK:   -h
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 5ae5ecd556adb7..b9f729d8e10eb4 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -690,6 +690,7 @@ bool DwarfLinkerForBinary::linkImpl(
   GeneralLinker->setNumThreads(Options.Threads);
   GeneralLinker->setPrependPath(Options.PrependPath);
   GeneralLinker->setKeepFunctionForStatic(Options.KeepFunctionForStatic);
+  GeneralLinker->setDeterministicLevel(Options.DesiredDeterministicLevel);
   GeneralLinker->setInputVerificationHandler(
       [&](const DWARFFile &File, llvm::StringRef Output) {
         std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h
index fd9d985097d6e2..a3bc625acdc5d8 100644
--- a/llvm/tools/dsymutil/LinkUtils.h
+++ b/llvm/tools/dsymutil/LinkUtils.h
@@ -75,6 +75,10 @@ struct LinkOptions {
   dwarf_linker::DWARFLinkerBase::OutputFileType FileType =
       dwarf_linker::DWARFLinkerBase::OutputFileType::Object;
 
+  // Deterministic mode.
+  dwarf_linker::DeterministicLevel DesiredDeterministicLevel =
+      dwarf_linker::DeterministicLevel::Full;
+
   /// The accelerator table kind
   DsymutilAccelTableKind TheAccelTableKind;
 
diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td
index a4e4c6c4cdb9c0..d9f9661e176ff2 100644
--- a/llvm/tools/dsymutil/Options.td
+++ b/llvm/tools/dsymutil/Options.td
@@ -212,3 +212,9 @@ def dsym_search_path: Separate<["-", "--"], "D">,
   MetaVarName<"<path>">,
   HelpText<"Specify a directory that contain dSYM files to search for.">,
   Group<grp_general>;
+
+def deterministic: Separate<["--", "-"], "deterministic">,
+  MetaVarName<"<level name>">,
+  HelpText<"Specify the desired level of output determinism.\nValid names are 'full', 'trusted' and 'none'. Defaults to 'full'">,
+  Group<grp_general>;
+def: Joined<["--", "-"], "deterministic=">, Alias<deterministic>;
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index b0e988c6f8e4b8..b3641d2bce78dc 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -246,6 +246,26 @@ getDWARFLinkerType(opt::InputArgList &Args) {
   return DsymutilDWARFLinkerType::Classic;
 }
 
+static Expected<DeterministicLevel>
+getDeterministicLevel(opt::InputArgList &Args) {
+  if (opt::Arg *LinkerType = Args.getLastArg(OPT_deterministic)) {
+    StringRef S = LinkerType->getValue();
+    if (S == "full")
+      return DeterministicLevel::Full;
+    if (S == "trusted")
+      return DeterministicLevel::Trusted;
+    if (S == "none")
+      return DeterministicLevel::None;
+    return make_error<StringError>("invalid deterministic level specified: '" +
+                                       S +
+                                       "'. Supported values are 'full', "
+                                       "'trusted', 'none'.",
+                                   inconvertibleErrorCode());
+  }
+
+  return DeterministicLevel::Full;
+}
+
 static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
   if (Args.hasArg(OPT_gen_reproducer))
     return ReproducerMode::GenerateOnExit;
@@ -341,6 +361,12 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
     return DWARFLinkerType.takeError();
   }
 
+  if (Expected<DeterministicLevel> DeterministicLevelVal =
+          getDeterministicLevel(Args))
+    Options.LinkOpts.DesiredDeterministicLevel = *DeterministicLevelVal;
+  else
+    return DeterministicLevelVal.takeError();
+
   if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
     Options.SymbolMap = SymbolMap->getValue();
 
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index bd17f3c4a6595e..7cadaf91f38151 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -362,6 +362,7 @@ Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
   DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
   DebugInfoLinker->setVerbosity(Options.Verbose);
   DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
+  DebugInfoLinker->setDeterministicLevel(Options.DesiredDeterministicLevel);
 
   s...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/83020


More information about the llvm-commits mailing list