[llvm] Normalize file path to fix problems with different folder separators. (PR #215225)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 03:05:50 PDT 2026


https://github.com/VladimirMedic updated https://github.com/llvm/llvm-project/pull/215225

>From 487cf96bcb620ed141a174f9a6c5ea4f54fa9784 Mon Sep 17 00:00:00 2001
From: VladimirMedic <Vladimir.Medic at amd.com>
Date: Mon, 10 Aug 2026 10:05:46 +0200
Subject: [PATCH 1/5] Normalize file path to fix problems with different folder
 separators.

---
 .../Inputs/source-interleave-windows-path.ll  | 76 +++++++++++++++++++
 ...source-interleave-function-from-debug.test | 12 +--
 .../X86/source-interleave-prefix-windows.test | 16 ++--
 .../X86/source-interleave-prefix.test         | 27 ++++---
 .../tools/llvm-objdump/X86/source-path.test   | 33 ++++++++
 llvm/tools/llvm-objdump/SourcePrinter.cpp     | 24 +++---
 6 files changed, 153 insertions(+), 35 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll

diff --git a/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll b/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll
new file mode 100644
index 0000000000000..fd6f320c60453
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll
@@ -0,0 +1,76 @@
+; NOTE: This is a copy of source-interleave.ll whose source path is spelled with
+;       Windows separators, as emitted by a toolchain running on Windows. It
+;       lets source-path.test check that such paths are handled on any host.
+;
+;       The whole relative path is held in the file name with an empty
+;       directory. MCDwarfLineTableHeader::tryGetFile splits that into a
+;       directory and a base name using the host separator, so on a POSIX host
+;       nothing is split off and the recorded path keeps '\' throughout, which
+;       is the case this is meant to cover.
+;
+;       The separators are baked in rather than substituted by sed, because
+;       escaping a backslash through both sed and the lit shell is unreadable.
+
+; ModuleID = 'source-interleave-x86_64.bc'
+source_filename = "source-interleave-x86_64.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at a = global i32 1, align 4, !dbg !4
+
+; Function Attrs: nounwind uwtable
+define i32 @foo() #0 !dbg !9 {
+entry:
+  %0 = load i32, ptr @a, align 4, !dbg !12
+  ret i32 %0, !dbg !13
+}
+
+; Function Attrs: nounwind uwtable
+define i32 @main() #0 !dbg !14 {
+entry:
+  %retval = alloca i32, align 4
+  %b = alloca ptr, align 8
+  store i32 0, ptr %retval, align 4
+  call void @llvm.dbg.declare(metadata ptr %b, metadata !15, metadata !17), !dbg !18
+  store ptr @a, ptr %b, align 8, !dbg !18
+  %0 = load ptr, ptr %b, align 8, !dbg !19
+  %1 = load i32, ptr %0, align 4, !dbg !20
+  %call = call i32 @foo(), !dbg !21
+  %add = add nsw i32 %1, %call, !dbg !22
+  ret i32 %add, !dbg !23
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3)
+!1 = !DIFile(filename: "dx12\5Ccompute\5Cno_rs\5Csource-interleave-x86_64.c", directory: "")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true), expr: !DIExpression())
+!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!6 = !{i32 2, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{!"clang version 4.0.0"}
+!9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!5}
+!12 = !DILocation(line: 3, column: 10, scope: !9)
+!13 = !DILocation(line: 3, column: 3, scope: !9)
+!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !10, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: false, unit: !0, retainedNodes: !2)
+!15 = !DILocalVariable(name: "b", scope: !14, file: !1, line: 7, type: !16)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, align: 64)
+!17 = !DIExpression()
+!18 = !DILocation(line: 7, column: 8, scope: !14)
+!19 = !DILocation(line: 8, column: 11, scope: !14)
+!20 = !DILocation(line: 8, column: 10, scope: !14)
+!21 = !DILocation(line: 8, column: 15, scope: !14)
+!22 = !DILocation(line: 8, column: 13, scope: !14)
+!23 = !DILocation(line: 8, column: 3, scope: !14)
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
index 96ae656100531..32ef8d8c0eb9e 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
@@ -9,7 +9,7 @@
 
 ; CHECK:      0000000000000000 <foo>:
 ; CHECK-NEXT: ; foo():
-; CHECK-NEXT: ; /tmp{{/|\\}}src.cc:1
+; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:1
 ; CHECK-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
 ; CHECK-NEXT:        5: c3                            retq
 
@@ -18,7 +18,7 @@
 ; CHECK-DEMANGLE:         0000000000000008 <xyz::bar()>:
 ; CHECK-DEMANGLE-NEXT:    ; xyz::bar():
 
-; CHECK-NEXT: ; /tmp{{/|\\}}src.cc:3
+; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
 ; CHECK-NEXT:        8: b8 0a 00 00 00                movl    $10, %eax
 ; CHECK-NEXT:        d: c3                            retq
 
@@ -27,7 +27,7 @@
 ; CHECK-DEMANGLE:         0000000000000010 <xyz::baz()>:
 ; CHECK-DEMANGLE-NEXT:    ; xyz::baz():
 
-; CHECK-NEXT: ; /tmp{{/|\\}}src.cc:3
+; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
 ; CHECK-NEXT:       10: b8 14 00 00 00                movl    $20, %eax
 ; CHECK-NEXT:       15: c3                            retq
 
@@ -39,17 +39,17 @@
 
 ; STRIPPED:      0000000000000000 <.text>:
 ; STRIPPED-NEXT: ; Function1():
-; STRIPPED-NEXT: ; /tmp{{/|\\}}src.cc:1
+; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:1
 ; STRIPPED-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
 ; STRIPPED-NEXT:        5: c3                            retq
 
 ; STRIPPED:      ; xyz::bar():
-; STRIPPED-NEXT: ; /tmp{{/|\\}}src.cc:3
+; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
 ; STRIPPED-NEXT:        8: b8 0a 00 00 00                movl    $10, %eax
 ; STRIPPED-NEXT:        d: c3                            retq
 
 ; STRIPPED:      ; xyz::baz():
-; STRIPPED-NEXT: ; /tmp{{/|\\}}src.cc:3
+; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
 ; STRIPPED-NEXT:       10: b8 14 00 00 00                movl    $20, %eax
 ; STRIPPED-NEXT:       15: c3                            retq
 
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
index f75ba94353b68..bee32bd74007d 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
@@ -6,14 +6,12 @@
 
 ; RUN: sed -e "s,SRC_COMPDIR,/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
 ; RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
-; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix' -DSEP=%{fs-sep}
+; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix'
 
-;; When --prefix is specified and the file path is absolute, sys::path::append
-;; is used to add the file path to the prefix. On Windows, if the file path
-;; starts with a slash, sys::path::append currently does a straight
-;; concatenation, resulting in the first slash being preserved as-is ('/').
-;; The second slash (after 'Inputs') is generated by llc using
-;; sys::path::append to join the directory and filename, which uses the
-;; preferred path separator (controlled by LLVM_WINDOWS_PREFER_FORWARD_SLASH).
-; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]]/Inputs[[SEP]]source-interleave-x86_64.c
+;; The source path from the debug info is normalized before --prefix is applied,
+;; so the reported path uses one separator style throughout instead of mixing
+;; them. Which style that is depends on LLVM_WINDOWS_PREFER_FORWARD_SLASH, so
+;; both are accepted here. sys::path::append then concatenates the path onto
+;; the prefix without inserting a separator, because it already starts with one.
+; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
 
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
index 746add22f96e5..02cea7efbb6b9 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
@@ -1,19 +1,20 @@
 ;; Test --prefix option.
 
-;; Separators change from platform to platform. In POSIX the full path for the
-;; directory './Inputs' appended with the file 'source-interleave-x86_64.c' is
-;; './Inputs/source-interleave-x86_64.c'. For Windows it is
-;; './Inputs\source-interleave-x86_64.c'. Platform specific tests are needed
-;; since '\' may or may not be a separator.
+;; Separators change from platform to platform, and on Windows they further
+;; depend on LLVM_WINDOWS_PREFER_FORWARD_SLASH. Source paths taken from the
+;; debug info are normalized so that a single path does not mix styles, but
+;; which separator that ends up being is not part of the contract: every check
+;; below accepts '/' and '\' interchangeably. Platform specific tests are still
+;; needed since '\' may or may not be a separator.
 
 ;; Test prefix option ignored for relative paths.
-;; For the test below it is possible to accept both '/' and '\' as a separator.
+;; Normalization folds away the leading './' of './Inputs', leaving 'Inputs'.
 
 ; RUN: sed -e "s,SRC_COMPDIR,./Inputs,g" %p/Inputs/source-interleave.ll > %t-relative-path.ll
 ; RUN: llc -o %t-relative-path.o -filetype=obj -mtriple=x86_64-pc-linux %t-relative-path.ll
 ; RUN: llvm-objdump --prefix myprefix --source %t-relative-path.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-relative-path.o -DPREFIX=. -DCOMPDIR=/Inputs
-; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]][[COMPDIR]]{{[/\\]}}source-interleave-x86_64.c
+; RUN:   FileCheck %s --check-prefix=CHECK-RELATIVE-PREFIX -DFILE=%t-relative-path.o
+; CHECK-RELATIVE-PREFIX: warning: '[[FILE]]': failed to find source Inputs{{[/\\]}}source-interleave-x86_64.c
 
 ;; Test invalid source interleave fixed by adding the correct prefix.
 
@@ -28,18 +29,22 @@
 ; RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t-correct-prefix.ll
 ; RUN: llc -o %t-correct-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-correct-prefix.ll
 ; RUN: llvm-objdump --prefix myprefix --source %t-correct-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-correct-prefix.o -DPREFIX=myprefix%/p -DCOMPDIR=/Inputs
+; RUN:   FileCheck %s --check-prefix=CHECK-ABSOLUTE-PREFIX -DFILE=%t-correct-prefix.o
+;; The compilation directory is an absolute host path, so the middle of the
+;; reported path is not spelled out here.
+; CHECK-ABSOLUTE-PREFIX: warning: '[[FILE]]': failed to find source myprefix{{.*}}Inputs{{[/\\]}}source-interleave-x86_64.c
 
 ;; Using only a prefix separator is the same as not using the `--prefix` option.
 
 ; RUN: llvm-objdump --prefix / --source %t-missing-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX='' -DCOMPDIR=/Inputs
+; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=''
+; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
 
 ;; All trailing separators on the prefix are discarded.
 ;; The prefix 'myprefix//' is converted to 'myprefix'.
 
 ; RUN: llvm-objdump --prefix myprefix// --source %t-missing-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix -DCOMPDIR=/Inputs
+; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix
 
 ;; Test invalid source interleave fixed by adding the correct prefix and
 ;; stripping out an extra directory from the path.
diff --git a/llvm/test/tools/llvm-objdump/X86/source-path.test b/llvm/test/tools/llvm-objdump/X86/source-path.test
index 4d6e9990e8245..ee1be1f70b2ac 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-path.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-path.test
@@ -151,3 +151,36 @@
 ; LINE-SUBST-PREFIX-NEXT: pushq
 ; LINE-SUBST-PREFIX: ; [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c:3
 ; LINE-SUBST-PREFIX-NEXT: movq
+
+;; Objects built on Windows record source paths with '\' separators, which are
+;; not separators on a POSIX host. Paths from the debug info are normalized
+;; before the rules below are applied, so the same object behaves the same way
+;; whatever the host is.
+
+; RUN: llc -o %t-winpath.o -filetype=obj -mtriple=x86_64-pc-linux \
+; RUN:   %p/Inputs/source-interleave-windows-path.ll
+
+;; Which separator a path is printed with depends on the host and, on Windows,
+;; on LLVM_WINDOWS_PREFER_FORWARD_SLASH, so it is not checked for here. What is
+;; checked is that one path does not mix the two styles: the separator is
+;; captured from its first occurrence and has to be the same one throughout.
+; RUN: llvm-objdump --no-print-imm-hex -d --line-numbers %t-winpath.o | \
+; RUN:   FileCheck %s --check-prefix=WINPATH-LINE
+
+; WINPATH-LINE: <foo>:
+; WINPATH-LINE-NEXT: ; foo():
+; WINPATH-LINE-NEXT: ; dx12[[SEP:[/\\]]]compute[[SEP]]no_rs[[SEP]]source-interleave-x86_64.c:2
+
+;; <from> may be spelled with either separator; both name the same directory.
+
+; RUN: llvm-objdump --no-print-imm-hex -d --source \
+; RUN:   --substitute-path 'dx12\compute\no_rs' %/p/Inputs %t-winpath.o | \
+; RUN:   FileCheck %s --check-prefix=SOURCE
+; RUN: llvm-objdump --no-print-imm-hex -d --source \
+; RUN:   --substitute-path dx12/compute/no_rs %/p/Inputs %t-winpath.o | \
+; RUN:   FileCheck %s --check-prefix=SOURCE
+
+;; --source-dir finds the same file by its base name.
+
+; RUN: llvm-objdump --no-print-imm-hex -d --source --source-dir %/p/Inputs \
+; RUN:   %t-winpath.o | FileCheck %s --check-prefix=SOURCE
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.cpp b/llvm/tools/llvm-objdump/SourcePrinter.cpp
index 9d8daa9043fd8..3a06b3d721ba2 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -85,22 +85,22 @@ static std::string applySubstitutePaths(StringRef FileName) {
   if (SubstitutePaths.empty())
     return FileName.str();
 
+  // FileName is normalized by the caller, so the components split out of it are
+  // normalized too. Only the rules given on the command line still need it.
   StringRef BaseName = sys::path::filename(FileName);
-  SmallString<256> Directory(sys::path::parent_path(FileName));
-  normalizeSourcePath(Directory);
+  StringRef Directory = sys::path::parent_path(FileName);
 
   for (const auto &[From, To] : SubstitutePaths) {
     SmallString<256> FromPath(From);
     normalizeSourcePath(FromPath);
-    StringRef Dir = Directory;
-    if (!Dir.starts_with(FromPath))
+    if (!Directory.starts_with(FromPath))
       continue;
-    if (Dir.size() > FromPath.size() &&
-        !sys::path::is_separator(Dir[FromPath.size()]))
+    if (Directory.size() > FromPath.size() &&
+        !sys::path::is_separator(Directory[FromPath.size()]))
       continue;
 
     SmallString<256> NewDir(To);
-    StringRef Suffix = Dir.substr(FromPath.size());
+    StringRef Suffix = Directory.substr(FromPath.size());
     while (!Suffix.empty() && sys::path::is_separator(Suffix.front()))
       Suffix = Suffix.drop_front();
     if (!Suffix.empty())
@@ -111,7 +111,6 @@ static std::string applySubstitutePaths(StringRef FileName) {
       return BaseName.str();
     SmallString<256> Result(NewDir);
     sys::path::append(Result, BaseName);
-    normalizeSourcePath(Result);
     return std::string(Result);
   }
 
@@ -747,6 +746,12 @@ void SourcePrinter::printSourceLine(formatted_raw_ostream &OS,
       Symbolizer->symbolizeCode(*Obj, Address);
   if (ExpectedLineInfo) {
     LineInfo = *ExpectedLineInfo;
+    if (LineInfo.FileName != DILineInfo::BadString) {
+      SmallString<256> NormalizedName(LineInfo.FileName);
+      normalizeSourcePath(NormalizedName);
+      LineInfo.FileName = std::string(NormalizedName);
+    }
+
   } else if (!WarnedInvalidDebugInfo) {
     WarnedInvalidDebugInfo = true;
     // TODO Untested.
@@ -754,7 +759,8 @@ void SourcePrinter::printSourceLine(formatted_raw_ostream &OS,
                       toString(ExpectedLineInfo.takeError()),
                   ObjectFilename);
   }
-  if (!objdump::SubstitutePaths.empty())
+  if (!objdump::SubstitutePaths.empty() &&
+      LineInfo.FileName != DILineInfo::BadString)
     LineInfo.FileName = applySubstitutePaths(LineInfo.FileName);
 
   if (!objdump::Prefix.empty() &&

>From 3b38e2f2694ab7eacf9ae7fa27d3bae51257e545 Mon Sep 17 00:00:00 2001
From: VladimirMedic <Vladimir.Medic at amd.com>
Date: Mon, 10 Aug 2026 13:14:11 +0200
Subject: [PATCH 2/5] Fix failing test for other targets.

---
 .../ELF/Hexagon/source-interleave-hexagon.ll     |  4 +++-
 .../llvm-objdump/XCOFF/print-linenumber.test     | 16 ++++++++++------
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
index 0024e0b4908ab..a93fa9045794d 100644
--- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
+++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
@@ -67,7 +67,9 @@ attributes #1 = { nounwind readnone }
 !23 = !DILocation(line: 8, column: 3, scope: !14)
 ; LINES: <main>:
 ; LINES-NEXT: main():
-; LINES-NEXT: SRC_COMPDIR/source-interleave-hexagon.c:6
+;; Source paths are normalized to the host separator, which is '/' on POSIX and
+;; '\' on Windows, so match either.
+; LINES-NEXT: Inputs{{[/\\]}}source-interleave-hexagon.c:6
 
 ; SOURCE: <main>:
 ; SOURCE-NEXT: int main() {
diff --git a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
index 8256e27c064dd..3e09481edbe9f 100644
--- a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
+++ b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
@@ -1,5 +1,9 @@
 # Test that the `llvm-objdump -l` can print correct line numbers.
 
+## The path recorded in these objects is "/basic.c". Source paths are normalized
+## to the host separator before printing, so the leading separator is '/' on
+## POSIX and '\' on Windows. Only its consistency is checked here.
+
 # RUN: llvm-objdump -d -l %p/Inputs/basic32.o | FileCheck %s --check-prefix=LINES32
 # RUN: llvm-objdump -d -l %p/Inputs/basic64.o | FileCheck %s --check-prefix=LINES64
 
@@ -19,11 +23,11 @@
 # LINES32:       Disassembly of section .text:
 # LINES32:       00000000 <.main>:
 # LINES32:       ; .main():
-# LINES32-NEXT:  ; /basic.c:1
+# LINES32-NEXT:  ; [[SEP:[/\\]]]basic.c:1
 # LINES32-NEXT:         0: 38 60 00 00  	li 3, 0
-# LINES32-NEXT:  ; /basic.c:3
+# LINES32-NEXT:  ; [[SEP]]basic.c:3
 # LINES32-NEXT:         4: 48 00 00 04  	b 0x8
-# LINES32-NEXT:  ; /basic.c:4
+# LINES32-NEXT:  ; [[SEP]]basic.c:4
 # LINES32-NEXT:         8: 4e 80 00 20  	blr
 # LINES32-NEXT:         c: 00 00 00 00  	<unknown>
 # LINES32-NEXT:        10: 00 00 20 40  	<unknown>
@@ -36,11 +40,11 @@
 # LINES64:       Disassembly of section .text:
 # LINES64:       0000000000000000 <.main>:
 # LINES64:       ; .main():
-# LINES64-NEXT:  ; /basic.c:1
+# LINES64-NEXT:  ; [[SEP:[/\\]]]basic.c:1
 # LINES64-NEXT:         0: 38 60 00 00  	li 3, 0
-# LINES64-NEXT:  ; /basic.c:3
+# LINES64-NEXT:  ; [[SEP]]basic.c:3
 # LINES64-NEXT:         4: 48 00 00 04  	b 0x8
-# LINES64-NEXT:  ; /basic.c:4
+# LINES64-NEXT:  ; [[SEP]]basic.c:4
 # LINES64-NEXT:         8: 4e 80 00 20  	blr
 # LINES64-NEXT:         c: 00 00 00 00  	<unknown>
 # LINES64-NEXT:        10: 00 00 20 40  	<unknown>

>From 5a5d25e8343882789672b63576af11fa1ccb2e22 Mon Sep 17 00:00:00 2001
From: VladimirMedic <Vladimir.Medic at amd.com>
Date: Fri, 14 Aug 2026 16:25:32 +0200
Subject: [PATCH 3/5] Addressing review comments, use %{fs-sep} to check the
 correct path separator is used.

---
 .../ELF/Hexagon/source-interleave-hexagon.ll  |  9 ++-
 .../Inputs/source-interleave-windows-path.ll  | 76 -------------------
 ...source-interleave-function-from-debug.test | 18 ++---
 .../X86/source-interleave-prefix-windows.test | 16 ++--
 .../X86/source-interleave-prefix.test         | 29 ++++---
 .../tools/llvm-objdump/X86/source-path.test   | 55 ++++++++------
 .../llvm-objdump/XCOFF/print-linenumber.test  | 12 +--
 llvm/tools/llvm-objdump/SourcePrinter.cpp     |  1 -
 8 files changed, 76 insertions(+), 140 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll

diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
index a93fa9045794d..308f8f5aae1dd 100644
--- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
+++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
@@ -1,6 +1,6 @@
 ;  RUN: sed -e "s,SRC_COMPDIR,%p/Inputs,g" %s > %t.ll
 ;  RUN: llc  -o %t.o -filetype=obj -mtriple=hexagon-unknown-elf  %t.ll
-;  RUN: llvm-objdump  -d -l %t.o | FileCheck --check-prefix="LINES" %t.ll
+;  RUN: llvm-objdump  -d -l %t.o | FileCheck --check-prefix="LINES" -DSEP=%{fs-sep} %t.ll
 ;  RUN: llvm-objdump  -d -S %t.o | FileCheck --check-prefix="SOURCE" %t.ll
 ; ModuleID = 'source-interleave-hexagon.bc'
 source_filename = "source-interleave-hexagon.c"
@@ -67,9 +67,10 @@ attributes #1 = { nounwind readnone }
 !23 = !DILocation(line: 8, column: 3, scope: !14)
 ; LINES: <main>:
 ; LINES-NEXT: main():
-;; Source paths are normalized to the host separator, which is '/' on POSIX and
-;; '\' on Windows, so match either.
-; LINES-NEXT: Inputs{{[/\\]}}source-interleave-hexagon.c:6
+;; The compilation directory is spelled with '/', so on Windows the recorded
+;; path mixes separators. It is normalized to the host separator before being
+;; printed, and [[SEP]] is that separator, not "either of the two".
+; LINES-NEXT: Inputs[[SEP]]source-interleave-hexagon.c:6
 
 ; SOURCE: <main>:
 ; SOURCE-NEXT: int main() {
diff --git a/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll b/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll
deleted file mode 100644
index fd6f320c60453..0000000000000
--- a/llvm/test/tools/llvm-objdump/X86/Inputs/source-interleave-windows-path.ll
+++ /dev/null
@@ -1,76 +0,0 @@
-; NOTE: This is a copy of source-interleave.ll whose source path is spelled with
-;       Windows separators, as emitted by a toolchain running on Windows. It
-;       lets source-path.test check that such paths are handled on any host.
-;
-;       The whole relative path is held in the file name with an empty
-;       directory. MCDwarfLineTableHeader::tryGetFile splits that into a
-;       directory and a base name using the host separator, so on a POSIX host
-;       nothing is split off and the recorded path keeps '\' throughout, which
-;       is the case this is meant to cover.
-;
-;       The separators are baked in rather than substituted by sed, because
-;       escaping a backslash through both sed and the lit shell is unreadable.
-
-; ModuleID = 'source-interleave-x86_64.bc'
-source_filename = "source-interleave-x86_64.c"
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
- at a = global i32 1, align 4, !dbg !4
-
-; Function Attrs: nounwind uwtable
-define i32 @foo() #0 !dbg !9 {
-entry:
-  %0 = load i32, ptr @a, align 4, !dbg !12
-  ret i32 %0, !dbg !13
-}
-
-; Function Attrs: nounwind uwtable
-define i32 @main() #0 !dbg !14 {
-entry:
-  %retval = alloca i32, align 4
-  %b = alloca ptr, align 8
-  store i32 0, ptr %retval, align 4
-  call void @llvm.dbg.declare(metadata ptr %b, metadata !15, metadata !17), !dbg !18
-  store ptr @a, ptr %b, align 8, !dbg !18
-  %0 = load ptr, ptr %b, align 8, !dbg !19
-  %1 = load i32, ptr %0, align 4, !dbg !20
-  %call = call i32 @foo(), !dbg !21
-  %add = add nsw i32 %1, %call, !dbg !22
-  ret i32 %add, !dbg !23
-}
-
-; Function Attrs: nounwind readnone
-declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
-
-attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind readnone }
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!6, !7}
-!llvm.ident = !{!8}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3)
-!1 = !DIFile(filename: "dx12\5Ccompute\5Cno_rs\5Csource-interleave-x86_64.c", directory: "")
-!2 = !{}
-!3 = !{!4}
-!4 = !DIGlobalVariableExpression(var: !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true), expr: !DIExpression())
-!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
-!6 = !{i32 2, !"Dwarf Version", i32 4}
-!7 = !{i32 2, !"Debug Info Version", i32 3}
-!8 = !{!"clang version 4.0.0"}
-!9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
-!10 = !DISubroutineType(types: !11)
-!11 = !{!5}
-!12 = !DILocation(line: 3, column: 10, scope: !9)
-!13 = !DILocation(line: 3, column: 3, scope: !9)
-!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !10, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: false, unit: !0, retainedNodes: !2)
-!15 = !DILocalVariable(name: "b", scope: !14, file: !1, line: 7, type: !16)
-!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, align: 64)
-!17 = !DIExpression()
-!18 = !DILocation(line: 7, column: 8, scope: !14)
-!19 = !DILocation(line: 8, column: 11, scope: !14)
-!20 = !DILocation(line: 8, column: 10, scope: !14)
-!21 = !DILocation(line: 8, column: 15, scope: !14)
-!22 = !DILocation(line: 8, column: 13, scope: !14)
-!23 = !DILocation(line: 8, column: 3, scope: !14)
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
index 32ef8d8c0eb9e..998af741af037 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
@@ -2,14 +2,14 @@
 ;; output, getting it from the debug info.
 
 ; RUN: llc < %s -o %t.o -filetype=obj -mtriple=x86_64-unknown-linux-gnu
-; RUN: llvm-objdump --no-print-imm-hex -dl %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DEMANGLE
+; RUN: llvm-objdump --no-print-imm-hex -dl %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DEMANGLE -DSEP=%{fs-sep}
 
 ; RUN: llc < %s -o %t.o -filetype=obj -mtriple=x86_64-unknown-linux-gnu
-; RUN: llvm-objdump --no-print-imm-hex -dlC %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-DEMANGLE
+; RUN: llvm-objdump --no-print-imm-hex -dlC %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-DEMANGLE -DSEP=%{fs-sep}
 
 ; CHECK:      0000000000000000 <foo>:
 ; CHECK-NEXT: ; foo():
-; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:1
+; CHECK-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:1
 ; CHECK-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
 ; CHECK-NEXT:        5: c3                            retq
 
@@ -18,7 +18,7 @@
 ; CHECK-DEMANGLE:         0000000000000008 <xyz::bar()>:
 ; CHECK-DEMANGLE-NEXT:    ; xyz::bar():
 
-; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
+; CHECK-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:3
 ; CHECK-NEXT:        8: b8 0a 00 00 00                movl    $10, %eax
 ; CHECK-NEXT:        d: c3                            retq
 
@@ -27,7 +27,7 @@
 ; CHECK-DEMANGLE:         0000000000000010 <xyz::baz()>:
 ; CHECK-DEMANGLE-NEXT:    ; xyz::baz():
 
-; CHECK-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
+; CHECK-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:3
 ; CHECK-NEXT:       10: b8 14 00 00 00                movl    $20, %eax
 ; CHECK-NEXT:       15: c3                            retq
 
@@ -35,21 +35,21 @@
 ;; info. The IR is intentionally doctored to have different names in debug info
 ;; for the test case here.
 ; RUN: llvm-strip %t.o -N foo -N _ZN3xyz3barEv -N _ZN3xyz3bazEv -o %t-stripped.o
-; RUN: llvm-objdump --no-print-imm-hex -dlC %t-stripped.o | FileCheck %s --check-prefix=STRIPPED
+; RUN: llvm-objdump --no-print-imm-hex -dlC %t-stripped.o | FileCheck %s --check-prefix=STRIPPED -DSEP=%{fs-sep}
 
 ; STRIPPED:      0000000000000000 <.text>:
 ; STRIPPED-NEXT: ; Function1():
-; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:1
+; STRIPPED-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:1
 ; STRIPPED-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
 ; STRIPPED-NEXT:        5: c3                            retq
 
 ; STRIPPED:      ; xyz::bar():
-; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
+; STRIPPED-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:3
 ; STRIPPED-NEXT:        8: b8 0a 00 00 00                movl    $10, %eax
 ; STRIPPED-NEXT:        d: c3                            retq
 
 ; STRIPPED:      ; xyz::baz():
-; STRIPPED-NEXT: ; {{/|\\}}tmp{{/|\\}}src.cc:3
+; STRIPPED-NEXT: ; [[SEP]]tmp[[SEP]]src.cc:3
 ; STRIPPED-NEXT:       10: b8 14 00 00 00                movl    $20, %eax
 ; STRIPPED-NEXT:       15: c3                            retq
 
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
index bee32bd74007d..555bd3660df4f 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
@@ -6,12 +6,14 @@
 
 ; RUN: sed -e "s,SRC_COMPDIR,/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
 ; RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
-; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix'
+; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix' -DSEP=%{fs-sep}
 
-;; The source path from the debug info is normalized before --prefix is applied,
-;; so the reported path uses one separator style throughout instead of mixing
-;; them. Which style that is depends on LLVM_WINDOWS_PREFER_FORWARD_SLASH, so
-;; both are accepted here. sys::path::append then concatenates the path onto
-;; the prefix without inserting a separator, because it already starts with one.
-; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
+;; The compilation directory '/Inputs' is joined to the file name with the
+;; preferred separator, so the path recorded in the debug info mixes '/' and
+;; '\'. It is normalized before --prefix is applied, so every separator below is
+;; [[SEP]], the one native to this host: output that still mixed the two, or
+;; that used the other style, would not match. sys::path::append then
+;; concatenates the path onto the prefix without inserting a separator, because
+;; it already starts with one.
+; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
index 02cea7efbb6b9..7dfe2691efc95 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
@@ -1,20 +1,19 @@
 ;; Test --prefix option.
 
-;; Separators change from platform to platform, and on Windows they further
-;; depend on LLVM_WINDOWS_PREFER_FORWARD_SLASH. Source paths taken from the
-;; debug info are normalized so that a single path does not mix styles, but
-;; which separator that ends up being is not part of the contract: every check
-;; below accepts '/' and '\' interchangeably. Platform specific tests are still
+;; Source paths taken from the debug info are normalized to the separator native
+;; to the host, which [[SEP]] expands to. Platform specific tests are still
 ;; needed since '\' may or may not be a separator.
 
 ;; Test prefix option ignored for relative paths.
-;; Normalization folds away the leading './' of './Inputs', leaving 'Inputs'.
+;; './Inputs' is joined to the file name with the preferred separator, so on
+;; Windows the recorded path reads './Inputs\source-interleave-x86_64.c'.
+;; Normalization folds away the leading './' and unifies the separators.
 
 ; RUN: sed -e "s,SRC_COMPDIR,./Inputs,g" %p/Inputs/source-interleave.ll > %t-relative-path.ll
 ; RUN: llc -o %t-relative-path.o -filetype=obj -mtriple=x86_64-pc-linux %t-relative-path.ll
 ; RUN: llvm-objdump --prefix myprefix --source %t-relative-path.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-RELATIVE-PREFIX -DFILE=%t-relative-path.o
-; CHECK-RELATIVE-PREFIX: warning: '[[FILE]]': failed to find source Inputs{{[/\\]}}source-interleave-x86_64.c
+; RUN:   FileCheck %s --check-prefix=CHECK-RELATIVE-PREFIX -DFILE=%t-relative-path.o -DSEP=%{fs-sep}
+; CHECK-RELATIVE-PREFIX: warning: '[[FILE]]': failed to find source Inputs[[SEP]]source-interleave-x86_64.c
 
 ;; Test invalid source interleave fixed by adding the correct prefix.
 
@@ -28,23 +27,23 @@
 
 ; RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t-correct-prefix.ll
 ; RUN: llc -o %t-correct-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-correct-prefix.ll
+;; The compilation directory is written with '/' but is normalized, so the
+;; reported path is %p rather than %/p. sys::path::append does not insert a
+;; separator between the prefix and a path that has a root name.
 ; RUN: llvm-objdump --prefix myprefix --source %t-correct-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-ABSOLUTE-PREFIX -DFILE=%t-correct-prefix.o
-;; The compilation directory is an absolute host path, so the middle of the
-;; reported path is not spelled out here.
-; CHECK-ABSOLUTE-PREFIX: warning: '[[FILE]]': failed to find source myprefix{{.*}}Inputs{{[/\\]}}source-interleave-x86_64.c
+; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-correct-prefix.o -DPREFIX=myprefix%p -DSEP=%{fs-sep}
 
 ;; Using only a prefix separator is the same as not using the `--prefix` option.
 
 ; RUN: llvm-objdump --prefix / --source %t-missing-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=''
-; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
+; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX='' -DSEP=%{fs-sep}
+; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
 ;; All trailing separators on the prefix are discarded.
 ;; The prefix 'myprefix//' is converted to 'myprefix'.
 
 ; RUN: llvm-objdump --prefix myprefix// --source %t-missing-prefix.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix
+; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix -DSEP=%{fs-sep}
 
 ;; Test invalid source interleave fixed by adding the correct prefix and
 ;; stripping out an extra directory from the path.
diff --git a/llvm/test/tools/llvm-objdump/X86/source-path.test b/llvm/test/tools/llvm-objdump/X86/source-path.test
index ee1be1f70b2ac..cd8eadd6086c2 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-path.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-path.test
@@ -27,9 +27,13 @@
 ; LINE-NEXT: retq
 
 ; RUN: llvm-objdump --no-print-imm-hex -d --source %t.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING -DFILE=%t.o
+; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING -DFILE=%t.o -DSEP=%{fs-sep}
 
-; SOURCE-MISSING: warning: '[[FILE]]': failed to find source {{[/\\]}}wrong{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
+;; The compilation directory is spelled with '/' but is joined to the file name
+;; with the host separator, so on Windows the recorded path mixes the two.
+;; Normalization replaces every separator with [[SEP]], the one native to this
+;; host.
+; SOURCE-MISSING: warning: '[[FILE]]': failed to find source [[SEP]]wrong[[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
 ; RUN: llvm-objdump --no-print-imm-hex -d --source --substitute-path /wrong %/p %t.o | \
 ; RUN:   FileCheck %s --check-prefix=SOURCE
@@ -77,7 +81,7 @@
 ; SOURCE-NEXT: retq
 
 ; RUN: llvm-objdump --no-print-imm-hex -d --source --substitute-path /wron %/p %t.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING -DFILE=%t.o
+; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING -DFILE=%t.o -DSEP=%{fs-sep}
 
 ;; Two --source-dir trees both contain source-interleave-x86_64.c (same line
 ;; count; distinct in-line markers). The copy from the **earlier** flag must
@@ -106,9 +110,9 @@
 ; RUN: llvm-objdump --no-print-imm-hex -d --source \
 ; RUN:   --substitute-path /wrong /nowhere \
 ; RUN:   --substitute-path /wrong/Inputs %/p/Inputs %t.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING-SUBST -DFILE=%t.o
+; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING-SUBST -DFILE=%t.o -DSEP=%{fs-sep}
 
-; SOURCE-MISSING-SUBST: warning: '[[FILE]]': failed to find source {{[/\\]}}nowhere{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c
+; SOURCE-MISSING-SUBST: warning: '[[FILE]]': failed to find source [[SEP]]nowhere[[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
 ;; First substitute rule is a no-match; second matching rule remaps the path.
 ; RUN: llvm-objdump --no-print-imm-hex -d --source \
@@ -123,11 +127,11 @@
 
 ;; Empty <to> without --source-dir: relative path is not resolved; warn once, no crash.
 ; RUN: llvm-objdump --no-print-imm-hex -d --source --substitute-path /wrong "" %t.o 2>&1 | \
-; RUN:   FileCheck %s --check-prefix=SOURCE-EMPTY-TO -DFILE=%t.o \
+; RUN:   FileCheck %s --check-prefix=SOURCE-EMPTY-TO -DFILE=%t.o -DSEP=%{fs-sep} \
 ; RUN:     --implicit-check-not="foo()"
 
 ; SOURCE-EMPTY-TO: <foo>:
-; SOURCE-EMPTY-TO: warning: '[[FILE]]': failed to find source Inputs{{[/\\]}}source-interleave-x86_64.c
+; SOURCE-EMPTY-TO: warning: '[[FILE]]': failed to find source Inputs[[SEP]]source-interleave-x86_64.c
 ; SOURCE-EMPTY-TO: pushq
 
 ;; Empty <from> is rejected .
@@ -143,33 +147,40 @@
 ; RUN:   FileCheck %s --check-prefix=SOURCE
 ; RUN: llvm-objdump --no-print-imm-hex -d --line-numbers \
 ; RUN:   --substitute-path /wrong/Inputs /Inputs --prefix %/p %t.o | \
-; RUN:   FileCheck %s --check-prefix=LINE-SUBST-PREFIX -DPREFIX=%/p
+; RUN:   FileCheck %s --check-prefix=LINE-SUBST-PREFIX -DPREFIX=%/p -DSEP=%{fs-sep}
 
+;; --prefix is prepended after normalization and keeps whatever spelling it was
+;; given, which is why [[PREFIX]] still reads with '/' while the part that came
+;; from the debug info uses the host separator.
 ; LINE-SUBST-PREFIX: <foo>:
 ; LINE-SUBST-PREFIX-NEXT: ; foo():
-; LINE-SUBST-PREFIX-NEXT: ; [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c:2
+; LINE-SUBST-PREFIX-NEXT: ; [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c:2
 ; LINE-SUBST-PREFIX-NEXT: pushq
-; LINE-SUBST-PREFIX: ; [[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}source-interleave-x86_64.c:3
+; LINE-SUBST-PREFIX: ; [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c:3
 ; LINE-SUBST-PREFIX-NEXT: movq
 
-;; Objects built on Windows record source paths with '\' separators, which are
-;; not separators on a POSIX host. Paths from the debug info are normalized
-;; before the rules below are applied, so the same object behaves the same way
-;; whatever the host is.
+;; Objects built on Windows may record source paths with '\' separators, which
+;; are not separators on a POSIX host. Such a path is only ever a string here:
+;; no file of that name exists on either host, and --line-numbers reports the
+;; path without looking for it.
+;;
+;; The compilation directory below mixes the two separators, so whichever host
+;; reads the object, one of them is not a separator there. llc keeps it as
+;; spelled and joins the file name on with the host separator, so what reaches
+;; llvm-objdump is of a mixed style on any host. The '\' is doubled for sed.
 
-; RUN: llc -o %t-winpath.o -filetype=obj -mtriple=x86_64-pc-linux \
-; RUN:   %p/Inputs/source-interleave-windows-path.ll
+; RUN: sed -e 's,SRC_COMPDIR,dx12\\compute/no_rs,g' %p/Inputs/source-interleave.ll > %t-winpath.ll
+; RUN: llc -o %t-winpath.o -filetype=obj -mtriple=x86_64-pc-linux %t-winpath.ll
 
-;; Which separator a path is printed with depends on the host and, on Windows,
-;; on LLVM_WINDOWS_PREFER_FORWARD_SLASH, so it is not checked for here. What is
-;; checked is that one path does not mix the two styles: the separator is
-;; captured from its first occurrence and has to be the same one throughout.
+;; The path has to come back out spelled with [[SEP]] throughout, the separator
+;; native to this host, which is what would regress if it stopped being
+;; normalized.
 ; RUN: llvm-objdump --no-print-imm-hex -d --line-numbers %t-winpath.o | \
-; RUN:   FileCheck %s --check-prefix=WINPATH-LINE
+; RUN:   FileCheck %s --check-prefix=WINPATH-LINE -DSEP=%{fs-sep}
 
 ; WINPATH-LINE: <foo>:
 ; WINPATH-LINE-NEXT: ; foo():
-; WINPATH-LINE-NEXT: ; dx12[[SEP:[/\\]]]compute[[SEP]]no_rs[[SEP]]source-interleave-x86_64.c:2
+; WINPATH-LINE-NEXT: ; dx12[[SEP]]compute[[SEP]]no_rs[[SEP]]source-interleave-x86_64.c:2
 
 ;; <from> may be spelled with either separator; both name the same directory.
 
diff --git a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
index 3e09481edbe9f..284f75ab4415e 100644
--- a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
+++ b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
@@ -1,11 +1,11 @@
 # Test that the `llvm-objdump -l` can print correct line numbers.
 
 ## The path recorded in these objects is "/basic.c". Source paths are normalized
-## to the host separator before printing, so the leading separator is '/' on
-## POSIX and '\' on Windows. Only its consistency is checked here.
+## to the host separator before printing, so the leading separator is the one
+## sys::path::native() produces here, which [[SEP]] expands to.
 
-# RUN: llvm-objdump -d -l %p/Inputs/basic32.o | FileCheck %s --check-prefix=LINES32
-# RUN: llvm-objdump -d -l %p/Inputs/basic64.o | FileCheck %s --check-prefix=LINES64
+# RUN: llvm-objdump -d -l %p/Inputs/basic32.o | FileCheck %s --check-prefix=LINES32 -DSEP=%{fs-sep}
+# RUN: llvm-objdump -d -l %p/Inputs/basic64.o | FileCheck %s --check-prefix=LINES64 -DSEP=%{fs-sep}
 
 ## basic32.o Compiled with IBM XL C/C++ for AIX, V16.1.1.0
 ## Compiler command: xlc basic.c -c -qdbgfmt=dwarf -g -q32 -o basic32.o
@@ -23,7 +23,7 @@
 # LINES32:       Disassembly of section .text:
 # LINES32:       00000000 <.main>:
 # LINES32:       ; .main():
-# LINES32-NEXT:  ; [[SEP:[/\\]]]basic.c:1
+# LINES32-NEXT:  ; [[SEP]]basic.c:1
 # LINES32-NEXT:         0: 38 60 00 00  	li 3, 0
 # LINES32-NEXT:  ; [[SEP]]basic.c:3
 # LINES32-NEXT:         4: 48 00 00 04  	b 0x8
@@ -40,7 +40,7 @@
 # LINES64:       Disassembly of section .text:
 # LINES64:       0000000000000000 <.main>:
 # LINES64:       ; .main():
-# LINES64-NEXT:  ; [[SEP:[/\\]]]basic.c:1
+# LINES64-NEXT:  ; [[SEP]]basic.c:1
 # LINES64-NEXT:         0: 38 60 00 00  	li 3, 0
 # LINES64-NEXT:  ; [[SEP]]basic.c:3
 # LINES64-NEXT:         4: 48 00 00 04  	b 0x8
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.cpp b/llvm/tools/llvm-objdump/SourcePrinter.cpp
index 3a06b3d721ba2..66ffa36cdd7eb 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -751,7 +751,6 @@ void SourcePrinter::printSourceLine(formatted_raw_ostream &OS,
       normalizeSourcePath(NormalizedName);
       LineInfo.FileName = std::string(NormalizedName);
     }
-
   } else if (!WarnedInvalidDebugInfo) {
     WarnedInvalidDebugInfo = true;
     // TODO Untested.

>From f4cfd7a04101c24773a2ff44903258154d4819fd Mon Sep 17 00:00:00 2001
From: VladimirMedic <Vladimir.Medic at amd.com>
Date: Tue, 18 Aug 2026 12:19:56 +0200
Subject: [PATCH 4/5] Changing comments in tests according to review.

---
 .../ELF/Hexagon/source-interleave-hexagon.ll  |  4 +--
 .../X86/source-interleave-prefix-windows.test | 12 ++++-----
 .../X86/source-interleave-prefix.test         |  2 +-
 .../tools/llvm-objdump/X86/source-path.test   | 25 ++++++++-----------
 .../llvm-objdump/XCOFF/print-linenumber.test  |  6 ++---
 5 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
index 308f8f5aae1dd..2de7e4d8140dc 100644
--- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
+++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/source-interleave-hexagon.ll
@@ -67,9 +67,7 @@ attributes #1 = { nounwind readnone }
 !23 = !DILocation(line: 8, column: 3, scope: !14)
 ; LINES: <main>:
 ; LINES-NEXT: main():
-;; The compilation directory is spelled with '/', so on Windows the recorded
-;; path mixes separators. It is normalized to the host separator before being
-;; printed, and [[SEP]] is that separator, not "either of the two".
+;; Show that directory separators are normalized to the preferred character.
 ; LINES-NEXT: Inputs[[SEP]]source-interleave-hexagon.c:6
 
 ; SOURCE: <main>:
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
index 555bd3660df4f..dce2328bd388e 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
@@ -8,12 +8,10 @@
 ; RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
 ; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix' -DSEP=%{fs-sep}
 
-;; The compilation directory '/Inputs' is joined to the file name with the
-;; preferred separator, so the path recorded in the debug info mixes '/' and
-;; '\'. It is normalized before --prefix is applied, so every separator below is
-;; [[SEP]], the one native to this host: output that still mixed the two, or
-;; that used the other style, would not match. sys::path::append then
-;; concatenates the path onto the prefix without inserting a separator, because
-;; it already starts with one.
+;; The compilation directory '/Inputs' is joined to the file name using the
+;; preferred separator, producing a mixed-style path. It is normalized before
+;; --prefix is applied, so all separators after the prefix are the host's preferred value.
+;; sys::path::append then joins it to the prefix without adding a separator
+;; because the path already starts with one.
 ; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
index 7dfe2691efc95..6361fcf69678e 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test
@@ -28,7 +28,7 @@
 ; RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t-correct-prefix.ll
 ; RUN: llc -o %t-correct-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-correct-prefix.ll
 ;; The compilation directory is written with '/' but is normalized, so the
-;; reported path is %p rather than %/p. sys::path::append does not insert a
+;; reported path is %p rather than %/p. llvm-objdump does not insert a
 ;; separator between the prefix and a path that has a root name.
 ; RUN: llvm-objdump --prefix myprefix --source %t-correct-prefix.o 2>&1 | \
 ; RUN:   FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-correct-prefix.o -DPREFIX=myprefix%p -DSEP=%{fs-sep}
diff --git a/llvm/test/tools/llvm-objdump/X86/source-path.test b/llvm/test/tools/llvm-objdump/X86/source-path.test
index cd8eadd6086c2..93c193bf476f6 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-path.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-path.test
@@ -30,9 +30,9 @@
 ; RUN:   FileCheck %s --check-prefix=SOURCE-MISSING -DFILE=%t.o -DSEP=%{fs-sep}
 
 ;; The compilation directory is spelled with '/' but is joined to the file name
-;; with the host separator, so on Windows the recorded path mixes the two.
-;; Normalization replaces every separator with [[SEP]], the one native to this
-;; host.
+;; with the preferred directory separator. On Windows, when
+;; LLVM_WINDOWS_PREFER_FORWARD_SLASH is not enabled, this means the path
+;; contains a mix of slash directions, which llvm-objdump then normalises.
 ; SOURCE-MISSING: warning: '[[FILE]]': failed to find source [[SEP]]wrong[[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
 ; RUN: llvm-objdump --no-print-imm-hex -d --source --substitute-path /wrong %/p %t.o | \
@@ -159,22 +159,17 @@
 ; LINE-SUBST-PREFIX: ; [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c:3
 ; LINE-SUBST-PREFIX-NEXT: movq
 
-;; Objects built on Windows may record source paths with '\' separators, which
-;; are not separators on a POSIX host. Such a path is only ever a string here:
-;; no file of that name exists on either host, and --line-numbers reports the
-;; path without looking for it.
+;; Source paths recorded in objects may use either path separator. They are
+;; treated as strings here: --line-numbers reports them without accessing the
+;; named file.
 ;;
-;; The compilation directory below mixes the two separators, so whichever host
-;; reads the object, one of them is not a separator there. llc keeps it as
-;; spelled and joins the file name on with the host separator, so what reaches
-;; llvm-objdump is of a mixed style on any host. The '\' is doubled for sed.
+;; The compilation directory deliberately contains mixed separators. llc
+;; preserves it as spelled and appends the file name using the host separator,
+;; so the resulting path may also have mixed separators. The '\' is doubled
+;; for sed. llvm-objdump then normalizes the slash direction when printing.
 
 ; RUN: sed -e 's,SRC_COMPDIR,dx12\\compute/no_rs,g' %p/Inputs/source-interleave.ll > %t-winpath.ll
 ; RUN: llc -o %t-winpath.o -filetype=obj -mtriple=x86_64-pc-linux %t-winpath.ll
-
-;; The path has to come back out spelled with [[SEP]] throughout, the separator
-;; native to this host, which is what would regress if it stopped being
-;; normalized.
 ; RUN: llvm-objdump --no-print-imm-hex -d --line-numbers %t-winpath.o | \
 ; RUN:   FileCheck %s --check-prefix=WINPATH-LINE -DSEP=%{fs-sep}
 
diff --git a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
index 284f75ab4415e..f352416bc343c 100644
--- a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
+++ b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test
@@ -1,8 +1,8 @@
 # Test that the `llvm-objdump -l` can print correct line numbers.
 
-## The path recorded in these objects is "/basic.c". Source paths are normalized
-## to the host separator before printing, so the leading separator is the one
-## sys::path::native() produces here, which [[SEP]] expands to.
+## The path recorded in these objects is "/basic.c". Source paths are
+## normalized to the preferred directory separator before printing,
+## so use a FileCheck variable to check for that in a portable manner.
 
 # RUN: llvm-objdump -d -l %p/Inputs/basic32.o | FileCheck %s --check-prefix=LINES32 -DSEP=%{fs-sep}
 # RUN: llvm-objdump -d -l %p/Inputs/basic64.o | FileCheck %s --check-prefix=LINES64 -DSEP=%{fs-sep}

>From a0dd21bf5195dbd9941466c6c96d437b6b6cfc34 Mon Sep 17 00:00:00 2001
From: VladimirMedic <Vladimir.Medic at amd.com>
Date: Thu, 27 Aug 2026 12:04:21 +0200
Subject: [PATCH 5/5] Add test cases that show prefix is preserved.

---
 .../X86/source-interleave-prefix-non-windows.test          | 7 +++++++
 .../llvm-objdump/X86/source-interleave-prefix-windows.test | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-non-windows.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-non-windows.test
index 0fba437dcde36..fba0da4cab250 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-non-windows.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-non-windows.test
@@ -9,3 +9,10 @@
 ; RUN: llvm-objdump --prefix 'myprefix/\' --source %t.o 2>&1 | FileCheck %s -DFILE=%t.o -DPREFIX='myprefix/\'
 ; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]]/Inputs/source-interleave-x86_64.c
 
+;; Only the path taken from the debug info is normalized. Separators inside the
+;; prefix are kept as spelled, so the '\' in 'my/pre\fix', which is an ordinary
+;; character here rather than a separator, is not rewritten to '/'.
+
+; RUN: llvm-objdump --prefix 'my/pre\fix' --source %t.o 2>&1 | \
+; RUN:   FileCheck %s -DFILE=%t.o -DPREFIX='my/pre\fix'
+
diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
index dce2328bd388e..aa8fd42c021a5 100644
--- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix-windows.test
@@ -15,3 +15,10 @@
 ;; because the path already starts with one.
 ; CHECK: warning: '[[FILE]]': failed to find source [[PREFIX]][[SEP]]Inputs[[SEP]]source-interleave-x86_64.c
 
+;; Only the path taken from the debug info is normalized. Separators inside the
+;; prefix are kept as spelled, even though both '/' and '\' are separators here,
+;; so 'my/pre\fix' is not rewritten to 'my\pre\fix'.
+
+; RUN: llvm-objdump --prefix 'my/pre\fix' --source %t.o 2>&1 | \
+; RUN:   FileCheck %s -DFILE=%t.o -DPREFIX='my/pre\fix' -DSEP=%{fs-sep}
+



More information about the llvm-commits mailing list