Add new llvm.dbg.declare_value intrinsic. (#168132)
For swift async code, we need to use a debug intrinsic that behaves like an llvm.dbg.declare but can take any location type rather than just a pointer or integer. To solve this, a new debug instrinsic called llvm.dbg.declare_value has been created, which behaves exactly like an llvm.dbg.declare but can take non pointer and integer location types. More information here: https://discourse.llvm.org/t/rfc-introduce-new-llvm-dbg-coroframe-entry-intrinsic/88269 This is the first patch as part of a stack of patches, with the one succeeding it being: https://github.com/llvm/llvm-project/pull/168134
This commit is contained in:
parent
ad7a5d4e05
commit
20ebc7ea82
@ -308,6 +308,28 @@ directly, not its address. Note that the value operand of this intrinsic may
|
||||
be indirect (i.e, a pointer to the source variable), provided that interpreting
|
||||
the complex expression derives the direct value.
|
||||
|
||||
|
||||
``#dbg_declare_value``
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
#dbg_declare_value([Value|MDNode], DILocalVariable, DIExpression, DILocation)
|
||||
|
||||
This record provides information about a local element (e.g., variable). The
|
||||
first argument is used to compute the value of the variable throughout the
|
||||
entire function. The second argument is a
|
||||
:ref:`local variable <dilocalvariable>` containing a description of the
|
||||
variable. The third argument is a :ref:`complex expression <diexpression>`. The
|
||||
foruth argument is a :ref:`source location <dilocation>`. A
|
||||
``#dbg_declare_value`` record describes describes the *value* of a source
|
||||
variable directly, not its address. The difference between a ``#dbg_value`` and
|
||||
a ``#dbg_declare_value`` is that, just like a ``#dbg_declare``, a frontend
|
||||
should generate exactly one ``#dbg_declare_value`` record. The idea is to have
|
||||
``#dbg_declare`` guarantees but be able to describe a value rather than the
|
||||
address of a value.
|
||||
|
||||
|
||||
``#dbg_assign``
|
||||
^^^^^^^^^^^^^^^
|
||||
.. toctree::
|
||||
|
||||
@ -688,6 +688,8 @@ enum FunctionCodes {
|
||||
FUNC_CODE_DEBUG_RECORD_VALUE_SIMPLE =
|
||||
64, // [DILocation, DILocalVariable, DIExpression, Value]
|
||||
FUNC_CODE_DEBUG_RECORD_LABEL = 65, // [DILocation, DILabel]
|
||||
FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE =
|
||||
66, // [DILocation, DILocalVariable, DIExpression, ValueAsMetadata]
|
||||
};
|
||||
|
||||
enum UseListCodes {
|
||||
|
||||
@ -1156,6 +1156,18 @@ namespace llvm {
|
||||
DIExpression *Expr, const DILocation *DL,
|
||||
InsertPosition InsertPt);
|
||||
|
||||
/// Insert a new llvm.dbg.declare_value intrinsic call.
|
||||
/// \param Storage llvm::Value of the variable
|
||||
/// \param VarInfo Variable's debug info descriptor.
|
||||
/// \param Expr A complex location expression.
|
||||
/// \param DL Debug info location.
|
||||
/// \param InsertPt Location for the new intrinsic.
|
||||
LLVM_ABI DbgInstPtr insertDeclareValue(llvm::Value *Storage,
|
||||
DILocalVariable *VarInfo,
|
||||
DIExpression *Expr,
|
||||
const DILocation *DL,
|
||||
InsertPosition InsertPt);
|
||||
|
||||
/// Insert a new llvm.dbg.label intrinsic call.
|
||||
/// \param LabelInfo Label's debug info descriptor.
|
||||
/// \param DL Debug info location.
|
||||
|
||||
@ -44,6 +44,8 @@ class Module;
|
||||
LLVM_ABI TinyPtrVector<DbgVariableRecord *> findDVRDeclares(Value *V);
|
||||
/// As above, for DVRValues.
|
||||
LLVM_ABI TinyPtrVector<DbgVariableRecord *> findDVRValues(Value *V);
|
||||
/// As above, for DVRDeclareValues.
|
||||
LLVM_ABI TinyPtrVector<DbgVariableRecord *> findDVRDeclareValues(Value *V);
|
||||
|
||||
/// Finds the debug info records describing a value.
|
||||
LLVM_ABI void
|
||||
|
||||
@ -282,6 +282,7 @@ public:
|
||||
Declare,
|
||||
Value,
|
||||
Assign,
|
||||
DeclareValue,
|
||||
|
||||
End, ///< Marks the end of the concrete types.
|
||||
Any, ///< To indicate all LocationTypes in searches.
|
||||
@ -364,6 +365,13 @@ public:
|
||||
createDVRDeclare(Value *Address, DILocalVariable *DV, DIExpression *Expr,
|
||||
const DILocation *DI, DbgVariableRecord &InsertBefore);
|
||||
|
||||
LLVM_ABI static DbgVariableRecord *
|
||||
createDVRDeclareValue(Value *Address, DILocalVariable *DV, DIExpression *Expr,
|
||||
const DILocation *DI);
|
||||
LLVM_ABI static DbgVariableRecord *
|
||||
createDVRDeclareValue(Value *Address, DILocalVariable *DV, DIExpression *Expr,
|
||||
const DILocation *DI, DbgVariableRecord &InsertBefore);
|
||||
|
||||
/// Iterator for ValueAsMetadata that internally uses direct pointer iteration
|
||||
/// over either a ValueAsMetadata* or a ValueAsMetadata**, dereferencing to the
|
||||
/// ValueAsMetadata .
|
||||
@ -414,6 +422,7 @@ public:
|
||||
|
||||
bool isDbgDeclare() const { return Type == LocationType::Declare; }
|
||||
bool isDbgValue() const { return Type == LocationType::Value; }
|
||||
bool isDbgDeclareValue() const { return Type == LocationType::DeclareValue; }
|
||||
|
||||
/// Get the locations corresponding to the variable referenced by the debug
|
||||
/// info intrinsic. Depending on the intrinsic, this could be the
|
||||
@ -439,12 +448,16 @@ public:
|
||||
bool hasValidLocation() const { return getVariableLocationOp(0) != nullptr; }
|
||||
|
||||
/// Does this describe the address of a local variable. True for dbg.addr
|
||||
/// and dbg.declare, but not dbg.value, which describes its value.
|
||||
/// and dbg.declare, but not dbg.value or dbg.declare_value, which describes
|
||||
/// its value.
|
||||
bool isAddressOfVariable() const { return Type == LocationType::Declare; }
|
||||
|
||||
/// Determine if this describes the value of a local variable. It is false for
|
||||
/// dbg.declare, but true for dbg.value, which describes its value.
|
||||
bool isValueOfVariable() const { return Type == LocationType::Value; }
|
||||
/// dbg.declare, but true for dbg.value and dbg.declare_value, which describes
|
||||
/// its value.
|
||||
bool isValueOfVariable() const {
|
||||
return Type == LocationType::Value || Type == LocationType::DeclareValue;
|
||||
}
|
||||
|
||||
LocationType getType() const { return Type; }
|
||||
|
||||
|
||||
@ -1007,6 +1007,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
DBGRECORDTYPEKEYWORD(declare);
|
||||
DBGRECORDTYPEKEYWORD(assign);
|
||||
DBGRECORDTYPEKEYWORD(label);
|
||||
DBGRECORDTYPEKEYWORD(declare_value);
|
||||
#undef DBGRECORDTYPEKEYWORD
|
||||
|
||||
if (Keyword.starts_with("DIFlag")) {
|
||||
|
||||
@ -7155,7 +7155,8 @@ bool LLParser::parseDebugRecord(DbgRecord *&DR, PerFunctionState &PFS) {
|
||||
.Case("declare", RecordKind::ValueKind)
|
||||
.Case("value", RecordKind::ValueKind)
|
||||
.Case("assign", RecordKind::ValueKind)
|
||||
.Case("label", RecordKind::LabelKind);
|
||||
.Case("label", RecordKind::LabelKind)
|
||||
.Case("declare_value", RecordKind::ValueKind);
|
||||
|
||||
// Parsing labels is trivial; parse here and early exit, otherwise go into the
|
||||
// full DbgVariableRecord processing stage.
|
||||
@ -7180,7 +7181,8 @@ bool LLParser::parseDebugRecord(DbgRecord *&DR, PerFunctionState &PFS) {
|
||||
LocType ValueType = StringSwitch<LocType>(Lex.getStrVal())
|
||||
.Case("declare", LocType::Declare)
|
||||
.Case("value", LocType::Value)
|
||||
.Case("assign", LocType::Assign);
|
||||
.Case("assign", LocType::Assign)
|
||||
.Case("declare_value", LocType::DeclareValue);
|
||||
|
||||
Lex.Lex();
|
||||
if (parseToken(lltok::lparen, "Expected '(' here"))
|
||||
|
||||
@ -272,6 +272,7 @@ GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_CALLBR)
|
||||
STRINGIFY_CODE(FUNC_CODE, BLOCKADDR_USERS)
|
||||
STRINGIFY_CODE(FUNC_CODE, DEBUG_RECORD_DECLARE)
|
||||
STRINGIFY_CODE(FUNC_CODE, DEBUG_RECORD_DECLARE_VALUE)
|
||||
STRINGIFY_CODE(FUNC_CODE, DEBUG_RECORD_VALUE)
|
||||
STRINGIFY_CODE(FUNC_CODE, DEBUG_RECORD_ASSIGN)
|
||||
STRINGIFY_CODE(FUNC_CODE, DEBUG_RECORD_VALUE_SIMPLE)
|
||||
|
||||
@ -6655,6 +6655,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_VALUE_SIMPLE:
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_VALUE:
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_DECLARE:
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE:
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_ASSIGN: {
|
||||
// DbgVariableRecords are placed after the Instructions that they are
|
||||
// attached to.
|
||||
@ -6671,6 +6672,8 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
// ..., Value
|
||||
// dbg_declare (FUNC_CODE_DEBUG_RECORD_DECLARE)
|
||||
// ..., LocationMetadata
|
||||
// dbg_declare_value (FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE)
|
||||
// ..., LocationMetadata
|
||||
// dbg_assign (FUNC_CODE_DEBUG_RECORD_ASSIGN)
|
||||
// ..., LocationMetadata, DIAssignID, DIExpression, LocationMetadata
|
||||
unsigned Slot = 0;
|
||||
@ -6712,6 +6715,11 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
DVR = new DbgVariableRecord(RawLocation, Var, Expr, DIL,
|
||||
DbgVariableRecord::LocationType::Declare);
|
||||
break;
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE:
|
||||
DVR = new DbgVariableRecord(
|
||||
RawLocation, Var, Expr, DIL,
|
||||
DbgVariableRecord::LocationType::DeclareValue);
|
||||
break;
|
||||
case bitc::FUNC_CODE_DEBUG_RECORD_ASSIGN: {
|
||||
DIAssignID *ID = cast<DIAssignID>(getFnMetadataByID(Record[Slot++]));
|
||||
DIExpression *AddrExpr =
|
||||
|
||||
@ -3844,6 +3844,9 @@ void ModuleBitcodeWriter::writeFunction(
|
||||
} else if (DVR.isDbgDeclare()) {
|
||||
Vals.push_back(VE.getMetadataID(DVR.getRawLocation()));
|
||||
Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_RECORD_DECLARE, Vals);
|
||||
} else if (DVR.isDbgDeclareValue()) {
|
||||
Vals.push_back(VE.getMetadataID(DVR.getRawLocation()));
|
||||
Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE, Vals);
|
||||
} else {
|
||||
assert(DVR.isDbgAssign() && "Unexpected DbgRecord kind");
|
||||
Vals.push_back(VE.getMetadataID(DVR.getRawLocation()));
|
||||
|
||||
@ -4864,6 +4864,9 @@ void AssemblyWriter::printDbgVariableRecord(const DbgVariableRecord &DVR) {
|
||||
case DbgVariableRecord::LocationType::Declare:
|
||||
Out << "declare";
|
||||
break;
|
||||
case DbgVariableRecord::LocationType::DeclareValue:
|
||||
Out << "declare_value";
|
||||
break;
|
||||
case DbgVariableRecord::LocationType::Assign:
|
||||
Out << "assign";
|
||||
break;
|
||||
|
||||
@ -1147,6 +1147,24 @@ DbgInstPtr DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
|
||||
return DVR;
|
||||
}
|
||||
|
||||
DbgInstPtr DIBuilder::insertDeclareValue(Value *Storage,
|
||||
DILocalVariable *VarInfo,
|
||||
DIExpression *Expr,
|
||||
const DILocation *DL,
|
||||
InsertPosition InsertPt) {
|
||||
assert(VarInfo &&
|
||||
"empty or invalid DILocalVariable* passed to dbg.declare_value");
|
||||
assert(DL && "Expected debug loc");
|
||||
assert(DL->getScope()->getSubprogram() ==
|
||||
VarInfo->getScope()->getSubprogram() &&
|
||||
"Expected matching subprograms");
|
||||
|
||||
DbgVariableRecord *DVR =
|
||||
DbgVariableRecord::createDVRDeclareValue(Storage, VarInfo, Expr, DL);
|
||||
insertDbgVariableRecord(DVR, InsertPt);
|
||||
return DVR;
|
||||
}
|
||||
|
||||
void DIBuilder::insertDbgVariableRecord(DbgVariableRecord *DVR,
|
||||
InsertPosition InsertPt) {
|
||||
assert(InsertPt.isValid());
|
||||
|
||||
@ -62,6 +62,23 @@ TinyPtrVector<DbgVariableRecord *> llvm::findDVRDeclares(Value *V) {
|
||||
return Declares;
|
||||
}
|
||||
|
||||
TinyPtrVector<DbgVariableRecord *> llvm::findDVRDeclareValues(Value *V) {
|
||||
// This function is hot. Check whether the value has any metadata to avoid a
|
||||
// DenseMap lookup. This check is a bitfield datamember lookup.
|
||||
if (!V->isUsedByMetadata())
|
||||
return {};
|
||||
auto *L = ValueAsMetadata::getIfExists(V);
|
||||
if (!L)
|
||||
return {};
|
||||
|
||||
TinyPtrVector<DbgVariableRecord *> DEclareValues;
|
||||
for (DbgVariableRecord *DVR : L->getAllDbgVariableRecordUsers())
|
||||
if (DVR->getType() == DbgVariableRecord::LocationType::DeclareValue)
|
||||
DEclareValues.push_back(DVR);
|
||||
|
||||
return DEclareValues;
|
||||
}
|
||||
|
||||
TinyPtrVector<DbgVariableRecord *> llvm::findDVRValues(Value *V) {
|
||||
// This function is hot. Check whether the value has any metadata to avoid a
|
||||
// DenseMap lookup. This check is a bitfield datamember lookup.
|
||||
|
||||
@ -211,6 +211,22 @@ DbgVariableRecord::createDVRDeclare(Value *Address, DILocalVariable *DV,
|
||||
return NewDVRDeclare;
|
||||
}
|
||||
|
||||
DbgVariableRecord *
|
||||
DbgVariableRecord::createDVRDeclareValue(Value *Address, DILocalVariable *DV,
|
||||
DIExpression *Expr,
|
||||
const DILocation *DI) {
|
||||
return new DbgVariableRecord(ValueAsMetadata::get(Address), DV, Expr, DI,
|
||||
LocationType::DeclareValue);
|
||||
}
|
||||
|
||||
DbgVariableRecord *DbgVariableRecord::createDVRDeclareValue(
|
||||
Value *Address, DILocalVariable *DV, DIExpression *Expr,
|
||||
const DILocation *DI, DbgVariableRecord &InsertBefore) {
|
||||
auto *NewDVRCoro = createDVRDeclareValue(Address, DV, Expr, DI);
|
||||
NewDVRCoro->insertBefore(&InsertBefore);
|
||||
return NewDVRCoro;
|
||||
}
|
||||
|
||||
DbgVariableRecord *DbgVariableRecord::createDVRAssign(
|
||||
Value *Val, DILocalVariable *Variable, DIExpression *Expression,
|
||||
DIAssignID *AssignID, Value *Address, DIExpression *AddressExpression,
|
||||
@ -427,6 +443,10 @@ DbgVariableRecord::createDebugIntrinsic(Module *M,
|
||||
case DbgVariableRecord::LocationType::End:
|
||||
case DbgVariableRecord::LocationType::Any:
|
||||
llvm_unreachable("Invalid LocationType");
|
||||
break;
|
||||
case DbgVariableRecord::LocationType::DeclareValue:
|
||||
llvm_unreachable(
|
||||
"#dbg_declare_value should never be converted to an intrinsic");
|
||||
}
|
||||
|
||||
// Create the intrinsic from this DbgVariableRecord's information, optionally
|
||||
|
||||
@ -190,6 +190,9 @@ private:
|
||||
case DbgVariableRecord::LocationType::Declare:
|
||||
*OS << "declare";
|
||||
break;
|
||||
case DbgVariableRecord::LocationType::DeclareValue:
|
||||
*OS << "declare_value";
|
||||
break;
|
||||
case DbgVariableRecord::LocationType::Assign:
|
||||
*OS << "assign";
|
||||
break;
|
||||
@ -7083,6 +7086,7 @@ void Verifier::visit(DbgVariableRecord &DVR) {
|
||||
|
||||
CheckDI(DVR.getType() == DbgVariableRecord::LocationType::Value ||
|
||||
DVR.getType() == DbgVariableRecord::LocationType::Declare ||
|
||||
DVR.getType() == DbgVariableRecord::LocationType::DeclareValue ||
|
||||
DVR.getType() == DbgVariableRecord::LocationType::Assign,
|
||||
"invalid #dbg record type", &DVR, DVR.getType(), BB, F);
|
||||
|
||||
|
||||
37
llvm/test/Assembler/dbg_declare_value.ll
Normal file
37
llvm/test/Assembler/dbg_declare_value.ll
Normal file
@ -0,0 +1,37 @@
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
|
||||
; CHECK: #dbg_declare_value(double %{{[0-9]+}}, !{{[0-9]+}}, !DIExpression(), !{{[0-9]+}})
|
||||
|
||||
; ModuleID = '/tmp/test.c'
|
||||
source_filename = "/tmp/test.c"
|
||||
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
|
||||
target triple = "arm64-apple-macosx26.0.0"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
|
||||
define void @foo(double noundef %0) #0 !dbg !9 {
|
||||
#dbg_declare_value(double %0, !15, !DIExpression(), !16)
|
||||
ret void, !dbg !21
|
||||
}
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
|
||||
!llvm.ident = !{!8}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (git@github.com:rastogishubham/llvm-project.git bacf99969b2f3e6db4cfcf536cce8b01ffd20aa0)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
|
||||
!1 = !DIFile(filename: "/tmp/test.c", directory: "/Users/srastogi/Development/llvm-project-2/build_ninja", checksumkind: CSK_MD5, checksum: "fa15cf45ed4f9d805aab17eb7856a442")
|
||||
!2 = !{i32 7, !"Dwarf Version", i32 5}
|
||||
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!4 = !{i32 1, !"wchar_size", i32 4}
|
||||
!5 = !{i32 8, !"PIC Level", i32 2}
|
||||
!6 = !{i32 7, !"uwtable", i32 1}
|
||||
!7 = !{i32 7, !"frame-pointer", i32 4}
|
||||
!8 = !{!"clang version 22.0.0git (git@github.com:rastogishubham/llvm-project.git bacf99969b2f3e6db4cfcf536cce8b01ffd20aa0)"}
|
||||
!9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
|
||||
!10 = !DIFile(filename: "/tmp/test.c", directory: "", checksumkind: CSK_MD5, checksum: "fa15cf45ed4f9d805aab17eb7856a442")
|
||||
!11 = !DISubroutineType(types: !12)
|
||||
!12 = !{null, !13}
|
||||
!13 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
|
||||
!14 = !{}
|
||||
!15 = !DILocalVariable(name: "x", arg: 1, scope: !9, file: !10, line: 1, type: !13)
|
||||
!16 = !DILocation(line: 1, column: 17, scope: !9)
|
||||
!21 = !DILocation(line: 3, column: 1, scope: !9)
|
||||
Loading…
x
Reference in New Issue
Block a user