Skip to content

Commit 8fda2cf

Browse files
committed
[mlir][llvm] Handle debug record import edge cases
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 dbf4525 commit 8fda2cf

File tree

4 files changed

+96
-60
lines changed

4 files changed

+96
-60
lines changed

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

Lines changed: 9 additions & 5 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 *debugRecord);
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
@@ -349,16 +350,19 @@ class ModuleImport {
349350
/// Converts a single debug intrinsic.
350351
LogicalResult processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
351352
DominanceInfo &domInfo);
353+
/// Emits a warning for an unsupported debug records.
354+
LogicalResult emitUnsupportedDebugRecordWarning(llvm::DbgRecord &debugRecord,
355+
Location loc);
352356
/// Converts a single debug record.
353-
LogicalResult processDebugRecord(llvm::DbgRecord &debugRecord,
357+
LogicalResult processDebugRecord(llvm::DbgVariableRecord &debugRecord,
354358
DominanceInfo &domInfo);
355359
/// Process arguments for declare/value operation insertion. `localVarAttr`
356360
/// and `localExprAttr` are the attained attributes after importing the debug
357361
/// variable and expressions. This also sets the builder insertion point to be
358362
/// used by these operations.
359363
std::tuple<DILocalVariableAttr, DIExpressionAttr, Value>
360364
processDebugOpArgumentsAndInsertionPt(
361-
Location loc, bool hasArgList, bool isKillLocation,
365+
Location loc,
362366
llvm::function_ref<FailureOr<Value>()> convertArgOperandToValue,
363367
llvm::Value *address,
364368
llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> variable,
@@ -508,7 +512,7 @@ class ModuleImport {
508512
SetVector<llvm::Instruction *> debugIntrinsics;
509513
/// Function-local list of debug records that need to be imported after the
510514
/// function conversion has finished.
511-
SetVector<llvm::DbgRecord *> debugRecords;
515+
SetVector<llvm::DbgVariableRecord *> debugRecords;
512516
/// Mapping between LLVM alias scope and domain metadata nodes and
513517
/// attributes in the LLVM dialect corresponding to these nodes.
514518
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: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ void ModuleImport::addDebugIntrinsic(llvm::CallInst *intrinsic) {
524524
debugIntrinsics.insert(intrinsic);
525525
}
526526

527-
void ModuleImport::addDebugRecord(llvm::DbgRecord *debugRecord) {
527+
void ModuleImport::addDebugRecord(llvm::DbgVariableRecord *debugRecord) {
528528
if (!debugRecords.contains(debugRecord))
529529
debugRecords.insert(debugRecord);
530530
}
@@ -2557,10 +2557,32 @@ 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 &debugRecord :
2565+
inst->DebugMarker->getDbgRecordRange()) {
2566+
// Store debug variable records for later processing.
2567+
if (auto *dbgVariableRecord =
2568+
dyn_cast<llvm::DbgVariableRecord>(&debugRecord)) {
2569+
addDebugRecord(dbgVariableRecord);
2570+
continue;
2571+
}
2572+
Location loc = translateLoc(debugRecord.getDebugLoc());
2573+
// Convert debug labels in-place.
2574+
if (auto *dbgLabelRecord = dyn_cast<llvm::DbgLabelRecord>(&debugRecord)) {
2575+
DILabelAttr labelAttr =
2576+
debugImporter->translate(dbgLabelRecord->getLabel());
2577+
if (!labelAttr)
2578+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
2579+
LLVM::DbgLabelOp::create(builder, loc, labelAttr);
2580+
continue;
2581+
}
2582+
// Warn if an unsupported debug record is encountered.
2583+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
2584+
}
2585+
}
25642586

25652587
// Convert all remaining LLVM instructions to MLIR operations.
25662588
return convertInstruction(inst);
@@ -3047,10 +3069,12 @@ LogicalResult ModuleImport::processFunction(llvm::Function *func) {
30473069
return success();
30483070
}
30493071

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)
3072+
/// Checks if `dbgIntr` is a kill location that holds metadata instead of an SSA
3073+
/// value.
3074+
static bool isMetadataKillLocation(llvm::DbgVariableIntrinsic *dbgIntr) {
3075+
if (!dbgIntr->isKillLocation())
30533076
return false;
3077+
llvm::Value *value = dbgIntr->getArgOperand(0);
30543078
auto *nodeAsVal = dyn_cast<llvm::MetadataAsValue>(value);
30553079
if (!nodeAsVal)
30563080
return false;
@@ -3095,23 +3119,13 @@ static LogicalResult setDebugIntrinsicBuilderInsertionPoint(
30953119

30963120
std::tuple<DILocalVariableAttr, DIExpressionAttr, Value>
30973121
ModuleImport::processDebugOpArgumentsAndInsertionPt(
3098-
Location loc, bool hasArgList, bool isKillLocation,
3122+
Location loc,
30993123
llvm::function_ref<FailureOr<Value>()> convertArgOperandToValue,
31003124
llvm::Value *address,
31013125
llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> variable,
31023126
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.
3127+
// Drop debug intrinsics if the associated debug information cannot be
3128+
// translated due to an unsupported construct.
31153129
DILocalVariableAttr localVarAttr = matchLocalVariableAttr(variable);
31163130
if (!localVarAttr)
31173131
return {};
@@ -3144,10 +3158,21 @@ ModuleImport::processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
31443158
return convertMetadataValue(dbgIntr->getArgOperand(0));
31453159
};
31463160

3161+
// Drop debug intrinsics with an argument list.
3162+
// TODO: Support this case.
3163+
if (dbgIntr->hasArgList())
3164+
return emitUnsupportedWarning();
3165+
3166+
// Drop debug intrinsics with kill locations that have metadata nodes as
3167+
// location operand, which cannot be converted to poison as the type cannot be
3168+
// reconstructed.
3169+
// TODO: Support this case.
3170+
if (isMetadataKillLocation(dbgIntr))
3171+
return emitUnsupportedWarning();
3172+
31473173
auto [localVariableAttr, locationExprAttr, locVal] =
31483174
processDebugOpArgumentsAndInsertionPt(
3149-
loc, dbgIntr->hasArgList(), dbgIntr->isKillLocation(),
3150-
convertArgOperandToValue, dbgIntr->getArgOperand(0),
3175+
loc, convertArgOperandToValue, dbgIntr->getArgOperand(0),
31513176
dbgIntr->getArgOperand(1), dbgIntr->getExpression(), domInfo);
31523177

31533178
if (!localVariableAttr)
@@ -3171,26 +3196,26 @@ ModuleImport::processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,
31713196
return success();
31723197
}
31733198

3174-
LogicalResult ModuleImport::processDebugRecord(llvm::DbgRecord &debugRecord,
3175-
DominanceInfo &domInfo) {
3176-
Location loc = translateLoc(debugRecord.getDebugLoc());
3177-
auto emitUnsupportedWarning = [&]() {
3178-
if (!emitExpensiveWarnings)
3179-
return success();
3180-
std::string options;
3181-
llvm::raw_string_ostream optionsStream(options);
3182-
debugRecord.print(optionsStream);
3183-
emitWarning(loc) << "unhandled debug record " << optionsStream.str();
3199+
LogicalResult
3200+
ModuleImport::emitUnsupportedDebugRecordWarning(llvm::DbgRecord &debugRecord,
3201+
Location loc) {
3202+
if (!emitExpensiveWarnings)
31843203
return success();
3185-
};
3204+
std::string options;
3205+
llvm::raw_string_ostream optionsStream(options);
3206+
debugRecord.print(optionsStream);
3207+
emitWarning(loc) << "unhandled debug record " << optionsStream.str();
3208+
return success();
3209+
}
31863210

3211+
LogicalResult
3212+
ModuleImport::processDebugRecord(llvm::DbgVariableRecord &debugRecord,
3213+
DominanceInfo &domInfo) {
31873214
OpBuilder::InsertionGuard guard(builder);
3188-
auto *dbgVar = dyn_cast<llvm::DbgVariableRecord>(&debugRecord);
3189-
if (!dbgVar)
3190-
return emitUnsupportedWarning();
3215+
Location loc = translateLoc(debugRecord.getDebugLoc());
31913216

31923217
auto convertArgOperandToValue = [&]() -> FailureOr<Value> {
3193-
llvm::Value *value = dbgVar->getAddress();
3218+
llvm::Value *value = debugRecord.getAddress();
31943219

31953220
// Return the mapped value if it has been converted before.
31963221
auto it = valueMapping.find(value);
@@ -3203,26 +3228,36 @@ LogicalResult ModuleImport::processDebugRecord(llvm::DbgRecord &debugRecord,
32033228
return failure();
32043229
};
32053230

3231+
// Drop debug records with an argument list.
3232+
// TODO: Support this case.
3233+
if (debugRecord.hasArgList())
3234+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
3235+
3236+
// Drop kill location debug records with a null address operand, which cannot
3237+
// be converted to poison as the type cannot be reconstructed.
3238+
// TODO: Support this case.
3239+
if (!debugRecord.getAddress())
3240+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
3241+
32063242
auto [localVariableAttr, locationExprAttr, locVal] =
32073243
processDebugOpArgumentsAndInsertionPt(
3208-
loc, dbgVar->hasArgList(), dbgVar->isKillLocation(),
3209-
convertArgOperandToValue, dbgVar->getAddress(), dbgVar->getVariable(),
3210-
dbgVar->getExpression(), domInfo);
3244+
loc, convertArgOperandToValue, debugRecord.getAddress(),
3245+
debugRecord.getVariable(), debugRecord.getExpression(), domInfo);
32113246

32123247
if (!localVariableAttr)
3213-
return emitUnsupportedWarning();
3248+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
32143249

32153250
if (!locVal) // Expected if localVariableAttr is present.
32163251
return failure();
32173252

3218-
if (dbgVar->isDbgDeclare())
3253+
if (debugRecord.isDbgDeclare())
32193254
LLVM::DbgDeclareOp::create(builder, loc, locVal, localVariableAttr,
32203255
locationExprAttr);
3221-
else if (dbgVar->isDbgValue())
3256+
else if (debugRecord.isDbgValue())
32223257
LLVM::DbgValueOp::create(builder, loc, locVal, localVariableAttr,
32233258
locationExprAttr);
32243259
else // isDbgAssign
3225-
return emitUnsupportedWarning();
3260+
return emitUnsupportedDebugRecordWarning(debugRecord, loc);
32263261

32273262
return success();
32283263
}
@@ -3239,10 +3274,9 @@ LogicalResult ModuleImport::processDebugIntrinsics() {
32393274

32403275
LogicalResult ModuleImport::processDebugRecords() {
32413276
DominanceInfo domInfo;
3242-
for (llvm::DbgRecord *debugRecord : debugRecords) {
3277+
for (llvm::DbgVariableRecord *debugRecord : debugRecords)
32433278
if (failed(processDebugRecord(*debugRecord, domInfo)))
32443279
return failure();
3245-
}
32463280
debugRecords.clear();
32473281
return success();
32483282
}

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 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 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)