[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