Skip to content

Commit 31127b9

Browse files
authored
[mlir][llvm] Handle debug record import edge cases (#168774)
This commit enables the direct import of debug records by default and fixes issues with two edge cases: - Detect early on if the address operand is an argument list (calling getAddress() for argument lists asserts) - Use getAddress() to check if the address operand is null, which means the address operand is an empty metadata node, which currently is not supported. - Add support for debug label records. This is a follow-up to: #167812
1 parent ea9ec7c commit 31127b9

File tree

4 files changed

+97
-58
lines changed

4 files changed

+97
-58
lines changed

mlir/include/mlir/Target/LLVMIR/ModuleImport.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,9 @@ class ModuleImport {
282282
/// after the function conversion has finished.
283283
void addDebugIntrinsic(llvm::CallInst *intrinsic);
284284

285-
/// Similar to `addDebugIntrinsic`, but for debug records.
286-
void addDebugRecord(llvm::DbgRecord *debugRecord);
285+
/// Adds a debug record to the list of debug records that need to be imported
286+
/// after the function conversion has finished.
287+
void addDebugRecord(llvm::DbgVariableRecord *dbgRecord);
287288

288289
/// Converts the LLVM values for an intrinsic to mixed MLIR values and
289290
/// attributes for LLVM_IntrOpBase. Attributes correspond to LLVM immargs. The
@@ -343,22 +344,22 @@ class ModuleImport {
343344
/// Converts all debug intrinsics in `debugIntrinsics`. Assumes that the
344345
/// function containing the intrinsics has been fully converted to MLIR.
345346
LogicalResult processDebugIntrinsics();
346-
/// Converts all debug records in `debugRecords`. Assumes that the
347+
/// Converts all debug records in `dbgRecords`. Assumes that the
347348
/// function containing the record has been fully converted to MLIR.
348349
LogicalResult processDebugRecords();
349350
/// Converts a single debug intrinsic.
350351
LogicalResult processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
351352
DominanceInfo &domInfo);
352353
/// Converts a single debug record.
353-
LogicalResult processDebugRecord(llvm::DbgRecord &debugRecord,
354+
LogicalResult processDebugRecord(llvm::DbgVariableRecord &dbgRecord,
354355
DominanceInfo &domInfo);
355356
/// Process arguments for declare/value operation insertion. `localVarAttr`
356357
/// and `localExprAttr` are the attained attributes after importing the debug
357358
/// variable and expressions. This also sets the builder insertion point to be
358359
/// used by these operations.
359360
std::tuple<DILocalVariableAttr, DIExpressionAttr, Value>
360361
processDebugOpArgumentsAndInsertionPt(
361-
Location loc, bool hasArgList, bool isKillLocation,
362+
Location loc,
362363
llvm::function_ref<FailureOr<Value>()> convertArgOperandToValue,
363364
llvm::Value *address,
364365
llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> variable,
@@ -508,7 +509,7 @@ class ModuleImport {
508509
SetVector<llvm::Instruction *> debugIntrinsics;
509510
/// Function-local list of debug records that need to be imported after the
510511
/// function conversion has finished.
511-
SetVector<llvm::DbgRecord *> debugRecords;
512+
SetVector<llvm::DbgVariableRecord *> dbgRecords;
512513
/// Mapping between LLVM alias scope and domain metadata nodes and
513514
/// attributes in the LLVM dialect corresponding to these nodes.
514515
DenseMap<const llvm::MDNode *, Attribute> aliasScopeMapping;

mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ void registerFromLLVMIRTranslation() {
7979

8080
// Now that the translation supports importing debug records directly,
8181
// make it the default, but allow the user to override to old behavior.
82-
if (!convertDebugRecToIntrinsics)
82+
if (convertDebugRecToIntrinsics)
8383
llvmModule->convertFromNewDbgValues();
8484

8585
return translateLLVMIRToModule(

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 84 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -524,9 +524,9 @@ void ModuleImport::addDebugIntrinsic(llvm::CallInst *intrinsic) {
524524
debugIntrinsics.insert(intrinsic);
525525
}
526526

527-
void ModuleImport::addDebugRecord(llvm::DbgRecord *debugRecord) {
528-
if (!debugRecords.contains(debugRecord))
529-
debugRecords.insert(debugRecord);
527+
void ModuleImport::addDebugRecord(llvm::DbgVariableRecord *dbgRecord) {
528+
if (!dbgRecords.contains(dbgRecord))
529+
dbgRecords.insert(dbgRecord);
530530
}
531531

532532
static Attribute convertCGProfileModuleFlagValue(ModuleOp mlirModule,
@@ -2557,10 +2557,40 @@ LogicalResult ModuleImport::processInstruction(llvm::Instruction *inst) {
25572557
if (auto *intrinsic = dyn_cast<llvm::IntrinsicInst>(inst))
25582558
return convertIntrinsic(intrinsic);
25592559

2560-
// Capture instruction with attached debug markers for later processing.
2561-
if (inst->DebugMarker)
2562-
for (llvm::DbgRecord &debugRecord : inst->DebugMarker->getDbgRecordRange())
2563-
addDebugRecord(&debugRecord);
2560+
// Process debug records attached to this instruction. Debug variable records
2561+
// are stored for later processing after all SSA values are converted, while
2562+
// debug label records can be converted immediately.
2563+
if (inst->DebugMarker) {
2564+
for (llvm::DbgRecord &dbgRecord : inst->DebugMarker->getDbgRecordRange()) {
2565+
// Store debug variable records for later processing.
2566+
if (auto *dbgVariableRecord =
2567+
dyn_cast<llvm::DbgVariableRecord>(&dbgRecord)) {
2568+
addDebugRecord(dbgVariableRecord);
2569+
continue;
2570+
}
2571+
Location loc = translateLoc(dbgRecord.getDebugLoc());
2572+
auto emitUnsupportedWarning = [&]() -> LogicalResult {
2573+
if (!emitExpensiveWarnings)
2574+
return success();
2575+
std::string options;
2576+
llvm::raw_string_ostream optionsStream(options);
2577+
dbgRecord.print(optionsStream);
2578+
emitWarning(loc) << "unhandled debug record " << optionsStream.str();
2579+
return success();
2580+
};
2581+
// Convert the debug label records in-place.
2582+
if (auto *dbgLabelRecord = dyn_cast<llvm::DbgLabelRecord>(&dbgRecord)) {
2583+
DILabelAttr labelAttr =
2584+
debugImporter->translate(dbgLabelRecord->getLabel());
2585+
if (!labelAttr)
2586+
return emitUnsupportedWarning();
2587+
LLVM::DbgLabelOp::create(builder, loc, labelAttr);
2588+
continue;
2589+
}
2590+
// Warn if an unsupported debug record is encountered.
2591+
return emitUnsupportedWarning();
2592+
}
2593+
}
25642594

25652595
// Convert all remaining LLVM instructions to MLIR operations.
25662596
return convertInstruction(inst);
@@ -3047,10 +3077,12 @@ LogicalResult ModuleImport::processFunction(llvm::Function *func) {
30473077
return success();
30483078
}
30493079

3050-
/// Checks if a kill location holds metadata instead of an SSA value.
3051-
static bool isMetadataKillLocation(bool isKillLocation, llvm::Value *value) {
3052-
if (!isKillLocation)
3080+
/// Checks if `dbgIntr` is a kill location that holds metadata instead of an SSA
3081+
/// value.
3082+
static bool isMetadataKillLocation(llvm::DbgVariableIntrinsic *dbgIntr) {
3083+
if (!dbgIntr->isKillLocation())
30533084
return false;
3085+
llvm::Value *value = dbgIntr->getArgOperand(0);
30543086
auto *nodeAsVal = dyn_cast<llvm::MetadataAsValue>(value);
30553087
if (!nodeAsVal)
30563088
return false;
@@ -3095,23 +3127,13 @@ static LogicalResult setDebugIntrinsicBuilderInsertionPoint(
30953127

30963128
std::tuple<DILocalVariableAttr, DIExpressionAttr, Value>
30973129
ModuleImport::processDebugOpArgumentsAndInsertionPt(
3098-
Location loc, bool hasArgList, bool isKillLocation,
3130+
Location loc,
30993131
llvm::function_ref<FailureOr<Value>()> convertArgOperandToValue,
31003132
llvm::Value *address,
31013133
llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> variable,
31023134
llvm::DIExpression *expression, DominanceInfo &domInfo) {
3103-
// Drop debug intrinsics with arg lists.
3104-
// TODO: Support debug intrinsics that have arg lists.
3105-
if (hasArgList)
3106-
return {};
3107-
// Kill locations can have metadata nodes as location operand. This
3108-
// cannot be converted to poison as the type cannot be reconstructed.
3109-
// TODO: find a way to support this case.
3110-
if (isMetadataKillLocation(isKillLocation, address))
3111-
return {};
3112-
// Drop debug intrinsics if the associated variable information cannot be
3113-
// translated due to cyclic debug metadata.
3114-
// TODO: Support cyclic debug metadata.
3135+
// Drop debug intrinsics if the associated debug information cannot be
3136+
// translated due to an unsupported construct.
31153137
DILocalVariableAttr localVarAttr = matchLocalVariableAttr(variable);
31163138
if (!localVarAttr)
31173139
return {};
@@ -3144,10 +3166,21 @@ ModuleImport::processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
31443166
return convertMetadataValue(dbgIntr->getArgOperand(0));
31453167
};
31463168

3169+
// Drop debug intrinsics with an argument list.
3170+
// TODO: Support this case.
3171+
if (dbgIntr->hasArgList())
3172+
return emitUnsupportedWarning();
3173+
3174+
// Drop debug intrinsics with kill locations that have metadata nodes as
3175+
// location operand, which cannot be converted to poison as the type cannot be
3176+
// reconstructed.
3177+
// TODO: Support this case.
3178+
if (isMetadataKillLocation(dbgIntr))
3179+
return emitUnsupportedWarning();
3180+
31473181
auto [localVariableAttr, locationExprAttr, locVal] =
31483182
processDebugOpArgumentsAndInsertionPt(
3149-
loc, dbgIntr->hasArgList(), dbgIntr->isKillLocation(),
3150-
convertArgOperandToValue, dbgIntr->getArgOperand(0),
3183+
loc, convertArgOperandToValue, dbgIntr->getArgOperand(0),
31513184
dbgIntr->getArgOperand(1), dbgIntr->getExpression(), domInfo);
31523185

31533186
if (!localVariableAttr)
@@ -3171,26 +3204,35 @@ ModuleImport::processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
31713204
return success();
31723205
}
31733206

3174-
LogicalResult ModuleImport::processDebugRecord(llvm::DbgRecord &debugRecord,
3175-
DominanceInfo &domInfo) {
3176-
Location loc = translateLoc(debugRecord.getDebugLoc());
3177-
auto emitUnsupportedWarning = [&]() {
3207+
LogicalResult
3208+
ModuleImport::processDebugRecord(llvm::DbgVariableRecord &dbgRecord,
3209+
DominanceInfo &domInfo) {
3210+
OpBuilder::InsertionGuard guard(builder);
3211+
Location loc = translateLoc(dbgRecord.getDebugLoc());
3212+
auto emitUnsupportedWarning = [&]() -> LogicalResult {
31783213
if (!emitExpensiveWarnings)
31793214
return success();
31803215
std::string options;
31813216
llvm::raw_string_ostream optionsStream(options);
3182-
debugRecord.print(optionsStream);
3183-
emitWarning(loc) << "unhandled debug record " << optionsStream.str();
3217+
dbgRecord.print(optionsStream);
3218+
emitWarning(loc) << "unhandled debug variable record "
3219+
<< optionsStream.str();
31843220
return success();
31853221
};
31863222

3187-
OpBuilder::InsertionGuard guard(builder);
3188-
auto *dbgVar = dyn_cast<llvm::DbgVariableRecord>(&debugRecord);
3189-
if (!dbgVar)
3223+
// Drop debug records with an argument list.
3224+
// TODO: Support this case.
3225+
if (dbgRecord.hasArgList())
3226+
return emitUnsupportedWarning();
3227+
3228+
// Drop all other debug records with a address operand that cannot be
3229+
// converted to an SSA value such as an empty metadata node.
3230+
// TODO: Support this case.
3231+
if (!dbgRecord.getAddress())
31903232
return emitUnsupportedWarning();
31913233

31923234
auto convertArgOperandToValue = [&]() -> FailureOr<Value> {
3193-
llvm::Value *value = dbgVar->getAddress();
3235+
llvm::Value *value = dbgRecord.getAddress();
31943236

31953237
// Return the mapped value if it has been converted before.
31963238
auto it = valueMapping.find(value);
@@ -3205,20 +3247,19 @@ LogicalResult ModuleImport::processDebugRecord(llvm::DbgRecord &debugRecord,
32053247

32063248
auto [localVariableAttr, locationExprAttr, locVal] =
32073249
processDebugOpArgumentsAndInsertionPt(
3208-
loc, dbgVar->hasArgList(), dbgVar->isKillLocation(),
3209-
convertArgOperandToValue, dbgVar->getAddress(), dbgVar->getVariable(),
3210-
dbgVar->getExpression(), domInfo);
3250+
loc, convertArgOperandToValue, dbgRecord.getAddress(),
3251+
dbgRecord.getVariable(), dbgRecord.getExpression(), domInfo);
32113252

32123253
if (!localVariableAttr)
32133254
return emitUnsupportedWarning();
32143255

32153256
if (!locVal) // Expected if localVariableAttr is present.
32163257
return failure();
32173258

3218-
if (dbgVar->isDbgDeclare())
3259+
if (dbgRecord.isDbgDeclare())
32193260
LLVM::DbgDeclareOp::create(builder, loc, locVal, localVariableAttr,
32203261
locationExprAttr);
3221-
else if (dbgVar->isDbgValue())
3262+
else if (dbgRecord.isDbgValue())
32223263
LLVM::DbgValueOp::create(builder, loc, locVal, localVariableAttr,
32233264
locationExprAttr);
32243265
else // isDbgAssign
@@ -3239,11 +3280,10 @@ LogicalResult ModuleImport::processDebugIntrinsics() {
32393280

32403281
LogicalResult ModuleImport::processDebugRecords() {
32413282
DominanceInfo domInfo;
3242-
for (llvm::DbgRecord *debugRecord : debugRecords) {
3243-
if (failed(processDebugRecord(*debugRecord, domInfo)))
3283+
for (llvm::DbgVariableRecord *dbgRecord : dbgRecords)
3284+
if (failed(processDebugRecord(*dbgRecord, domInfo)))
32443285
return failure();
3245-
}
3246-
debugRecords.clear();
3286+
dbgRecords.clear();
32473287
return success();
32483288
}
32493289

mlir/test/Target/LLVMIR/Import/import-failure.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
; RUN: not mlir-translate -import-llvm -emit-expensive-warnings -split-input-file %s 2>&1 -o /dev/null | FileCheck %s
22

3-
; Check that debug intrinsics with an unsupported argument are dropped.
4-
5-
declare void @llvm.dbg.value(metadata, metadata, metadata)
3+
; Check that debug records with an unsupported argument are dropped.
64

75
; CHECK: import-failure.ll
8-
; CHECK-SAME: warning: dropped intrinsic: tail call void @llvm.dbg.value(metadata !DIArgList(i64 %{{.*}}, i64 undef), metadata !3, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 1, DW_OP_mul, DW_OP_plus, DW_OP_stack_value))
6+
; CHECK-SAME: warning: unhandled debug variable record #dbg_value(!DIArgList(i64 %{{.*}}, i64 undef), !{{.*}}, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 1, DW_OP_mul, DW_OP_plus, DW_OP_stack_value), !{{.*}})
97
; CHECK: import-failure.ll
10-
; CHECK-SAME: warning: dropped intrinsic: tail call void @llvm.dbg.value(metadata !6, metadata !3, metadata !DIExpression())
8+
; CHECK-SAME: warning: unhandled debug variable record #dbg_value(!{{.*}}, !{{.*}}, !DIExpression(), !{{.*}})
119
define void @unsupported_argument(i64 %arg1) {
12-
tail call void @llvm.dbg.value(metadata !DIArgList(i64 %arg1, i64 undef), metadata !3, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 1, DW_OP_mul, DW_OP_plus, DW_OP_stack_value)), !dbg !5
13-
tail call void @llvm.dbg.value(metadata !6, metadata !3, metadata !DIExpression()), !dbg !5
10+
#dbg_value(!DIArgList(i64 %arg1, i64 undef), !3, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 1, DW_OP_mul, DW_OP_plus, DW_OP_stack_value), !5)
11+
#dbg_value(!6, !3, !DIExpression(), !5)
1412
ret void
1513
}
1614

0 commit comments

Comments
 (0)