[llvm-branch-commits] [llvm-mc] Add --show-source-loc option to emit source locations (PR #199298)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri May 22 16:20:36 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-mc
Author: Alexander Richardson (arichardson)
<details>
<summary>Changes</summary>
This adds a new --show-source-loc flag (and -asm-show-source-loc
MCTargetOption) to llvm-mc, which emits source location comments
(`# <SourceLoc: filename:line:col>`).
When instructions originate from macro expansions, llvm-mc unwinds the
instantiation stack, emitting intermediate expansion layers as
`# <MacroLoc: filename:line:col>` and reporting the top-level
macro invocation in `SourceLoc`. For .include directives, it also emits
`# <IncludeLoc: filename:line:col>` to report the include stack.
The main motivation for this feature is improving
update_mc_test_checks.py to cleanly map output instructions back to
input lines, enabling automated test updates for assembly files that
include directives like .ifdef or macros.
Assisted-By: Gemini
---
Full diff: https://github.com/llvm/llvm-project/pull/199298.diff
12 Files Affected:
- (modified) llvm/include/llvm/MC/MCTargetOptions.h (+1)
- (modified) llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h (+1)
- (modified) llvm/include/llvm/Support/SourceMgr.h (+1-1)
- (modified) llvm/lib/MC/MCAsmStreamer.cpp (+38)
- (modified) llvm/lib/MC/MCTargetOptions.cpp (+3-3)
- (modified) llvm/lib/MC/MCTargetOptionsCommandFlags.cpp (+7)
- (modified) llvm/lib/Support/SourceMgr.cpp (+1-1)
- (added) llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc (+5)
- (added) llvm/test/tools/llvm-mc/disassemble-show-source-loc.s (+9)
- (added) llvm/test/tools/llvm-mc/show-source-loc.s (+52)
- (modified) llvm/tools/llvm-mc/Disassembler.cpp (+1)
- (modified) llvm/tools/llvm-mc/llvm-mc.cpp (+6)
``````````diff
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 2f24608b5f6ba..52ae464a8b91d 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -52,6 +52,7 @@ class MCTargetOptions {
bool FDPIC : 1;
bool ShowMCEncoding : 1;
bool ShowMCInst : 1;
+ bool ShowMCInstSourceLoc : 1;
bool AsmVerbose : 1;
/// Preserve Comments in Assembly.
diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index ae80887900349..b9ddeeec4f537 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -45,6 +45,7 @@ LLVM_ABI bool getEmitCompactUnwindNonCanonical();
LLVM_ABI bool getEmitSFrameUnwind();
LLVM_ABI bool getShowMCInst();
+LLVM_ABI bool getShowMCInstSourceLoc();
LLVM_ABI bool getFatalWarnings();
diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 83cb3de26453a..6157213c4b870 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -263,7 +263,7 @@ class SourceMgr {
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
/// This will return a null SMLoc if the line/column location is invalid.
LLVM_ABI SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
- unsigned ColNo);
+ unsigned ColNo) const;
/// Emit a message about the specified location with the specified string.
///
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 05e3dc28a502b..c279dab35d0a5 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
#include <algorithm>
#include <optional>
@@ -60,6 +61,7 @@ class MCAsmStreamer final : public MCAsmBaseStreamer {
bool IsVerboseAsm = false;
bool ShowInst = false;
+ bool ShowInstSourceLoc = false;
bool UseDwarfDirectory = false;
void EmitRegisterName(int64_t Register);
@@ -107,6 +109,7 @@ class MCAsmStreamer final : public MCAsmBaseStreamer {
if (IsVerboseAsm)
InstPrinter->setCommentStream(CommentStream);
ShowInst = TO.ShowMCInst;
+ ShowInstSourceLoc = TO.ShowMCInstSourceLoc;
switch (TO.MCUseDwarfDirectory) {
case MCTargetOptions::DisableDwarfDirectory:
UseDwarfDirectory = false;
@@ -2624,6 +2627,41 @@ void MCAsmStreamer::emitInstruction(const MCInst &Inst,
getCommentOS() << "\n";
EmitEOL();
+
+ if (ShowInstSourceLoc && Inst.getLoc().isValid()) {
+ if (const SourceMgr *SM = getContext().getSourceManager()) {
+ SMLoc Loc = Inst.getLoc();
+ unsigned BufID = SM->FindBufferContainingLoc(Loc);
+ bool PrintedSourceLoc = false;
+
+ auto PrintLoc = [&](StringRef Type, SMLoc L, unsigned Buf) {
+ StringRef Filename = SM->getMemoryBuffer(Buf)->getBufferIdentifier();
+ std::pair<unsigned, unsigned> LineCol = SM->getLineAndColumn(L, Buf);
+ OS << MAI->getCommentString() << " <" << Type << ": " << Filename
+ << ":" << LineCol.first << ":" << LineCol.second << ">\n";
+ };
+
+ // Unwind the macro expansion and inclusion stacks.
+ while (BufID) {
+ SMLoc ParentLoc = SM->getParentIncludeLoc(BufID);
+ if (SMLoc DefLoc = SM->getMacroDefLoc(BufID); DefLoc.isValid()) {
+ PrintLoc("MacroLoc", DefLoc, SM->FindBufferContainingLoc(DefLoc));
+ } else {
+ // First location is the SourceLoc, all others are include stack
+ if (!PrintedSourceLoc) {
+ PrintLoc("SourceLoc", Loc, BufID);
+ PrintedSourceLoc = true;
+ } else {
+ PrintLoc("IncludeLoc", Loc, BufID);
+ }
+ }
+ // Move up to the parent context (the macro call site or the include site)
+ // for the next iteration of the stack unwinding.
+ Loc = ParentLoc;
+ BufID = Loc.isValid() ? SM->FindBufferContainingLoc(Loc) : 0;
+ }
+ }
+ }
}
void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index be6d19d111620..daf7ccece36c7 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -15,9 +15,9 @@ MCTargetOptions::MCTargetOptions()
: MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false),
MCNoWarn(false), MCNoDeprecatedWarn(false), MCNoTypeCheck(false),
MCSaveTempLabels(false), MCIncrementalLinkerCompatible(false),
- FDPIC(false), ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false),
- PreserveAsmComments(true), Dwarf64(false),
- EmitDwarfUnwind(EmitDwarfUnwindType::Default),
+ FDPIC(false), ShowMCEncoding(false), ShowMCInst(false),
+ ShowMCInstSourceLoc(false), AsmVerbose(false), PreserveAsmComments(true),
+ Dwarf64(false), EmitDwarfUnwind(EmitDwarfUnwindType::Default),
MCUseDwarfDirectory(DefaultDwarfDirectory),
EmitCompactUnwindNonCanonical(false), EmitSFrameUnwind(false),
PPCUseFullRegisterNames(false) {}
diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 359c1bceb25b1..a80af06837b06 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -50,6 +50,7 @@ MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind)
MCOPT(bool, EmitCompactUnwindNonCanonical)
MCOPT(bool, EmitSFrameUnwind)
MCOPT(bool, ShowMCInst)
+MCOPT(bool, ShowMCInstSourceLoc)
MCOPT(bool, FatalWarnings)
MCOPT(bool, NoWarn)
MCOPT(bool, NoDeprecatedWarn)
@@ -124,6 +125,11 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
cl::desc("Emit internal instruction representation to assembly file"));
MCBINDOPT(ShowMCInst);
+ static cl::opt<bool> ShowMCInstSourceLoc(
+ "asm-show-source-loc",
+ cl::desc("Emit source locations of instructions to assembly file"));
+ MCBINDOPT(ShowMCInstSourceLoc);
+
static cl::opt<bool> FatalWarnings("fatal-warnings",
cl::desc("Treat warnings as errors"));
MCBINDOPT(FatalWarnings);
@@ -203,6 +209,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
Options.Dwarf64 = getDwarf64();
Options.DwarfVersion = getDwarfVersion();
Options.ShowMCInst = getShowMCInst();
+ Options.ShowMCInstSourceLoc = getShowMCInstSourceLoc();
Options.ABIName = getABIName();
Options.MCFatalWarnings = getFatalWarnings();
Options.MCNoWarn = getNoWarn();
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 62fce28486d4a..66cee9ac28f03 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -259,7 +259,7 @@ std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc,
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
/// This will return a null SMLoc if the line/column location is invalid.
SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
- unsigned ColNo) {
+ unsigned ColNo) const {
auto &SB = getBufferInfo(BufferID);
const char *Ptr = SB.getPointerForLineNumber(LineNo);
if (!Ptr)
diff --git a/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc b/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc
new file mode 100644
index 0000000000000..58e7a9628156d
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc
@@ -0,0 +1,5 @@
+xorl %ecx, %ecx
+
+.macro inc_macro reg
+ incl \reg
+.endm
diff --git a/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s b/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s
new file mode 100644
index 0000000000000..31c9fc8a5bd59
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s
@@ -0,0 +1,9 @@
+# RUN: llvm-mc -triple=x86_64 -disassemble -show-source-loc %s | FileCheck %s
+
+# CHECK: nop
+# CHECK-NEXT: # <SourceLoc: {{.*}}disassemble-show-source-loc.s:5:1>
+0x90
+
+# CHECK: xorl %ecx, %ecx
+# CHECK-NEXT: # <SourceLoc: {{.*}}disassemble-show-source-loc.s:9:1>
+0x31 0xc9
diff --git a/llvm/test/tools/llvm-mc/show-source-loc.s b/llvm/test/tools/llvm-mc/show-source-loc.s
new file mode 100644
index 0000000000000..1fe06f2b87ed6
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/show-source-loc.s
@@ -0,0 +1,52 @@
+# RUN: llvm-mc -triple=x86_64 -show-source-loc %s -I %S/Inputs
+# RUN: llvm-mc -triple=x86_64 -show-source-loc %s -I %S/Inputs | FileCheck %s
+
+## Check that -show-source-loc emits <SourceLoc: ...> comments after instructions.
+
+.macro inner_macro reg1, reg2
+ addl \reg1, \reg2
+ subl \reg2, \reg1
+.endm
+
+.macro outer_macro r1, r2
+ inner_macro \r1, \r2
+.endm
+
+## Standard instructions report their exact line number.
+nop
+# CHECK: nop
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-2]]:1>
+
+## Nested macro expansion reports the full expansion stack.
+outer_macro %eax, %ebx
+# CHECK: addl %eax, %ebx
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:6:1>
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:11:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-4]]:1>
+# CHECK: subl %ebx, %eax
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:6:1>
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:11:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-8]]:1>
+
+## .include reports the include file location and the .include directive location.
+.include "show-source-loc.inc"
+# CHECK: xorl %ecx, %ecx
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.inc:1:1>
+# CHECK-NEXT: # <IncludeLoc: {{.*}}show-source-loc.s:[[#@LINE-3]]:31>
+
+## Macro defined in an include file.
+inc_macro %edx
+# CHECK: incl %edx
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.inc:3:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-3]]:1>
+
+## Indefinite repeat block (.irp).
+.irp reg, %esi, %edi
+ incl \reg
+.endr
+# CHECK: incl %esi
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:44:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-5]]:1>
+# CHECK: incl %edi
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:44:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-8]]:1>
diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp
index 9a61f68b12d31..55ab78ddefe42 100644
--- a/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/llvm/tools/llvm-mc/Disassembler.cpp
@@ -77,6 +77,7 @@ static bool printInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
[[fallthrough]];
case MCDisassembler::Success:
+ Inst.setLoc(SMLoc::getFromPointer(Bytes.second[Index]));
Streamer.emitInstruction(Inst, STI);
break;
}
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 903f82e6855ba..afbd861b91b81 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -86,6 +86,11 @@ static cl::opt<bool>
ShowInst("show-inst", cl::desc("Show internal instruction representation"),
cl::cat(MCCategory));
+static cl::opt<bool>
+ ShowSourceLoc("show-source-loc",
+ cl::desc("Show source location of instructions"),
+ cl::cat(MCCategory));
+
static cl::opt<bool>
ShowInstOperands("show-inst-operands",
cl::desc("Show instructions operands as parsed"),
@@ -409,6 +414,7 @@ int main(int argc, char **argv) {
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
MCOptions.CompressDebugSections = CompressDebugSections.getValue();
MCOptions.ShowMCInst = ShowInst;
+ MCOptions.ShowMCInstSourceLoc = ShowSourceLoc;
MCOptions.AsmVerbose = true;
MCOptions.MCNoExecStack = NoExecStack;
MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;
``````````
</details>
https://github.com/llvm/llvm-project/pull/199298
More information about the llvm-branch-commits
mailing list