diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h @@ -934,10 +934,11 @@ LLVM_DUMP_METHOD void dump_mloc_map(); #endif - /// Create a DBG_VALUE based on machine location \p MLoc. Qualify it with the + /// Create a DBG_VALUE based on debug operands \p DbgOps. Qualify it with the /// information in \pProperties, for variable Var. Don't insert it anywhere, /// just return the builder for it. - MachineInstrBuilder emitLoc(Optional MLoc, const DebugVariable &Var, + MachineInstrBuilder emitLoc(const SmallVectorImpl &DbgOps, + const DebugVariable &Var, const DbgValueProperties &Properties); }; diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -351,8 +351,10 @@ if (!Result.second) Result.first->second = NewValue; ActiveMLocs[M].insert(Var.first); + SmallVector ResolvedOps; + ResolvedOps.push_back(M); PendingDbgValues.push_back( - MTracker->emitLoc(M, Var.first, Var.second.Properties)); + MTracker->emitLoc(ResolvedOps, Var.first, Var.second.Properties)); } flushDbgValues(MBB.begin(), &MBB); } @@ -390,7 +392,10 @@ if (!UseBeforeDefVariables.count(Use.Var)) continue; - PendingDbgValues.push_back(MTracker->emitLoc(L, Use.Var, Use.Properties)); + SmallVector ResolvedOps; + ResolvedOps.push_back(L); + PendingDbgValues.push_back( + MTracker->emitLoc(ResolvedOps, Use.Var, Use.Properties)); } flushDbgValues(pos, nullptr); } @@ -589,7 +594,11 @@ // is None and a $noreg DBG_VALUE will be created. Otherwise, a DBG_VALUE // identifying the alternative location will be emitted. const DbgValueProperties &Properties = ActiveVLocIt->second.Properties; - PendingDbgValues.push_back(MTracker->emitLoc(NewLoc, Var, Properties)); + SmallVector ResolvedOps; + if (NewLoc) + ResolvedOps.push_back(*NewLoc); + PendingDbgValues.push_back( + MTracker->emitLoc(ResolvedOps, Var, Properties)); // Update machine locations <=> variable locations maps. Defer updating // ActiveMLocs to avoid invalidaing the ActiveMLocIt iterator. @@ -641,8 +650,10 @@ assert(ActiveVLocIt != ActiveVLocs.end()); ActiveVLocIt->second.Loc = Dst; + SmallVector ResolvedOps; + ResolvedOps.push_back(Dst); MachineInstr *MI = - MTracker->emitLoc(Dst, Var, ActiveVLocIt->second.Properties); + MTracker->emitLoc(ResolvedOps, Var, ActiveVLocIt->second.Properties); PendingDbgValues.push_back(MI); } ActiveMLocs[Src].clear(); @@ -892,9 +903,10 @@ } #endif -MachineInstrBuilder MLocTracker::emitLoc(Optional MLoc, - const DebugVariable &Var, - const DbgValueProperties &Properties) { +MachineInstrBuilder +MLocTracker::emitLoc(const SmallVectorImpl &DbgOps, + const DebugVariable &Var, + const DbgValueProperties &Properties) { DebugLoc DL = DILocation::get(Var.getVariable()->getContext(), 0, 0, Var.getVariable()->getScope(), const_cast(Var.getInlinedAt())); @@ -903,6 +915,17 @@ ? TII.get(TargetOpcode::DBG_VALUE_LIST) : TII.get(TargetOpcode::DBG_VALUE); +#ifdef EXPENSIVE_CHECKS + assert(all_of(DbgOps, + [](const ResolvedDbgOp &Op) { + return Op.IsConst || !Op.Loc.isIllegal(); + }) && + "Did not expect illegal ops in DbgOps."); + assert((DbgOps.size() == 0 || + DbgOps.size() == Properties.getLocationOpCount()) && + "Expected to have either one DbgOp per MI LocationOp, or none."); +#endif + auto GetRegOp = [](unsigned Reg) -> MachineOperand { return MachineOperand::CreateReg( /* Reg */ Reg, /* isDef */ false, /* isImp */ false, @@ -920,104 +943,114 @@ Properties.DIExpr); }; - // Only 1 location is currently supported. - if (Properties.IsVariadic && Properties.getLocationOpCount() != 1) + // Don't bother passing any real operands to BuildMI if any of them would be + // $noreg. + if (DbgOps.empty()) return EmitUndef(); bool Indirect = Properties.Indirect; const DIExpression *Expr = Properties.DIExpr; - if (!MLoc) { - // No location -> DBG_VALUE $noreg - return EmitUndef(); - } else if (LocIdxToLocID[*MLoc] >= NumRegs) { - unsigned LocID = LocIdxToLocID[*MLoc]; - SpillLocationNo SpillID = locIDToSpill(LocID); - StackSlotPos StackIdx = locIDToSpillIdx(LocID); - unsigned short Offset = StackIdx.second; - - // TODO: support variables that are located in spill slots, with non-zero - // offsets from the start of the spill slot. It would require some more - // complex DIExpression calculations. This doesn't seem to be produced by - // LLVM right now, so don't try and support it. - // Accept no-subregister slots and subregisters where the offset is zero. - // The consumer should already have type information to work out how large - // the variable is. - if (Offset == 0) { - const SpillLoc &Spill = SpillLocs[SpillID.id()]; - unsigned Base = Spill.SpillBase; - MOs.push_back(GetRegOp(Base)); - - // There are several ways we can dereference things, and several inputs - // to consider: - // * NRVO variables will appear with IsIndirect set, but should have - // nothing else in their DIExpressions, - // * Variables with DW_OP_stack_value in their expr already need an - // explicit dereference of the stack location, - // * Values that don't match the variable size need DW_OP_deref_size, - // * Everything else can just become a simple location expression. - - // We need to use deref_size whenever there's a mismatch between the - // size of value and the size of variable portion being read. - // Additionally, we should use it whenever dealing with stack_value - // fragments, to avoid the consumer having to determine the deref size - // from DW_OP_piece. - bool UseDerefSize = false; - unsigned ValueSizeInBits = getLocSizeInBits(*MLoc); - unsigned DerefSizeInBytes = ValueSizeInBits / 8; - if (auto Fragment = Var.getFragment()) { - unsigned VariableSizeInBits = Fragment->SizeInBits; - if (VariableSizeInBits != ValueSizeInBits || Expr->isComplex()) - UseDerefSize = true; - } else if (auto Size = Var.getVariable()->getSizeInBits()) { - if (*Size != ValueSizeInBits) { - UseDerefSize = true; + + assert(DbgOps.size() == Properties.getLocationOpCount()); + + // If all locations are valid, accumulate them into our list of + // MachineOperands. For any spilled locations, either update the indirectness + // register or apply the appropriate transformations in the DIExpression. + for (size_t Idx = 0; Idx < Properties.getLocationOpCount(); ++Idx) { + const ResolvedDbgOp &Op = DbgOps[Idx]; + + if (Op.IsConst) { + MOs.push_back(Op.MO); + continue; + } + + LocIdx MLoc = Op.Loc; + unsigned LocID = LocIdxToLocID[MLoc]; + if (LocID >= NumRegs) { + SpillLocationNo SpillID = locIDToSpill(LocID); + StackSlotPos StackIdx = locIDToSpillIdx(LocID); + unsigned short Offset = StackIdx.second; + + // TODO: support variables that are located in spill slots, with non-zero + // offsets from the start of the spill slot. It would require some more + // complex DIExpression calculations. This doesn't seem to be produced by + // LLVM right now, so don't try and support it. + // Accept no-subregister slots and subregisters where the offset is zero. + // The consumer should already have type information to work out how large + // the variable is. + if (Offset == 0) { + const SpillLoc &Spill = SpillLocs[SpillID.id()]; + unsigned Base = Spill.SpillBase; + + // There are several ways we can dereference things, and several inputs + // to consider: + // * NRVO variables will appear with IsIndirect set, but should have + // nothing else in their DIExpressions, + // * Variables with DW_OP_stack_value in their expr already need an + // explicit dereference of the stack location, + // * Values that don't match the variable size need DW_OP_deref_size, + // * Everything else can just become a simple location expression. + + // We need to use deref_size whenever there's a mismatch between the + // size of value and the size of variable portion being read. + // Additionally, we should use it whenever dealing with stack_value + // fragments, to avoid the consumer having to determine the deref size + // from DW_OP_piece. + bool UseDerefSize = false; + unsigned ValueSizeInBits = getLocSizeInBits(MLoc); + unsigned DerefSizeInBytes = ValueSizeInBits / 8; + if (auto Fragment = Var.getFragment()) { + unsigned VariableSizeInBits = Fragment->SizeInBits; + if (VariableSizeInBits != ValueSizeInBits || Expr->isComplex()) + UseDerefSize = true; + } else if (auto Size = Var.getVariable()->getSizeInBits()) { + if (*Size != ValueSizeInBits) { + UseDerefSize = true; + } } - } - if (Properties.Indirect) { - // This is something like an NRVO variable, where the pointer has been - // spilt to the stack, or a dbg.addr pointing at a coroutine frame - // field. It should end up being a memory location, with the pointer - // to the variable loaded off the stack with a deref. It can't be a - // DW_OP_stack_value expression. - assert(!Expr->isImplicit()); - Expr = TRI.prependOffsetExpression( - Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, - Spill.SpillOffset); - } else if (UseDerefSize) { - // We're loading a value off the stack that's not the same size as the - // variable. Add / subtract stack offset, explicitly deref with a size, - // and add DW_OP_stack_value if not already present. - SmallVector Ops = {dwarf::DW_OP_deref_size, - DerefSizeInBytes}; - Expr = DIExpression::prependOpcodes(Expr, Ops, true); - unsigned Flags = DIExpression::StackValue | DIExpression::ApplyOffset; - Expr = TRI.prependOffsetExpression(Expr, Flags, Spill.SpillOffset); - } else if (Expr->isComplex()) { - // A variable with no size ambiguity, but with extra elements in it's - // expression. Manually dereference the stack location. - assert(Expr->isComplex()); - Expr = TRI.prependOffsetExpression( - Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, - Spill.SpillOffset); + SmallVector OffsetOps; + TRI.getOffsetOpcodes(Spill.SpillOffset, OffsetOps); + bool StackValue = false; + + if (Properties.Indirect) { + // This is something like an NRVO variable, where the pointer has been + // spilt to the stack. It should end up being a memory location, with + // the pointer to the variable loaded off the stack with a deref: + assert(!Expr->isImplicit()); + OffsetOps.push_back(dwarf::DW_OP_deref); + } else if (UseDerefSize && !Properties.IsVariadic) { + // TODO: Figure out how to handle deref size issues for variadic + // values. + // We're loading a value off the stack that's not the same size as the + // variable. Add / subtract stack offset, explicitly deref with a + // size, and add DW_OP_stack_value if not already present. + OffsetOps.push_back(dwarf::DW_OP_deref_size); + OffsetOps.push_back(DerefSizeInBytes); + StackValue = true; + } else if (Expr->isComplex()) { + // A variable with no size ambiguity, but with extra elements in it's + // expression. Manually dereference the stack location. + OffsetOps.push_back(dwarf::DW_OP_deref); + } else { + // A plain value that has been spilt to the stack, with no further + // context. Request a location expression, marking the DBG_VALUE as + // IsIndirect. + Indirect = true; + } + + Expr = DIExpression::appendOpsToArg(Expr, OffsetOps, Idx, StackValue); + MOs.push_back(GetRegOp(Base)); } else { - // A plain value that has been spilt to the stack, with no further - // context. Request a location expression, marking the DBG_VALUE as - // IsIndirect. - Expr = TRI.prependOffsetExpression(Expr, DIExpression::ApplyOffset, - Spill.SpillOffset); - Indirect = true; + // This is a stack location with a weird subregister offset: emit an + // undef DBG_VALUE instead. + return EmitUndef(); } } else { - // This is a stack location with a weird subregister offset: emit an undef - // DBG_VALUE instead. - return EmitUndef(); + // Non-empty, non-stack slot, must be a plain register. + MOs.push_back(GetRegOp(LocID)); } - } else { - // Non-empty, non-stack slot, must be a plain register. - unsigned LocID = LocIdxToLocID[*MLoc]; - MOs.push_back(GetRegOp(LocID)); } return BuildMI(MF, DL, Desc, Indirect, MOs, Var.getVariable(), Expr); @@ -1374,7 +1407,10 @@ // This DBG_VALUE is potentially a $noreg / undefined location, if // FoundLoc is None. // (XXX -- could morph the DBG_INSTR_REF in the future). - MachineInstr *DbgMI = MTracker->emitLoc(FoundLoc, V, Properties); + SmallVector ResolvedOps; + if (FoundLoc) + ResolvedOps.push_back(*FoundLoc); + MachineInstr *DbgMI = MTracker->emitLoc(ResolvedOps, V, Properties); TTracker->PendingDbgValues.push_back(DbgMI); TTracker->flushDbgValues(MI.getIterator(), nullptr);