diff --git a/llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp --- a/llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp @@ -72,11 +72,6 @@ /// Calculate the liveness information for the given machine function. bool runOnMachineFunction(MachineFunction &MF) override; - MachineFunctionProperties getRequiredProperties() const override { - return MachineFunctionProperties().set( - MachineFunctionProperties::Property::NoVRegs); - } - void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); MachineFunctionPass::getAnalysisUsage(AU); diff --git a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp --- a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp @@ -298,6 +298,16 @@ } }; + // Target indices used for wasm-specific locations. + struct WasmLoc { + int Index; // One of TargetIndex values defined in WebAssembly.h + int64_t Offset; + bool operator==(const WasmLoc &Other) const { + return Index == Other.Index && Offset == Other.Offset; + } + bool operator!=(const WasmLoc &Other) const { return !(*this == Other); } + }; + /// Identity of the variable at this location. const DebugVariable Var; @@ -312,7 +322,8 @@ InvalidKind = 0, RegisterKind, SpillLocKind, - ImmediateKind + ImmediateKind, + WasmLocKind }; enum class EntryValueLocKind { @@ -331,6 +342,7 @@ int64_t Immediate; const ConstantFP *FPImm; const ConstantInt *CImm; + WasmLoc WasmLocation; MachineLocValue() : Hash(0) {} }; @@ -347,6 +359,8 @@ switch (Kind) { case MachineLocKind::SpillLocKind: return Value.SpillLocation == Other.Value.SpillLocation; + case MachineLocKind::WasmLocKind: + return Value.WasmLocation == Other.Value.WasmLocation; case MachineLocKind::RegisterKind: case MachineLocKind::ImmediateKind: return Value.Hash == Other.Value.Hash; @@ -365,6 +379,11 @@ Other.Kind, Other.Value.SpillLocation.SpillBase, Other.Value.SpillLocation.SpillOffset.getFixed(), Other.Value.SpillLocation.SpillOffset.getScalable()); + case MachineLocKind::WasmLocKind: + return std::make_tuple(Kind, Value.WasmLocation.Index, + Value.WasmLocation.Offset) < + std::make_tuple(Other.Kind, Other.Value.WasmLocation.Index, + Other.Value.WasmLocation.Offset); case MachineLocKind::RegisterKind: case MachineLocKind::ImmediateKind: return std::tie(Kind, Value.Hash) < @@ -428,6 +447,9 @@ } else if (Op.isCImm()) { Kind = MachineLocKind::ImmediateKind; Loc.CImm = Op.getCImm(); + } else if (Op.isTargetIndex()) { + Kind = MachineLocKind::WasmLocKind; + Loc.WasmLocation = {Op.getIndex(), Op.getOffset()}; } else llvm_unreachable("Invalid Op kind for MachineLoc."); return {Kind, Loc}; @@ -563,6 +585,10 @@ MOs.push_back(Orig); break; } + case MachineLocKind::WasmLocKind: { + MOs.push_back(Orig); + break; + } case MachineLocKind::InvalidKind: llvm_unreachable("Tried to produce DBG_VALUE for invalid VarLoc"); } @@ -655,8 +681,9 @@ } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - // TRI can be null. - void dump(const TargetRegisterInfo *TRI, raw_ostream &Out = dbgs()) const { + // TRI and TII can be null. + void dump(const TargetRegisterInfo *TRI, const TargetInstrInfo *TII, + raw_ostream &Out = dbgs()) const { Out << "VarLoc("; for (const MachineLoc &MLoc : Locs) { if (Locs.begin() != &MLoc) @@ -675,6 +702,22 @@ case MachineLocKind::ImmediateKind: Out << MLoc.Value.Immediate; break; + case MachineLocKind::WasmLocKind: { + if (TII) { + auto Indices = TII->getSerializableTargetIndices(); + auto Found = + find_if(Indices, [&](const std::pair &I) { + return I.first == MLoc.Value.WasmLocation.Index; + }); + assert(Found != Indices.end()); + Out << Found->second; + if (MLoc.Value.WasmLocation.Offset > 0) + Out << " + " << MLoc.Value.WasmLocation.Offset; + } else { + Out << "WasmLoc"; + } + break; + } case MachineLocKind::InvalidKind: llvm_unreachable("Invalid VarLoc in dump method"); } @@ -737,11 +780,6 @@ // always have an index at the universal location index as the last index. if (VL.EVKind == VarLoc::EntryValueLocKind::NonEntryValueKind) { VL.getDescribingRegs(Locations); - assert(all_of(Locations, - [](auto RegNo) { - return RegNo < LocIndex::kFirstInvalidRegLocation; - }) && - "Physreg out of range?"); if (VL.containsSpillLocs()) { LocIndex::u32_location_t Loc = LocIndex::kSpillLocation; Locations.push_back(Loc); @@ -1202,7 +1240,7 @@ for (const VarLoc &VL : VarLocs) { Out << " Var: " << VL.Var.getVariable()->getName(); Out << " MI: "; - VL.dump(TRI, Out); + VL.dump(TRI, TII, Out); } } Out << "\n"; @@ -1340,7 +1378,7 @@ if (all_of(MI.debug_operands(), [](const MachineOperand &MO) { return (MO.isReg() && MO.getReg()) || MO.isImm() || MO.isFPImm() || - MO.isCImm(); + MO.isCImm() || MO.isTargetIndex(); })) { // Use normal VarLoc constructor for registers and immediates. VarLoc VL(MI, LS); @@ -1453,7 +1491,7 @@ ProcessVarLoc(VL); LLVM_DEBUG({ dbgs() << "Creating VarLoc for register copy:"; - VL.dump(TRI); + VL.dump(TRI, TII); }); return; } @@ -1466,7 +1504,7 @@ ProcessVarLoc(VL); LLVM_DEBUG({ dbgs() << "Creating VarLoc for spill:"; - VL.dump(TRI); + VL.dump(TRI, TII); }); return; } @@ -1479,7 +1517,7 @@ ProcessVarLoc(VL); LLVM_DEBUG({ dbgs() << "Creating VarLoc for restore:"; - VL.dump(TRI); + VL.dump(TRI, TII); }); return; } @@ -1817,7 +1855,7 @@ for (VarLoc &VL : VarLocs) { // Copy OpenRanges to OutLocs, if not already present. dbgs() << "Add to OutLocs in MBB #" << CurMBB->getNumber() << ": "; - VL.dump(TRI); + VL.dump(TRI, TII); } }); VarLocSet &VLS = getVarLocsInMBB(CurMBB, OutLocs); @@ -2058,9 +2096,12 @@ static void collectRegDefs(const MachineInstr &MI, DefinedRegsSet &Regs, const TargetRegisterInfo *TRI) { for (const MachineOperand &MO : MI.operands()) - if (MO.isReg() && MO.isDef() && MO.getReg()) - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) - Regs.insert(*AI); + if (MO.isReg() && MO.isDef() && MO.getReg()) { + Regs.insert(MO.getReg()); + if (Register::isPhysicalRegister(MO.getReg())) + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) + Regs.insert(*AI); + } } /// This routine records the entry values of function parameters. The values diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -505,7 +505,6 @@ disablePass(&PostRASchedulerID); disablePass(&FuncletLayoutID); disablePass(&StackMapLivenessID); - disablePass(&LiveDebugValuesID); disablePass(&PatchableFunctionID); disablePass(&ShrinkWrapID); diff --git a/llvm/test/DebugInfo/WebAssembly/live-debug-values.mir b/llvm/test/DebugInfo/WebAssembly/live-debug-values.mir new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/WebAssembly/live-debug-values.mir @@ -0,0 +1,170 @@ +# RUN: llc -run-pass livedebugvalues %s -o - | FileCheck %s + +# Test if LiveDebugValue analysis works on Wasm. + +--- | + target triple = "wasm32-unknown-unknown" + + define void @test_const_vars() !dbg !5 { + call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !10 + call void @llvm.dbg.value(metadata i32 0, metadata !11, metadata !DIExpression()), !dbg !10 + call void @llvm.dbg.value(metadata i32 0, metadata !12, metadata !DIExpression()), !dbg !10 + call void @llvm.dbg.value(metadata i32 0, metadata !13, metadata !DIExpression()), !dbg !10 + ret void + } + + define void @test_target_index_vars() !dbg !14 { + call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 0, metadata !19, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 0, metadata !20, metadata !DIExpression()), !dbg !16 + ret void + } + + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3, !4} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) + !1 = !DIFile(filename: "test.c", directory: "") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{i32 1, !"wchar_size", i32 4} + !5 = distinct !DISubprogram(name: "test_const_vars", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, unit: !0) + !6 = !DISubroutineType(types: !7) + !7 = !{!8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !DILocalVariable(name: "var0", scope: !5, file: !1, line: 2, type: !8) + !10 = !DILocation(line: 0, scope: !5) + !11 = !DILocalVariable(name: "var1", scope: !5, file: !1, line: 2, type: !8) + !12 = !DILocalVariable(name: "var2", scope: !5, file: !1, line: 2, type: !8) + !13 = !DILocalVariable(name: "var3", scope: !5, file: !1, line: 2, type: !8) + !14 = distinct !DISubprogram(name: "test_target_index_vars", scope: !1, file: !1, line: 10, type: !6, scopeLine: 1, unit: !0) + !15 = !DILocalVariable(name: "var0", scope: !14, file: !1, line: 11, type: !8) + !16 = !DILocation(line: 10, scope: !14) + !17 = !DILocalVariable(name: "var1", scope: !14, file: !1, line: 11, type: !8) + !18 = !DILocalVariable(name: "var2", scope: !14, file: !1, line: 11, type: !8) + !19 = !DILocalVariable(name: "var3", scope: !14, file: !1, line: 11, type: !8) + !20 = !DILocalVariable(name: "var4", scope: !14, file: !1, line: 11, type: !8) +... + +--- +# !9 (var0): Its debug value is set once in bb.0 and valid throughout the +# function. So a new DBG_VALUE will be added to the beginnings of all +# other BBs (bb.1, bb.2, and bb.3). +# !11 (var1): Its debug value is set in bb.0, but is reset to no info in bb.1. +# So a new DBG_VALUE will be added in the beginning of bb.1 and +# bb.2, but bb.3 will not, because its two predecesors (bb.1 and +# bb.2) have different debug values. +# !12 (var2): Its debug value is set both in bb.1 and bb.2 with the same value. +# bb.3 will have a new DBG_VALUE representing that value. +# !13 (var3): Its debug value is set both in bb.1 and bb.2 but with different +# values. bb.3 will NOT have a new DBG_VALUE instruction because its +# predecessors don't agree on a value. +# CHECK-LABEL: name: test_const_vars +name: test_const_vars +liveins: + - { reg: '$arguments' } +body: | + bb.0: + successors: %bb.1, %bb.2 + liveins: $arguments + DBG_VALUE 10, $noreg, !9, !DIExpression(), debug-location !10 + DBG_VALUE 20, $noreg, !11, !DIExpression(), debug-location !10 + %0:i32 = CONST_I32 1, implicit-def $arguments + BR_IF %bb.2, %0:i32, implicit-def $arguments + + ; CHECK: bb.1: + ; CHECK-DAG: DBG_VALUE 10, $noreg, !9 + ; CHECK-DAG: DBG_VALUE 20, $noreg, !11 + bb.1: + ; predecessors: %bb.0 + successors: %bb.3 + DBG_VALUE $noreg, $noreg, !11, !DIExpression(), debug-location !10 + DBG_VALUE 30, $noreg, !12, !DIExpression(), debug-location !10 + DBG_VALUE 30, $noreg, !13, !DIExpression(), debug-location !10 + BR %bb.3, implicit-def $arguments + + ; CHECK: bb.2: + ; CHECK-DAG: DBG_VALUE 10, $noreg, !9 + ; CHECK-DAG: DBG_VALUE 20, $noreg, !11 + bb.2: + ; predecessors: %bb.0 + successors: %bb.3 + DBG_VALUE 30, $noreg, !12, !DIExpression(), debug-location !10 + DBG_VALUE 40, $noreg, !13, !DIExpression(), debug-location !10 + BR %bb.3, implicit-def $arguments + + ; CHECK: bb.3: + ; CHECK-DAG: DBG_VALUE 10, $noreg, !9 + ; CHECK-DAG: DBG_VALUE 30, $noreg, !12 + ; CHECK-NOT: DBG_VALUE {{[0-9]+}}, $noreg, !11 + ; CHECK-NOT: DBG_VALUE {{[0-9]+}}, $noreg, !13 + bb.3: + ; predecessors: %bb.1, %bb.2 + RETURN implicit-def dead $arguments +... + +--- +# !15 (var0): Its debug value is set once in bb.0 and valid throughout the +# function. So a new DBG_VALUE will be added to the beginnings of all +# other BBs (bb.1, bb.2, and bb.3). +# !17 (var1): Its debug value is set in bb.0, but is reset to no info back later +# in bb.0. So no DBG_VALUEs will be added in other BBs. +# !18 (var2): Its debug value is set both in bb.1 and bb.2 with the same value +# (The same kind (local) and same local index). bb.3 will have a new +# DBG_VALUE representing that value. +# !19 (var3): Its debug value is set both in bb.1 and bb.2 but with different +# values. Both are locals, but their indices are different. bb.3 +# will NOT have a new DBG_VALUE instruction because its predecessors +# don't agree on a value. +# !20 (var4): Its debug value is set both in bb.1 and bb.2 but with different +# values. They have different kinds; one is a local and the other is +# a stack operand. (Their index is the same, but it doesn't matter.) +# bb.3 will NOT have a new DBG_VALUE instruction because its +# predecessors don't agree on a value. +# CHECK-LABEL: name: test_target_index_vars +name: test_target_index_vars +liveins: + - { reg: '$arguments' } +body: | + bb.0: + successors: %bb.1, %bb.2 + liveins: $arguments + DBG_VALUE target-index(wasm-local), $noreg, !15, !DIExpression(), debug-location !16 + DBG_VALUE target-index(wasm-operand-stack) + 2, $noreg, !17, !DIExpression(), debug-location !16 + %0:i32 = CONST_I32 1, implicit-def $arguments + DBG_VALUE $noreg, $noreg, !17, !DIExpression(), debug-location !16 + BR_IF %bb.2, %0:i32, implicit-def $arguments + + ; CHECK: bb.1: + ; CHECK: DBG_VALUE target-index(wasm-local), $noreg, !15 + bb.1: + ; predecessors: %bb.0 + successors: %bb.3 + DBG_VALUE target-index(wasm-local) + 2, $noreg, !18, !DIExpression(), debug-location !16 + DBG_VALUE target-index(wasm-local) + 3, $noreg, !19, !DIExpression(), debug-location !16 + DBG_VALUE target-index(wasm-operand-stack) + 3, $noreg, !20, !DIExpression(), debug-location !16 + BR %bb.3, implicit-def $arguments + + ; CHECK: bb.2: + ; CHECK: DBG_VALUE target-index(wasm-local), $noreg, !15 + bb.2: + ; predecessors: %bb.0 + successors: %bb.3 + DBG_VALUE target-index(wasm-local) + 2, $noreg, !18, !DIExpression(), debug-location !16 + DBG_VALUE target-index(wasm-local) + 5, $noreg, !19, !DIExpression(), debug-location !16 + DBG_VALUE target-index(wasm-local) + 3, $noreg, !20, !DIExpression(), debug-location !16 + BR %bb.3, implicit-def $arguments + + ; CHECK: bb.3: + ; CHECK-DAG: DBG_VALUE target-index(wasm-local), $noreg, !15 + ; CHECK-DAG: DBG_VALUE target-index(wasm-local) + 2, $noreg, !18 + ; CHECK-NOT: DBG_VALUE target-index(wasm-local){{.*}}, $noreg, !19 + ; CHECK-NOT: DBG_VALUE target-index(wasm-local){{.*}}, $noreg, !20 + bb.3: + ; predecessors: %bb.1, %bb.2 + RETURN implicit-def dead $arguments +...