Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Casting.h" @@ -3770,6 +3771,10 @@ Fragment(DIExpr ? DIExpr->getFragmentInfo() : std::nullopt), InlinedAt(InlinedAt) {} + DebugVariable(const MachineInstr *MI) + : DebugVariable(MI->getDebugVariable(), MI->getDebugExpression(), + MI->getDebugLoc()->getInlinedAt()) {} + const DILocalVariable *getVariable() const { return Variable; } std::optional getFragment() const { return Fragment; } const DILocation *getInlinedAt() const { return InlinedAt; } Index: llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp =================================================================== --- llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -2172,10 +2172,10 @@ unsigned &NewOpc, Register &EvenReg, Register &OddReg, Register &BaseReg, int &Offset, Register &PredReg, ARMCC::CondCodes &Pred, bool &isT2); - bool RescheduleOps(MachineBasicBlock *MBB, - SmallVectorImpl &Ops, - unsigned Base, bool isLd, - DenseMap &MI2LocMap); + bool RescheduleOps( + MachineBasicBlock *MBB, SmallVectorImpl &Ops, + unsigned Base, bool isLd, DenseMap &MI2LocMap, + SmallDenseMap, 8> &RegisterMap); bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB); bool DistributeIncrements(); bool DistributeIncrements(Register Base); @@ -2324,10 +2324,10 @@ return true; } -bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB, - SmallVectorImpl &Ops, - unsigned Base, bool isLd, - DenseMap &MI2LocMap) { +bool ARMPreAllocLoadStoreOpt::RescheduleOps( + MachineBasicBlock *MBB, SmallVectorImpl &Ops, unsigned Base, + bool isLd, DenseMap &MI2LocMap, + SmallDenseMap, 8> &RegisterMap) { bool RetVal = false; // Sort by offset (in reverse order). @@ -2476,6 +2476,12 @@ } else { for (unsigned i = 0; i != NumMove; ++i) { MachineInstr *Op = Ops.pop_back_val(); + if (isLd) { + // Populate RegisterMap with all Registers defined by loads. + Register Reg = Op->getOperand(0).getReg(); + RegisterMap[Reg]; + } + MBB->splice(InsertPos, MBB, Op); } } @@ -2489,6 +2495,51 @@ return RetVal; } +static void forEachDbgRegOperand(MachineInstr *MI, + std::function Fn) { + if (MI->isNonListDebugValue()) { + auto &Op = MI->getOperand(0); + if (Op.isReg()) + Fn(Op); + } else { + for (unsigned I = 2; I < MI->getNumOperands(); I++) { + auto &Op = MI->getOperand(I); + if (Op.isReg()) + Fn(Op); + } + } +} + +// Update the RegisterMap with the instruction that was moved because a +// DBG_VALUE_LIST may need to be moved again. +static void updateRegisterMapForDbgValueListAfterMove( + SmallDenseMap, 8> &RegisterMap, + MachineInstr *DbgValueListInstr, MachineInstr *InstrToReplace) { + + forEachDbgRegOperand(DbgValueListInstr, [&](MachineOperand &Op) { + auto RegIt = RegisterMap.find(Op.getReg()); + if (RegIt == RegisterMap.end()) + return; + auto &InstrVec = RegIt->getSecond(); + for (unsigned I = 0; I < InstrVec.size(); I++) + if (InstrVec[I] == InstrToReplace) + InstrVec[I] = DbgValueListInstr; + }); +} + +static void replaceImmOperandWithUndefReg(MachineInstr *Instr, + MachineBasicBlock *MBB, + const TargetInstrInfo *TII) { + unsigned Opcode = Instr->getOpcode(); + auto BI = + BuildMI(*MBB, Instr, Instr->getDebugLoc(), TII->get(Opcode)).addReg(0); + for (unsigned I = 1; I < Instr->getNumOperands(); I++) { + auto &Op = Instr->getOperand(I); + BI->addOperand(Op); + } + MBB->erase(Instr); +} + bool ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) { bool RetVal = false; @@ -2501,6 +2552,10 @@ Base2InstMap Base2StsMap; BaseVec LdBases; BaseVec StBases; + // This map is used to track the relationship between the virtual + // register that is the result of a load that is moved and the DBG_VALUE + // MachineInstr pointer that uses that virtual register. + SmallDenseMap, 8> RegisterMap; unsigned Loc = 0; MachineBasicBlock::iterator MBBI = MBB->begin(); @@ -2563,7 +2618,7 @@ unsigned Base = LdBases[i]; SmallVectorImpl &Lds = Base2LdsMap[Base]; if (Lds.size() > 1) - RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap); + RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap, RegisterMap); } // Re-schedule stores. @@ -2571,7 +2626,7 @@ unsigned Base = StBases[i]; SmallVectorImpl &Sts = Base2StsMap[Base]; if (Sts.size() > 1) - RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap); + RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap, RegisterMap); } if (MBBI != E) { @@ -2582,6 +2637,265 @@ } } + // Reschedule DBG_VALUEs to match any loads that were moved. When a load is + // sunk beyond a DBG_VALUE that is referring to it, the DBG_VALUE becomes a + // use-before-def, resulting in a loss of debug info. + + // Example: + // Before the Pre Register Allocation Load Store Pass + // inst_a + // %2 = ld ... + // inst_b + // DBG_VALUE %2, "x", ... + // %3 = ld ... + + // After the Pass: + // inst_a + // inst_b + // DBG_VALUE %2, "x", ... + // %2 = ld ... + // %3 = ld ... + + // The code below addresses this by moving the DBG_VALUE to the position + // immediately after the load. + + // Example: + // After the code below: + // inst_a + // inst_b + // %2 = ld ... + // DBG_VALUE %2, "x", ... + // %3 = ld ... + + // The algorithm works in two phases: First RescheduleOps() populates the + // RegisterMap with registers that were moved as keys, there is no value + // inserted. In the next phase, every MachineInstr in a basic block is + // iterated over. If it is a valid DBG_VALUE or DBG_VALUE_LIST and it uses one + // or more registers in the RegisterMap, the RegisterMap and InstrMap are + // populated with the MachineInstr. If the DBG_VALUE or DBG_VALUE_LIST + // describes debug information for a variable that already exists in the + // DbgValueSinkCandidates, the MachineInstr in the DbgValueSinkCandidates must + // be set to undef. If the current MachineInstr is a load that was moved, + // undef the corresponding DBG_VALUE or DBG_VALUE_LIST and clone it to below + // the load. + + // To illustrate the above algorithm visually let's take this example. + + // Before the Pre Register Allocation Load Store Pass: + // %2 = ld ... + // DBG_VALUE %2, A, .... # X + // DBG_VALUE 0, A, ... # Y + // %3 = ld ... + // DBG_VALUE %3, A, ..., # Z + // %4 = ld ... + + // After Pre Register Allocation Load Store Pass: + // DBG_VALUE %2, A, .... # X + // DBG_VALUE 0, A, ... # Y + // DBG_VALUE %3, A, ..., # Z + // %2 = ld ... + // %3 = ld ... + // %4 = ld ... + + // The algorithm below does the following: + + // In the beginning, the RegisterMap will have been populated with the virtual + // registers %2, and %3, the DbgValueSinkCandidates and the InstrMap will be + // empty. DbgValueSinkCandidates = {}, RegisterMap = {2 -> {}, 3 -> {}}, + // InstrMap {} + // -> DBG_VALUE %2, A, .... # X + // DBG_VALUE 0, A, ... # Y + // DBG_VALUE %3, A, ..., # Z + // %2 = ld ... + // %3 = ld ... + // %4 = ld ... + + // After the first DBG_VALUE (denoted with an X) is processed, the + // DbgValueSinkCandidates and InstrMap will be populated and the RegisterMap + // entry for %2 will be populated as well. DbgValueSinkCandidates = {A -> X}, + // RegisterMap = {2 -> {X}, 3 -> {}}, InstrMap {X -> 2} DBG_VALUE %2, A, .... + // # X + // -> DBG_VALUE 0, A, ... # Y + // DBG_VALUE %3, A, ..., # Z + // %2 = ld ... + // %3 = ld ... + // %4 = ld ... + + // After the DBG_VALUE Y is processed, the DbgValueSinkCandidates is updated + // to now hold Y for A and the RegisterMap is also updated to remove X from + // %2, this is because both X and Y describe the same debug variable A. X is + // also updated to have a $noreg as the first operand. DbgValueSinkCandidates + // = {A -> {Y}}, RegisterMap = {2 -> {}, 3 -> {}}, InstrMap = {X + // -> 2} + // DBG_VALUE $noreg, A, .... # X + // DBG_VALUE 0, A, ... # Y + // -> DBG_VALUE %3, A, ..., # Z + // %2 = ld ... + // %3 = ld ... + // %4 = ld ... + + // After DBG_VALUE Z is processed, the DbgValueSinkCandidates is updated to + // hold Z fr A, the RegisterMap is updated to hold Z for %3, and the InstrMap + // is updated to have Z mapped to %3. This is again because Z describes the + // debug variable A, Y is also updated to have a $noreg as the first operand. + // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, + // InstrMap = {X + // -> 2, Z -> 3} + // DBG_VALUE $noreg, A, .... # X + // DBG_VALUE $noreg, A, ... # Y + // DBG_VALUE %3, A, ..., # Z + // -> %2 = ld ... + // %3 = ld ... + // %4 = ld ... + + // Nothing happens here since the RegisterMap for %2 contains no value. + // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, + // InstrMap = {X + // -> 2, Z -> 3} + // DBG_VALUE $noreg, A, .... # X + // DBG_VALUE $noreg, A, ... # Y + // DBG_VALUE %3, A, ..., # Z + // %2 = ld ... + // -> %3 = ld ... + // %4 = ld ... + + // Since the RegisterMap contains Z as a value for %3, the MachineInstr + // pointer Z is moved to come after the load for %3 and the Basic Block + // iterator is moved to after the DBG_VALUE Z's new position. + // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, + // InstrMap = {X + // -> 2, Z -> 3} + // DBG_VALUE $noreg, A, .... # X + // DBG_VALUE $noreg, A, ... # Y + // %2 = ld ... + // %3 = ld ... + // DBG_VALUE %3, A, ..., # Z + // -> %4 = ld ... + + // Nothing happens for %4 and the algorithm exits having processed the entire + // Basic Block. + // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, + // InstrMap = {X + // -> 2, Z -> 3} + // DBG_VALUE $noreg, A, .... # X + // DBG_VALUE $noreg, A, ... # Y + // %2 = ld ... + // %3 = ld ... + // DBG_VALUE %3, A, ..., # Z + // %4 = ld ... + + // This map is used to track the relationship between + // a Debug Variable and the DBG_VALUE MachineInstr pointer that describes the + // debug information for that Debug Variable. + SmallDenseMap DbgValueSinkCandidates; + // This map is used to track the relationship between a DBG_VALUE or + // DBG_VALUE_LIST MachineInstr pointer and Registers that it uses. + SmallDenseMap, 8> InstrMap; + for (MBBI = MBB->begin(), E = MBB->end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + + auto PopulateRegisterAndInstrMapForDebugInstr = [&](Register Reg) { + auto RegIt = RegisterMap.find(Reg); + if (RegIt == RegisterMap.end()) + return; + auto &InstrVec = RegIt->getSecond(); + InstrVec.push_back(&MI); + InstrMap[&MI].push_back(Reg); + }; + + if (MI.isDebugValue()) { + auto *DILocalVar = MI.getDebugVariable(); + // TODO: This should not happen, have to fix the MIR verifier to check for + // such instances and fix them. + if (!DILocalVar) + continue; + DebugVariable DbgVar(DILocalVar, MI.getDebugExpression(), + MI.getDebugLoc()->getInlinedAt()); + // If the first operand is a register and it exists in the RegisterMap, we + // know this is a DBG_VALUE that uses the result of a load that was moved, + // and is therefore a candidate to also be moved, add it to the + // RegisterMap and InstrMap. + forEachDbgRegOperand(&MI, [&](MachineOperand &Op) { + PopulateRegisterAndInstrMapForDebugInstr(Op.getReg()); + }); + + // If the current DBG_VALUE describes the same variable as one of the + // in-flight DBG_VALUEs, remove the candidate from the list and set it to + // undef. Moving one DBG_VALUE past another would result in the variable's + // value going back in time when stepping through the block in the + // debugger. + auto InstrIt = DbgValueSinkCandidates.find(DbgVar); + if (InstrIt != DbgValueSinkCandidates.end()) { + auto *Instr = InstrIt->getSecond(); + auto RegIt = InstrMap.find(Instr); + if (RegIt != InstrMap.end()) { + const auto &RegVec = RegIt->getSecond(); + // For every Register in the RegVec, remove the MachineInstr in the + // RegisterMap that describes the DbgVar. + for (auto &Reg : RegVec) { + auto RegIt = RegisterMap.find(Reg); + if (RegIt == RegisterMap.end()) + continue; + auto &InstrVec = RegIt->getSecond(); + auto IsDbgVar = [&](MachineInstr *I) -> bool { + DebugVariable Var(I); + return Var == DbgVar; + }; + + InstrVec.erase( + std::remove_if(InstrVec.begin(), InstrVec.end(), IsDbgVar), + InstrVec.end()); + } + forEachDbgRegOperand(Instr, + [&](MachineOperand &Op) { Op.setReg(0); }); + } else { + // The InstrMap does not contain the MachineInstr, this could mean it + // is a MachineInstr with an immediate operand. If so, set the + // immediate operand to $noreg. + auto &Op = Instr->getOperand(0); + if (Op.isImm()) + replaceImmOperandWithUndefReg(Instr, MBB, TII); + } + } + DbgValueSinkCandidates[DbgVar] = &MI; + } else { + // If the first operand of a load matches with a DBG_VALUE in RegisterMap, + // then move that DBG_VALUE to below the load. + auto Opc = MI.getOpcode(); + if (!isLoadSingle(Opc)) + continue; + auto Reg = MI.getOperand(0).getReg(); + auto RegIt = RegisterMap.find(Reg); + if (RegIt == RegisterMap.end()) + continue; + auto &DbgInstrVec = RegIt->getSecond(); + if (!DbgInstrVec.size()) + continue; + for (auto *DbgInstr : DbgInstrVec) { + MachineBasicBlock::iterator InsertPos = std::next(MBBI); + auto *ClonedMI = MI.getMF()->CloneMachineInstr(DbgInstr); + MBB->insert(InsertPos, ClonedMI); + MBBI++; + // Erase the entry into the DbgValueSinkCandidates for the DBG_VALUE + // that was moved. + DebugVariable DbgVar(DbgInstr); + auto DbgIt = DbgValueSinkCandidates.find(DbgVar); + // If the instruction is a DBG_VALUE_LIST, it may have already been + // erased from the DbgValueSinkCandidates. Only erase if it exists in + // the DbgValueSinkCandidates. + if (DbgIt != DbgValueSinkCandidates.end()) + DbgValueSinkCandidates.erase(DbgIt); + // Zero out original dbg instr + forEachDbgRegOperand(DbgInstr, + [&](MachineOperand &Op) { Op.setReg(0); }); + // Update RegisterMap with ClonedMI because it might have to be moved + // again. + if (DbgInstr->isDebugValueList()) + updateRegisterMapForDbgValueListAfterMove(RegisterMap, ClonedMI, + DbgInstr); + } + } + } return RetVal; } Index: llvm/test/DebugInfo/ARM/move-dbg-value-after-value-list.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/ARM/move-dbg-value-after-value-list.mir @@ -0,0 +1,152 @@ +# RUN: llc %s -start-after=arm-mve-vpt-opts -stop-after=arm-prera-ldst-opt -o - | FileCheck %s +# CHECK: %5:rgpr = t2MOVCCr %3, killed %4, 0 /* CC::eq */, $cpsr, debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE_LIST !60, !DIExpression(), $noreg, $noreg, debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: %0:rgpr = t2LDRi12 %5, 0, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) +# CHECK-NEXT: %6:rgpr = t2LDRi12 %5, 4, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy) +# CHECK-NEXT: %2:gpr = t2LDRi12 %5, 8, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy_context, align 8) +# CHECK-NEXT: DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: %7:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +# CHECK-NEXT: %8:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +# CHECK-NEXT: %9:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +# CHECK-NEXT: %10:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr + +# This test specifically checks if a DBG_VALUE_LIST that is succeeded by a DBG_VALUE can be properly undefed and the DBG_VALUE is the one that is moved. Assuming both instructions describe the same local variable. +--- | + target triple = "thumbv7k-apple-watchos8.0.0" + %struct.backtrace_control = type {} + @backtrace_user.ctl_default = internal unnamed_addr constant %struct.backtrace_control zeroinitializer, !dbg !0 + define i32 @backtrace_user(ptr nocapture noundef writeonly %bt, i32 noundef %max_frames, ptr noundef readonly %ctl_in, ptr nocapture noundef readnone %info_out) local_unnamed_addr #0 !dbg !2 {entry: + %tobool.not = icmp eq ptr %ctl_in, null, !dbg !96 + %.backtrace_user.ctl_default = select i1 %tobool.not, ptr @backtrace_user.ctl_default, ptr %ctl_in, !dbg !96 + %btc_user_copy = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !99 + %btc_user_copy_context = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !101 + ret i32 undef, !dbg !125 + } + !llvm.module.flags = !{!86, !87, !88, !89, !90, !91, !92, !93} + !llvm.dbg.cu = !{!32} + !llvm.ident = !{!94} + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(scope: !2, type: !11, isDefinition: true) + !2 = distinct !DISubprogram(scope: !3, type: !4, unit: !32, retainedNodes: !38) + !3 = !DIFile(filename: "backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !4 = !DISubroutineType(types: !5) + !5 = !{!30} + !6 = !DIBasicType(name: "unsigned int", encoding: DW_ATE_unsigned) + !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32) + !8 = !DIDerivedType(tag: DW_TAG_typedef, line: 5, baseType: !9) + !9 = !DIBasicType(name: "unsigned long", encoding: DW_ATE_unsigned) + !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 32) + !11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !12) + !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !13) + !13 = !{!14, !15, !26, !27} + !14 = !DIDerivedType(tag: DW_TAG_member, baseType: !8, size: 32) + !15 = !DIDerivedType(tag: DW_TAG_member, baseType: !16, offset: 32) + !16 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !17) + !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32) + !18 = !DISubroutineType(types: !19) + !19 = !{!20, !23, !25} + !20 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !21) + !21 = !DIBasicType(encoding: DW_ATE_signed) + !22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32) + !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "user_addr_t", baseType: !24) + !24 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !6) + !25 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !9) + !26 = !DIDerivedType(tag: DW_TAG_member, baseType: !22, offset: 64) + !27 = !DIDerivedType(tag: DW_TAG_member, baseType: !28, offset: 128) + !28 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !29) + !29 = !DIBasicType() + !30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 32) + !31 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagFwdDecl) + !32 = distinct !DICompileUnit(language: DW_LANG_C11, file: !33, retainedTypes: !34, globals: !37, sdk: "MacOSX13.0.sdk") + !33 = !DIFile(filename: "/Users/shubham/Development/Delta/backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !34 = !{!35, !8} + !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 32) + !36 = !DIBasicType(encoding: DW_ATE_signed_char) + !37 = !{} + !38 = !{!39, !40, !41, !42, !43, !44, !45, !46, !47, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !78, !80, !81, !84, !85} + !39 = !DILocalVariable(scope: !2, type: !7) + !40 = !DILocalVariable(name: "max_frames", scope: !2, type: !6) + !41 = !DILocalVariable(name: "ctl_in", scope: !2, type: !10) + !42 = !DILocalVariable(scope: !2, type: !30) + !43 = !DILocalVariable(scope: !2, type: !10) + !44 = !DILocalVariable(name: "pc", scope: !2, type: !8) + !45 = !DILocalVariable(name: "next_fp", scope: !2, type: !8) + !46 = !DILocalVariable(name: "fp", scope: !2, type: !8) + !47 = !DILocalVariable(scope: !2, type: !48) + !48 = !DIBasicType(encoding: DW_ATE_boolean) + !49 = !DILocalVariable(scope: !2, type: !28) + !50 = !DILocalVariable(scope: !2, type: !6) + !51 = !DILocalVariable(scope: !2, type: !21) + !52 = !DILocalVariable(scope: !2, type: !25) + !53 = !DILocalVariable(name: "truncated", scope: !2, type: !48) + !54 = !DILocalVariable(name: "user_64", scope: !2, type: !48) + !55 = !DILocalVariable(name: "allow_async", scope: !2, type: !48) + !56 = !DILocalVariable(name: "has_async", scope: !2, type: !48) + !57 = !DILocalVariable(scope: !2, type: !8) + !58 = !DILocalVariable(name: "async_index", scope: !2, type: !6) + !59 = !DILocalVariable(scope: !2, type: !16) + !60 = !DILocalVariable(scope: !2, type: !22) + !61 = !DILocalVariable(scope: !2, type: !62) + !62 = distinct !DICompositeType(tag: DW_TAG_union_type, elements: !63) + !63 = !{!64, !72} + !64 = !DIDerivedType(tag: DW_TAG_member, baseType: !65, size: 128) + !65 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !66) + !66 = !{!67, !71} + !67 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, size: 64) + !68 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !69) + !69 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !70) + !70 = !DIBasicType(encoding: DW_ATE_unsigned) + !71 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, offset: 64) + !72 = !DIDerivedType(tag: DW_TAG_member, baseType: !73, size: 64) + !73 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !74) + !74 = !{!75, !77} + !75 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, size: 32) + !76 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !24) + !77 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, offset: 32) + !78 = !DILocalVariable(scope: !79, type: !8) + !79 = distinct !DILexicalBlock(scope: !2, line: 70, column: 46) + !80 = !DILocalVariable(scope: !79, type: !48) + !81 = !DILocalVariable(name: "async_ctx_ptr", scope: !82, type: !23) + !82 = distinct !DILexicalBlock(scope: !83, line: 80, column: 31) + !83 = distinct !DILexicalBlock(scope: !79, line: 80, column: 7) + !84 = !DILocalVariable(scope: !82, type: !23) + !85 = !DILabel(scope: !2, name: "out", file: !3, line: 102) + !86 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 0]} + !87 = !{i32 7, !"Dwarf Version", i32 4} + !88 = !{i32 2, !"Debug Info Version", i32 3} + !89 = !{i32 1, !"wchar_size", i32 4} + !90 = !{i32 1, !"min_enum_size", i32 4} + !91 = !{i32 8, !"PIC Level", i32 2} + !92 = !{i32 7, !"uwtable", i32 2} + !93 = !{i32 7, !"frame-pointer", i32 1} + !94 = !{!"clang version 16.0.0 ()"} + !95 = !DILocation(scope: !2) + !96 = !DILocation(scope: !2) + !97 = !DILocation(scope: !2) + !99 = !DILocation(scope: !2) + !101 = !DILocation(scope: !2) + !125 = !DILocation(scope: !2) +name: backtrace_user +registers: + - {id: 0, class: rgpr, } + - {id: 1, class: gpr, } + - {id: 2, class: gpr, } +body: | + bb.0.entry: + %10:rgpr = COPY $r2 + %13:rgpr = t2MOV_ga_pcrel target-flags(arm-nonlazy) @backtrace_user.ctl_default, debug-location !96 + %15:rgpr = t2MOVCCr %10, killed %13, 0 /* CC::eq */, $cpsr, debug-location !96 + DBG_VALUE 0, $noreg, !60, !DIExpression(), debug-location !95 + %0:rgpr = t2LDRi12 %15, 0, 14 /* CC::al */, $noreg, debug-location !97 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) + DBG_VALUE 1, $noreg, !60, !DIExpression(), debug-location !95 + %16:rgpr = t2LDRi12 %15, 4, 14 /* CC::al */, $noreg, debug-location !99 :: (load (s32) from %ir.btc_user_copy) + DBG_VALUE_LIST !60, !DIExpression(), %16, %0, debug-location !95 + %2:gpr = t2LDRi12 %15, 8, 14 /* CC::al */, $noreg, debug-location !101 :: (load (s32) from %ir.btc_user_copy_context, align 8) + DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 + %31:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + %32:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + %33:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + %34:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr \ No newline at end of file Index: llvm/test/DebugInfo/ARM/move-dbg-value-lists.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/ARM/move-dbg-value-lists.mir @@ -0,0 +1,145 @@ +# RUN: llc %s -start-after=arm-mve-vpt-opts -stop-after=arm-prera-ldst-opt -o - | FileCheck %s +# CHECK: %5:rgpr = t2MOVCCr %3, killed %4, 0 /* CC::eq */, $cpsr, debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE_LIST !60, !DIExpression(), $noreg, $noreg, debug-location !95 +# CHECK-NEXT: %0:rgpr = t2LDRi12 %5, 0, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) +# CHECK-NEXT: DBG_VALUE_LIST !60, !DIExpression(), $noreg, $noreg, debug-location !95 +# CHECK-NEXT: %6:rgpr = t2LDRi12 %5, 4, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy) +# CHECK-NEXT: DBG_VALUE_LIST !60, !DIExpression(), %6, %0, debug-location !95 +# CHECK-NEXT: %2:gpr = t2LDRi12 %5, 8, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy_context, align 8) +# CHECK-NEXT: %7:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +# CHECK-NEXT: DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 +--- | + target triple = "thumbv7k-apple-watchos8.0.0" + %struct.backtrace_control = type {} + @backtrace_user.ctl_default = internal unnamed_addr constant %struct.backtrace_control zeroinitializer, !dbg !0 + define i32 @backtrace_user(ptr nocapture noundef writeonly %bt, i32 noundef %max_frames, ptr noundef readonly %ctl_in, ptr nocapture noundef readnone %info_out) local_unnamed_addr #0 !dbg !2 {entry: + %tobool.not = icmp eq ptr %ctl_in, null, !dbg !96 + %.backtrace_user.ctl_default = select i1 %tobool.not, ptr @backtrace_user.ctl_default, ptr %ctl_in, !dbg !96 + %btc_user_copy = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !99 + %btc_user_copy_context = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !101 + ret i32 undef, !dbg !125 + } + !llvm.module.flags = !{!86, !87, !88, !89, !90, !91, !92, !93} + !llvm.dbg.cu = !{!32} + !llvm.ident = !{!94} + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(scope: !2, type: !11, isDefinition: true) + !2 = distinct !DISubprogram(scope: !3, type: !4, unit: !32, retainedNodes: !38) + !3 = !DIFile(filename: "backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !4 = !DISubroutineType(types: !5) + !5 = !{!30} + !6 = !DIBasicType(name: "unsigned int", encoding: DW_ATE_unsigned) + !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32) + !8 = !DIDerivedType(tag: DW_TAG_typedef, line: 5, baseType: !9) + !9 = !DIBasicType(name: "unsigned long", encoding: DW_ATE_unsigned) + !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 32) + !11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !12) + !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !13) + !13 = !{!14, !15, !26, !27} + !14 = !DIDerivedType(tag: DW_TAG_member, baseType: !8, size: 32) + !15 = !DIDerivedType(tag: DW_TAG_member, baseType: !16, offset: 32) + !16 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !17) + !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32) + !18 = !DISubroutineType(types: !19) + !19 = !{!20, !23, !25} + !20 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !21) + !21 = !DIBasicType(encoding: DW_ATE_signed) + !22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32) + !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "user_addr_t", baseType: !24) + !24 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !6) + !25 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !9) + !26 = !DIDerivedType(tag: DW_TAG_member, baseType: !22, offset: 64) + !27 = !DIDerivedType(tag: DW_TAG_member, baseType: !28, offset: 128) + !28 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !29) + !29 = !DIBasicType() + !30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 32) + !31 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagFwdDecl) + !32 = distinct !DICompileUnit(language: DW_LANG_C11, file: !33, retainedTypes: !34, globals: !37, sdk: "MacOSX13.0.sdk") + !33 = !DIFile(filename: "/Users/shubham/Development/Delta/backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !34 = !{!35, !8} + !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 32) + !36 = !DIBasicType(encoding: DW_ATE_signed_char) + !37 = !{} + !38 = !{!39, !40, !41, !42, !43, !44, !45, !46, !47, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !78, !80, !81, !84, !85} + !39 = !DILocalVariable(scope: !2, type: !7) + !40 = !DILocalVariable(name: "max_frames", scope: !2, type: !6) + !41 = !DILocalVariable(name: "ctl_in", scope: !2, type: !10) + !42 = !DILocalVariable(scope: !2, type: !30) + !43 = !DILocalVariable(scope: !2, type: !10) + !44 = !DILocalVariable(name: "pc", scope: !2, type: !8) + !45 = !DILocalVariable(name: "next_fp", scope: !2, type: !8) + !46 = !DILocalVariable(name: "fp", scope: !2, type: !8) + !47 = !DILocalVariable(scope: !2, type: !48) + !48 = !DIBasicType(encoding: DW_ATE_boolean) + !49 = !DILocalVariable(scope: !2, type: !28) + !50 = !DILocalVariable(scope: !2, type: !6) + !51 = !DILocalVariable(scope: !2, type: !21) + !52 = !DILocalVariable(scope: !2, type: !25) + !53 = !DILocalVariable(name: "truncated", scope: !2, type: !48) + !54 = !DILocalVariable(name: "user_64", scope: !2, type: !48) + !55 = !DILocalVariable(name: "allow_async", scope: !2, type: !48) + !56 = !DILocalVariable(name: "has_async", scope: !2, type: !48) + !57 = !DILocalVariable(scope: !2, type: !8) + !58 = !DILocalVariable(name: "async_index", scope: !2, type: !6) + !59 = !DILocalVariable(scope: !2, type: !16) + !60 = !DILocalVariable(scope: !2, type: !22) + !61 = !DILocalVariable(scope: !2, type: !62) + !62 = distinct !DICompositeType(tag: DW_TAG_union_type, elements: !63) + !63 = !{!64, !72} + !64 = !DIDerivedType(tag: DW_TAG_member, baseType: !65, size: 128) + !65 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !66) + !66 = !{!67, !71} + !67 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, size: 64) + !68 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !69) + !69 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !70) + !70 = !DIBasicType(encoding: DW_ATE_unsigned) + !71 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, offset: 64) + !72 = !DIDerivedType(tag: DW_TAG_member, baseType: !73, size: 64) + !73 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !74) + !74 = !{!75, !77} + !75 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, size: 32) + !76 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !24) + !77 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, offset: 32) + !78 = !DILocalVariable(scope: !79, type: !8) + !79 = distinct !DILexicalBlock(scope: !2, line: 70, column: 46) + !80 = !DILocalVariable(scope: !79, type: !48) + !81 = !DILocalVariable(name: "async_ctx_ptr", scope: !82, type: !23) + !82 = distinct !DILexicalBlock(scope: !83, line: 80, column: 31) + !83 = distinct !DILexicalBlock(scope: !79, line: 80, column: 7) + !84 = !DILocalVariable(scope: !82, type: !23) + !85 = !DILabel(scope: !2, name: "out", file: !3, line: 102) + !86 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 0]} + !87 = !{i32 7, !"Dwarf Version", i32 4} + !88 = !{i32 2, !"Debug Info Version", i32 3} + !89 = !{i32 1, !"wchar_size", i32 4} + !90 = !{i32 1, !"min_enum_size", i32 4} + !91 = !{i32 8, !"PIC Level", i32 2} + !92 = !{i32 7, !"uwtable", i32 2} + !93 = !{i32 7, !"frame-pointer", i32 1} + !94 = !{!"clang version 16.0.0 ()"} + !95 = !DILocation(scope: !2) + !96 = !DILocation(scope: !2) + !97 = !DILocation(scope: !2) + !99 = !DILocation(scope: !2) + !101 = !DILocation(scope: !2) + !125 = !DILocation(scope: !2) +name: backtrace_user +registers: + - {id: 0, class: rgpr, } + - {id: 1, class: gpr, } + - {id: 2, class: gpr, } +body: | + bb.0.entry: + %10:rgpr = COPY $r2 + %13:rgpr = t2MOV_ga_pcrel target-flags(arm-nonlazy) @backtrace_user.ctl_default, debug-location !96 + %15:rgpr = t2MOVCCr %10, killed %13, 0 /* CC::eq */, $cpsr, debug-location !96 + DBG_VALUE 0, $noreg, !60, !DIExpression(), debug-location !95 + %0:rgpr = t2LDRi12 %15, 0, 14 /* CC::al */, $noreg, debug-location !97 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) + DBG_VALUE 1, $noreg, !60, !DIExpression(), debug-location !95 + %16:rgpr = t2LDRi12 %15, 4, 14 /* CC::al */, $noreg, debug-location !99 :: (load (s32) from %ir.btc_user_copy) + DBG_VALUE_LIST !60, !DIExpression(), %16, %0, debug-location !95 + %2:gpr = t2LDRi12 %15, 8, 14 /* CC::al */, $noreg, debug-location !101 :: (load (s32) from %ir.btc_user_copy_context, align 8) + %31:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 \ No newline at end of file Index: llvm/test/DebugInfo/ARM/move-dbg-value-same-reg.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/ARM/move-dbg-value-same-reg.mir @@ -0,0 +1,148 @@ +# RUN: llc %s -start-after=arm-mve-vpt-opts -stop-after=arm-prera-ldst-opt -o - | FileCheck %s +#CHECK: %5:rgpr = t2MOVCCr %3, killed %4, 0 /* CC::eq */, $cpsr, debug-location !95 +#CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +#CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +#CHECK-NEXT: DBG_VALUE $noreg, $noreg, !59, !DIExpression(), debug-location !95 +#CHECK-NEXT: %0:rgpr = t2LDRi12 %5, 0, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) +#CHECK-NEXT: DBG_VALUE %0, $noreg, !60, !DIExpression(), debug-location !95 +#CHECK-NEXT: DBG_VALUE %0, $noreg, !59, !DIExpression(), debug-location !95 +#CHECK-NEXT: %6:rgpr = t2LDRi12 %5, 4, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy) +#CHECK-NEXT: %2:gpr = t2LDRi12 %5, 8, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy_context, align 8) +#CHECK-NEXT: %7:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +#CHECK-NEXT: DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 + +# This test checks the case where two DBG_VALUEs share the same virtual register but describe different local variables. + +--- | + target triple = "thumbv7k-apple-watchos8.0.0" + %struct.backtrace_control = type {} + @backtrace_user.ctl_default = internal unnamed_addr constant %struct.backtrace_control zeroinitializer, !dbg !0 + define i32 @backtrace_user(ptr nocapture noundef writeonly %bt, i32 noundef %max_frames, ptr noundef readonly %ctl_in, ptr nocapture noundef readnone %info_out) local_unnamed_addr #0 !dbg !2 {entry: + %tobool.not = icmp eq ptr %ctl_in, null, !dbg !96 + %.backtrace_user.ctl_default = select i1 %tobool.not, ptr @backtrace_user.ctl_default, ptr %ctl_in, !dbg !96 + %btc_user_copy = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !99 + %btc_user_copy_context = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !101 + ret i32 undef, !dbg !125 + } + !llvm.module.flags = !{!86, !87, !88, !89, !90, !91, !92, !93} + !llvm.dbg.cu = !{!32} + !llvm.ident = !{!94} + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(scope: !2, type: !11, isDefinition: true) + !2 = distinct !DISubprogram(scope: !3, type: !4, unit: !32, retainedNodes: !38) + !3 = !DIFile(filename: "backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !4 = !DISubroutineType(types: !5) + !5 = !{!30} + !6 = !DIBasicType(name: "unsigned int", encoding: DW_ATE_unsigned) + !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32) + !8 = !DIDerivedType(tag: DW_TAG_typedef, line: 5, baseType: !9) + !9 = !DIBasicType(name: "unsigned long", encoding: DW_ATE_unsigned) + !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 32) + !11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !12) + !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !13) + !13 = !{!14, !15, !26, !27} + !14 = !DIDerivedType(tag: DW_TAG_member, baseType: !8, size: 32) + !15 = !DIDerivedType(tag: DW_TAG_member, baseType: !16, offset: 32) + !16 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !17) + !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32) + !18 = !DISubroutineType(types: !19) + !19 = !{!20, !23, !25} + !20 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !21) + !21 = !DIBasicType(encoding: DW_ATE_signed) + !22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32) + !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "user_addr_t", baseType: !24) + !24 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !6) + !25 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !9) + !26 = !DIDerivedType(tag: DW_TAG_member, baseType: !22, offset: 64) + !27 = !DIDerivedType(tag: DW_TAG_member, baseType: !28, offset: 128) + !28 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !29) + !29 = !DIBasicType() + !30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 32) + !31 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagFwdDecl) + !32 = distinct !DICompileUnit(language: DW_LANG_C11, file: !33, retainedTypes: !34, globals: !37, sdk: "MacOSX13.0.sdk") + !33 = !DIFile(filename: "/Users/shubham/Development/Delta/backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !34 = !{!35, !8} + !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 32) + !36 = !DIBasicType(encoding: DW_ATE_signed_char) + !37 = !{} + !38 = !{!39, !40, !41, !42, !43, !44, !45, !46, !47, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !78, !80, !81, !84, !85} + !39 = !DILocalVariable(scope: !2, type: !7) + !40 = !DILocalVariable(name: "max_frames", scope: !2, type: !6) + !41 = !DILocalVariable(name: "ctl_in", scope: !2, type: !10) + !42 = !DILocalVariable(scope: !2, type: !30) + !43 = !DILocalVariable(scope: !2, type: !10) + !44 = !DILocalVariable(name: "pc", scope: !2, type: !8) + !45 = !DILocalVariable(name: "next_fp", scope: !2, type: !8) + !46 = !DILocalVariable(name: "fp", scope: !2, type: !8) + !47 = !DILocalVariable(scope: !2, type: !48) + !48 = !DIBasicType(encoding: DW_ATE_boolean) + !49 = !DILocalVariable(scope: !2, type: !28) + !50 = !DILocalVariable(scope: !2, type: !6) + !51 = !DILocalVariable(scope: !2, type: !21) + !52 = !DILocalVariable(scope: !2, type: !25) + !53 = !DILocalVariable(name: "truncated", scope: !2, type: !48) + !54 = !DILocalVariable(name: "user_64", scope: !2, type: !48) + !55 = !DILocalVariable(name: "allow_async", scope: !2, type: !48) + !56 = !DILocalVariable(name: "has_async", scope: !2, type: !48) + !57 = !DILocalVariable(scope: !2, type: !8) + !58 = !DILocalVariable(name: "async_index", scope: !2, type: !6) + !59 = !DILocalVariable(scope: !2, type: !16) + !60 = !DILocalVariable(scope: !2, type: !22) + !61 = !DILocalVariable(scope: !2, type: !62) + !62 = distinct !DICompositeType(tag: DW_TAG_union_type, elements: !63) + !63 = !{!64, !72} + !64 = !DIDerivedType(tag: DW_TAG_member, baseType: !65, size: 128) + !65 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !66) + !66 = !{!67, !71} + !67 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, size: 64) + !68 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !69) + !69 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !70) + !70 = !DIBasicType(encoding: DW_ATE_unsigned) + !71 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, offset: 64) + !72 = !DIDerivedType(tag: DW_TAG_member, baseType: !73, size: 64) + !73 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !74) + !74 = !{!75, !77} + !75 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, size: 32) + !76 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !24) + !77 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, offset: 32) + !78 = !DILocalVariable(scope: !79, type: !8) + !79 = distinct !DILexicalBlock(scope: !2, line: 70, column: 46) + !80 = !DILocalVariable(scope: !79, type: !48) + !81 = !DILocalVariable(name: "async_ctx_ptr", scope: !82, type: !23) + !82 = distinct !DILexicalBlock(scope: !83, line: 80, column: 31) + !83 = distinct !DILexicalBlock(scope: !79, line: 80, column: 7) + !84 = !DILocalVariable(scope: !82, type: !23) + !85 = !DILabel(scope: !2, name: "out", file: !3, line: 102) + !86 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 0]} + !87 = !{i32 7, !"Dwarf Version", i32 4} + !88 = !{i32 2, !"Debug Info Version", i32 3} + !89 = !{i32 1, !"wchar_size", i32 4} + !90 = !{i32 1, !"min_enum_size", i32 4} + !91 = !{i32 8, !"PIC Level", i32 2} + !92 = !{i32 7, !"uwtable", i32 2} + !93 = !{i32 7, !"frame-pointer", i32 1} + !94 = !{!"clang version 16.0.0 ()"} + !95 = !DILocation(scope: !2) + !96 = !DILocation(scope: !2) + !97 = !DILocation(scope: !2) + !99 = !DILocation(scope: !2) + !101 = !DILocation(scope: !2) + !125 = !DILocation(scope: !2) +name: backtrace_user +registers: + - {id: 0, class: rgpr, } + - {id: 1, class: gpr, } + - {id: 2, class: gpr, } +body: | + bb.0.entry: + %10:rgpr = COPY $r2 + %13:rgpr = t2MOV_ga_pcrel target-flags(arm-nonlazy) @backtrace_user.ctl_default, debug-location !96 + %15:rgpr = t2MOVCCr %10, killed %13, 0 /* CC::eq */, $cpsr, debug-location !96 + DBG_VALUE 0, $noreg, !60, !DIExpression(), debug-location !95 + %0:rgpr = t2LDRi12 %15, 0, 14 /* CC::al */, $noreg, debug-location !97 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) + DBG_VALUE %0, $noreg, !60, !DIExpression(), debug-location !95 + DBG_VALUE %0, $noreg, !59, !DIExpression(), debug-location !95 + %16:rgpr = t2LDRi12 %15, 4, 14 /* CC::al */, $noreg, debug-location !99 :: (load (s32) from %ir.btc_user_copy) + %2:gpr = t2LDRi12 %15, 8, 14 /* CC::al */, $noreg, debug-location !101 :: (load (s32) from %ir.btc_user_copy_context, align 8) + %31:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 \ No newline at end of file Index: llvm/test/DebugInfo/ARM/move-dbg-values.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/ARM/move-dbg-values.mir @@ -0,0 +1,144 @@ +# RUN: llc %s -start-after=arm-mve-vpt-opts -stop-after=arm-prera-ldst-opt -o - | FileCheck %s +# CHECK: %5:rgpr = t2MOVCCr %3, killed %4, 0 /* CC::eq */, $cpsr, debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: DBG_VALUE $noreg, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: %0:rgpr = t2LDRi12 %5, 0, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) +# CHECK-NEXT: %6:rgpr = t2LDRi12 %5, 4, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy) +# CHECK-NEXT: DBG_VALUE %6, $noreg, !60, !DIExpression(), debug-location !95 +# CHECK-NEXT: %2:gpr = t2LDRi12 %5, 8, 14 /* CC::al */, $noreg, debug-location !95 :: (load (s32) from %ir.btc_user_copy_context, align 8) +# CHECK-NEXT: %7:rgpr = t2ANDrr %6, %0, 14 /* CC::al */, $noreg, def $cpsr +# CHECK-NEXT: DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 +--- | + target triple = "thumbv7k-apple-watchos8.0.0" + %struct.backtrace_control = type {} + @backtrace_user.ctl_default = internal unnamed_addr constant %struct.backtrace_control zeroinitializer, !dbg !0 + define i32 @backtrace_user(ptr nocapture noundef writeonly %bt, i32 noundef %max_frames, ptr noundef readonly %ctl_in, ptr nocapture noundef readnone %info_out) local_unnamed_addr #0 !dbg !2 {entry: + %tobool.not = icmp eq ptr %ctl_in, null, !dbg !96 + %.backtrace_user.ctl_default = select i1 %tobool.not, ptr @backtrace_user.ctl_default, ptr %ctl_in, !dbg !96 + %btc_user_copy = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !99 + %btc_user_copy_context = getelementptr inbounds %struct.backtrace_control, ptr %.backtrace_user.ctl_default, !dbg !101 + ret i32 undef, !dbg !125 + } + !llvm.module.flags = !{!86, !87, !88, !89, !90, !91, !92, !93} + !llvm.dbg.cu = !{!32} + !llvm.ident = !{!94} + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(scope: !2, type: !11, isDefinition: true) + !2 = distinct !DISubprogram(scope: !3, type: !4, unit: !32, retainedNodes: !38) + !3 = !DIFile(filename: "backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !4 = !DISubroutineType(types: !5) + !5 = !{!30} + !6 = !DIBasicType(name: "unsigned int", encoding: DW_ATE_unsigned) + !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32) + !8 = !DIDerivedType(tag: DW_TAG_typedef, line: 5, baseType: !9) + !9 = !DIBasicType(name: "unsigned long", encoding: DW_ATE_unsigned) + !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 32) + !11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !12) + !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !13) + !13 = !{!14, !15, !26, !27} + !14 = !DIDerivedType(tag: DW_TAG_member, baseType: !8, size: 32) + !15 = !DIDerivedType(tag: DW_TAG_member, baseType: !16, offset: 32) + !16 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !17) + !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32) + !18 = !DISubroutineType(types: !19) + !19 = !{!20, !23, !25} + !20 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !21) + !21 = !DIBasicType(encoding: DW_ATE_signed) + !22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32) + !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "user_addr_t", baseType: !24) + !24 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !6) + !25 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !9) + !26 = !DIDerivedType(tag: DW_TAG_member, baseType: !22, offset: 64) + !27 = !DIDerivedType(tag: DW_TAG_member, baseType: !28, offset: 128) + !28 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !29) + !29 = !DIBasicType() + !30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 32) + !31 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagFwdDecl) + !32 = distinct !DICompileUnit(language: DW_LANG_C11, file: !33, retainedTypes: !34, globals: !37, sdk: "MacOSX13.0.sdk") + !33 = !DIFile(filename: "/Users/shubham/Development/Delta/backtrace.pp.c", directory: "/Users/shubham/Development/Delta") + !34 = !{!35, !8} + !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 32) + !36 = !DIBasicType(encoding: DW_ATE_signed_char) + !37 = !{} + !38 = !{!39, !40, !41, !42, !43, !44, !45, !46, !47, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !78, !80, !81, !84, !85} + !39 = !DILocalVariable(scope: !2, type: !7) + !40 = !DILocalVariable(name: "max_frames", scope: !2, type: !6) + !41 = !DILocalVariable(name: "ctl_in", scope: !2, type: !10) + !42 = !DILocalVariable(scope: !2, type: !30) + !43 = !DILocalVariable(scope: !2, type: !10) + !44 = !DILocalVariable(name: "pc", scope: !2, type: !8) + !45 = !DILocalVariable(name: "next_fp", scope: !2, type: !8) + !46 = !DILocalVariable(name: "fp", scope: !2, type: !8) + !47 = !DILocalVariable(scope: !2, type: !48) + !48 = !DIBasicType(encoding: DW_ATE_boolean) + !49 = !DILocalVariable(scope: !2, type: !28) + !50 = !DILocalVariable(scope: !2, type: !6) + !51 = !DILocalVariable(scope: !2, type: !21) + !52 = !DILocalVariable(scope: !2, type: !25) + !53 = !DILocalVariable(name: "truncated", scope: !2, type: !48) + !54 = !DILocalVariable(name: "user_64", scope: !2, type: !48) + !55 = !DILocalVariable(name: "allow_async", scope: !2, type: !48) + !56 = !DILocalVariable(name: "has_async", scope: !2, type: !48) + !57 = !DILocalVariable(scope: !2, type: !8) + !58 = !DILocalVariable(name: "async_index", scope: !2, type: !6) + !59 = !DILocalVariable(scope: !2, type: !16) + !60 = !DILocalVariable(scope: !2, type: !22) + !61 = !DILocalVariable(scope: !2, type: !62) + !62 = distinct !DICompositeType(tag: DW_TAG_union_type, elements: !63) + !63 = !{!64, !72} + !64 = !DIDerivedType(tag: DW_TAG_member, baseType: !65, size: 128) + !65 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !66) + !66 = !{!67, !71} + !67 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, size: 64) + !68 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !69) + !69 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !70) + !70 = !DIBasicType(encoding: DW_ATE_unsigned) + !71 = !DIDerivedType(tag: DW_TAG_member, baseType: !68, offset: 64) + !72 = !DIDerivedType(tag: DW_TAG_member, baseType: !73, size: 64) + !73 = distinct !DICompositeType(tag: DW_TAG_structure_type, elements: !74) + !74 = !{!75, !77} + !75 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, size: 32) + !76 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !24) + !77 = !DIDerivedType(tag: DW_TAG_member, baseType: !76, offset: 32) + !78 = !DILocalVariable(scope: !79, type: !8) + !79 = distinct !DILexicalBlock(scope: !2, line: 70, column: 46) + !80 = !DILocalVariable(scope: !79, type: !48) + !81 = !DILocalVariable(name: "async_ctx_ptr", scope: !82, type: !23) + !82 = distinct !DILexicalBlock(scope: !83, line: 80, column: 31) + !83 = distinct !DILexicalBlock(scope: !79, line: 80, column: 7) + !84 = !DILocalVariable(scope: !82, type: !23) + !85 = !DILabel(scope: !2, name: "out", file: !3, line: 102) + !86 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 0]} + !87 = !{i32 7, !"Dwarf Version", i32 4} + !88 = !{i32 2, !"Debug Info Version", i32 3} + !89 = !{i32 1, !"wchar_size", i32 4} + !90 = !{i32 1, !"min_enum_size", i32 4} + !91 = !{i32 8, !"PIC Level", i32 2} + !92 = !{i32 7, !"uwtable", i32 2} + !93 = !{i32 7, !"frame-pointer", i32 1} + !94 = !{!"clang version 16.0.0 ()"} + !95 = !DILocation(scope: !2) + !96 = !DILocation(scope: !2) + !97 = !DILocation(scope: !2) + !99 = !DILocation(scope: !2) + !101 = !DILocation(scope: !2) + !125 = !DILocation(scope: !2) +name: backtrace_user +registers: + - {id: 0, class: rgpr, } + - {id: 1, class: gpr, } + - {id: 2, class: gpr, } +body: | + bb.0.entry: + %10:rgpr = COPY $r2 + %13:rgpr = t2MOV_ga_pcrel target-flags(arm-nonlazy) @backtrace_user.ctl_default, debug-location !96 + %15:rgpr = t2MOVCCr %10, killed %13, 0 /* CC::eq */, $cpsr, debug-location !96 + DBG_VALUE 0, $noreg, !60, !DIExpression(), debug-location !95 + %0:rgpr = t2LDRi12 %15, 0, 14 /* CC::al */, $noreg, debug-location !97 :: (load (s32) from %ir..backtrace_user.ctl_default, align 8) + DBG_VALUE %0, $noreg, !60, !DIExpression(), debug-location !95 + %16:rgpr = t2LDRi12 %15, 4, 14 /* CC::al */, $noreg, debug-location !99 :: (load (s32) from %ir.btc_user_copy) + DBG_VALUE %16, $noreg, !60, !DIExpression(), debug-location !95 + %2:gpr = t2LDRi12 %15, 8, 14 /* CC::al */, $noreg, debug-location !101 :: (load (s32) from %ir.btc_user_copy_context, align 8) + %31:rgpr = t2ANDrr %16, %0, 14 /* CC::al */, $noreg, def $cpsr + DBG_VALUE %2, $noreg, !60, !DIExpression(), debug-location !95 \ No newline at end of file