[llvm] [debug] Support 32-bit column number in DILocation (PR #201269)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 2 23:01:36 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-mc
Author: Cody Tapscott (topolarity)
<details>
<summary>Changes</summary>
This adds support for up to 32-bit column numbers in DILocation.
The downstream use case is in Julia, where we'd [like to use this](https://github.com/JuliaLang/julia/pull/61699) as a side channel to encode a PC-like index in DWARF, which works well except for this ~16-bit limitation.
DWARF supports this (`DW_LNS_set_column` takes a ULEB128) but CodeView does not, so in the case of overflow, I opted to drop the column number (similar to the existing `adjustColumn`) rather than the entire DILocation.
---
Full diff: https://github.com/llvm/llvm-project/pull/201269.diff
7 Files Affected:
- (modified) llvm/include/llvm/IR/DebugInfoMetadata.h (+5-6)
- (modified) llvm/include/llvm/MC/MCDwarf.h (+2-5)
- (modified) llvm/lib/AsmParser/LLParser.cpp (+1-1)
- (modified) llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (+12-5)
- (modified) llvm/lib/IR/DebugInfoMetadata.cpp (+5-18)
- (modified) llvm/lib/IR/LLVMContextImpl.h (+7-8)
- (modified) llvm/unittests/IR/MetadataTest.cpp (+15)
``````````diff
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 29d2de7a58884..9ea7b099b459a 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -2643,13 +2643,13 @@ class DISubprogram : public DILocalScope {
///
/// A debug location in source code, used for debug info and otherwise.
///
-/// Uses the SubclassData1, SubclassData16 and SubclassData32
-/// Metadata slots.
+/// Uses the SubclassData1 and SubclassData32 Metadata slots.
class DILocation : public MDNode {
friend class LLVMContextImpl;
friend class MDNode;
- uint64_t AtomGroup : 61;
+ uint64_t Column : 32;
+ uint64_t AtomGroup : 29;
uint64_t AtomRank : 3;
DILocation(LLVMContext &C, StorageType Storage, unsigned Line,
@@ -2710,7 +2710,7 @@ class DILocation : public MDNode {
TempDILocation clone() const { return cloneImpl(); }
unsigned getLine() const { return SubclassData32; }
- unsigned getColumn() const { return SubclassData16; }
+ unsigned getColumn() const { return Column; }
DILocalScope *getScope() const { return cast<DILocalScope>(getRawScope()); }
/// Return the linkage name of Subprogram. If the linkage name is empty,
@@ -2965,14 +2965,13 @@ class DILexicalBlock : public DILexicalBlockBase {
friend class LLVMContextImpl;
friend class MDNode;
- uint16_t Column;
+ uint32_t Column;
DILexicalBlock(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Column, ArrayRef<Metadata *> Ops)
: DILexicalBlockBase(C, DILexicalBlockKind, Storage, Ops),
Column(Column) {
SubclassData32 = Line;
- assert(Column < (1u << 16) && "Expected 16-bit column");
}
~DILexicalBlock() = default;
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 168eba59c11db..c7e12458192d0 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -107,7 +107,7 @@ struct MCDwarfFile {
class MCDwarfLoc {
uint32_t FileNum;
uint32_t Line;
- uint16_t Column;
+ uint32_t Column;
// Flags (see #define's below)
uint8_t Flags;
uint8_t Isa;
@@ -159,10 +159,7 @@ class MCDwarfLoc {
void setLine(unsigned line) { Line = line; }
/// Set the Column of this MCDwarfLoc.
- void setColumn(unsigned column) {
- assert(column <= UINT16_MAX);
- Column = column;
- }
+ void setColumn(unsigned column) { Column = column; }
/// Set the Flags of this MCDwarfLoc.
void setFlags(unsigned flags) {
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 44d81ad852688..d16bfe4a9b910 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -5000,7 +5000,7 @@ struct LineField : public MDUnsignedField {
};
struct ColumnField : public MDUnsignedField {
- ColumnField() : MDUnsignedField(0, UINT16_MAX) {}
+ ColumnField() : MDUnsignedField(0, UINT32_MAX) {}
};
struct DwarfTagField : public MDUnsignedField {
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index ccec0b5910658..d27ef852cda8f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -246,9 +246,15 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
.SiteFuncId;
Site->SiteFuncId = NextFuncId++;
+
+ // Set to unknown on overflow. We only have 16 bits to play with here.
+ unsigned IAColumn = InlinedAt->getColumn();
+ if (IAColumn > UINT16_MAX)
+ IAColumn = 0;
+
OS.emitCVInlineSiteIdDirective(
Site->SiteFuncId, ParentFuncId, maybeRecordFile(InlinedAt->getFile()),
- InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc());
+ InlinedAt->getLine(), IAColumn, SMLoc());
Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Inlinee);
auto InlineeIdx = getFuncIdForSubprogram(Inlinee);
@@ -523,9 +529,10 @@ void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL,
LI.isNeverStepInto())
return;
- ColumnInfo CI(DL.getCol(), /*EndColumn=*/0);
- if (CI.getStartColumn() != DL.getCol())
- return;
+ // Set to unknown on overflow. We only have 16 bits to play with here.
+ unsigned Column = DL.getCol();
+ if (Column > UINT16_MAX)
+ Column = 0;
if (!CurFn->HaveLineInfo)
CurFn->HaveLineInfo = true;
@@ -558,7 +565,7 @@ void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL,
addLocIfNotPresent(CurFn->ChildSites, Loc);
}
- OS.emitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(),
+ OS.emitCVLocDirective(FuncId, FileId, DL.getLine(), Column,
/*PrologueEnd=*/false, /*IsStmt=*/false,
DL->getFilename(), SMLoc());
}
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 79b7ce040b552..e553dcd45395a 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -61,37 +61,27 @@ DebugVariableAggregate::DebugVariableAggregate(const DbgVariableRecord *DVR)
DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Column, uint64_t AtomGroup, uint8_t AtomRank,
ArrayRef<Metadata *> MDs, bool ImplicitCode)
- : MDNode(C, DILocationKind, Storage, MDs), AtomGroup(AtomGroup),
- AtomRank(AtomRank) {
+ : MDNode(C, DILocationKind, Storage, MDs), Column(Column),
+ AtomGroup(AtomGroup), AtomRank(AtomRank) {
assert(AtomRank <= 7 && "AtomRank number should fit in 3 bits");
+ assert(AtomGroup < (1ULL << 29) && "AtomGroup number should fit in 29 bits");
if (AtomGroup)
C.updateDILocationAtomGroupWaterline(AtomGroup + 1);
assert((MDs.size() == 1 || MDs.size() == 2) &&
"Expected a scope and optional inlined-at");
- // Set line and column.
- assert(Column < (1u << 16) && "Expected 16-bit column");
-
+ // Set line. The column is stored in the dedicated 32-bit Column field via the
+ // member initializer above.
SubclassData32 = Line;
- SubclassData16 = Column;
setImplicitCode(ImplicitCode);
}
-static void adjustColumn(unsigned &Column) {
- // Set to unknown on overflow. We only have 16 bits to play with here.
- if (Column >= (1u << 16))
- Column = 0;
-}
-
DILocation *DILocation::getImpl(LLVMContext &Context, unsigned Line,
unsigned Column, Metadata *Scope,
Metadata *InlinedAt, bool ImplicitCode,
uint64_t AtomGroup, uint8_t AtomRank,
StorageType Storage, bool ShouldCreate) {
- // Fixup column.
- adjustColumn(Column);
-
if (Storage == Uniqued) {
if (auto *N = getUniqued(Context.pImpl->DILocations,
DILocationInfo::KeyTy(Line, Column, Scope,
@@ -1521,9 +1511,6 @@ DILexicalBlock *DILexicalBlock::getImpl(LLVMContext &Context, Metadata *Scope,
Metadata *File, unsigned Line,
unsigned Column, StorageType Storage,
bool ShouldCreate) {
- // Fixup column.
- adjustColumn(Column);
-
assert(Scope && "Expected scope");
DEFINE_GETIMPL_LOOKUP(DILexicalBlock, (Scope, File, Line, Column));
Metadata *Ops[] = {File, Scope};
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 57ff622b08813..a80c993f1bc29 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -297,13 +297,13 @@ template <> struct MDNodeKeyImpl<MDTuple> : MDNodeOpsKey {
template <> struct MDNodeKeyImpl<DILocation> {
Metadata *Scope;
Metadata *InlinedAt;
- uint64_t AtomGroup : 61;
+ uint64_t AtomGroup : 29;
uint64_t AtomRank : 3;
unsigned Line;
- uint16_t Column;
+ unsigned Column;
bool ImplicitCode;
- MDNodeKeyImpl(unsigned Line, uint16_t Column, Metadata *Scope,
+ MDNodeKeyImpl(unsigned Line, unsigned Column, Metadata *Scope,
Metadata *InlinedAt, bool ImplicitCode, uint64_t AtomGroup,
uint8_t AtomRank)
: Scope(Scope), InlinedAt(InlinedAt), AtomGroup(AtomGroup),
@@ -324,8 +324,7 @@ template <> struct MDNodeKeyImpl<DILocation> {
}
unsigned getHashValue() const {
- uint64_t LineColumnAndImplicitCode =
- Line | (uint64_t(Column) << 32) | (uint64_t(ImplicitCode) << 48);
+ uint64_t LineAndColumn = uint64_t(Line) | (uint64_t(Column) << 32);
// Hashing AtomGroup and AtomRank substantially impacts performance whether
// Key Instructions is enabled or not. We can't detect whether it's enabled
// here cheaply; avoiding hashing zero values is a good approximation. This
@@ -334,9 +333,9 @@ template <> struct MDNodeKeyImpl<DILocation> {
// outweighed by the overall compile time savings by performing this check.
// * (hash_combine(x) != hash_combine(x, 0))
if (AtomGroup || AtomRank)
- return hash_combine(LineColumnAndImplicitCode, Scope, InlinedAt,
- AtomGroup | (uint64_t(AtomRank) << 61));
- return hash_combine(LineColumnAndImplicitCode, Scope, InlinedAt);
+ return hash_combine(LineAndColumn, ImplicitCode, Scope, InlinedAt,
+ AtomGroup | (uint64_t(AtomRank) << 29));
+ return hash_combine(LineAndColumn, ImplicitCode, Scope, InlinedAt);
}
};
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 7222c885548e0..d0a35720d99a0 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -1627,6 +1627,21 @@ TEST_F(DILocationTest, getDistinct) {
EXPECT_EQ(L1, DILocation::get(Context, 2, 7, N));
}
+TEST_F(DILocationTest, WideColumn) {
+ MDNode *N = getSubprogram();
+ // Column numbers wider than 16 bits are preserved (up to 32 bits) rather
+ // than being clamped to zero.
+ DILocation *L = DILocation::get(Context, 2, 0x10000, N);
+ EXPECT_EQ(0x10000u, L->getColumn());
+
+ DILocation *Max = DILocation::get(Context, 2, UINT32_MAX, N);
+ EXPECT_EQ(UINT32_MAX, Max->getColumn());
+
+ // Distinct columns produce distinct (and uniqued) nodes.
+ EXPECT_EQ(L, DILocation::get(Context, 2, 0x10000, N));
+ EXPECT_NE(L, Max);
+}
+
TEST_F(DILocationTest, getTemporary) {
MDNode *N = MDNode::get(Context, {});
auto L = DILocation::getTemporary(Context, 2, 7, N);
``````````
</details>
https://github.com/llvm/llvm-project/pull/201269
More information about the llvm-commits
mailing list