diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-09-02 21:17:18 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-01-07 23:04:38 +0000 |
commit | 0e1e0ce556810ad5f9d45485e686f0653530516c (patch) | |
tree | ab02ce7c4fafc0518430e9cec77d41201bce23f0 /contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp | |
parent | c3eb0b7c19221f3a2133ab14d3ffffa61ec0c4bc (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp | 399 |
1 files changed, 371 insertions, 28 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp index 55be64ad7da0..fd510f85a8a3 100644 --- a/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp @@ -12,52 +12,388 @@ //===----------------------------------------------------------------------===// #include "WebAssemblyDebugValueManager.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/DebugInfoMetadata.h" using namespace llvm; -WebAssemblyDebugValueManager::WebAssemblyDebugValueManager( - MachineInstr *Instr) { +WebAssemblyDebugValueManager::WebAssemblyDebugValueManager(MachineInstr *Def) + : Def(Def) { // This code differs from MachineInstr::collectDebugValues in that it scans - // the whole BB, not just contiguous DBG_VALUEs. - if (!Instr->getOperand(0).isReg()) + // the whole BB, not just contiguous DBG_VALUEs, until another definition to + // the same register is encountered. + if (!Def->getOperand(0).isReg()) return; - CurrentReg = Instr->getOperand(0).getReg(); - - MachineBasicBlock::iterator DI = *Instr; - ++DI; - for (MachineBasicBlock::iterator DE = Instr->getParent()->end(); DI != DE; - ++DI) { - if (DI->isDebugValue() && - DI->hasDebugOperandForReg(Instr->getOperand(0).getReg())) - DbgValues.push_back(&*DI); + CurrentReg = Def->getOperand(0).getReg(); + + for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()), + ME = Def->getParent()->end(); + MI != ME; ++MI) { + // If another definition appears, stop + if (MI->definesRegister(CurrentReg)) + break; + if (MI->isDebugValue() && MI->hasDebugOperandForReg(CurrentReg)) + DbgValues.push_back(&*MI); } } -void WebAssemblyDebugValueManager::move(MachineInstr *Insert) { - MachineBasicBlock *MBB = Insert->getParent(); - for (MachineInstr *DBI : reverse(DbgValues)) - MBB->splice(Insert, DBI->getParent(), DBI); +// Returns true if both A and B are the same CONST_I32/I64/F32/F64 instructions. +// Doesn't include CONST_V128. +static bool isSameScalarConst(const MachineInstr *A, const MachineInstr *B) { + if (A->getOpcode() != B->getOpcode() || + !WebAssembly::isScalarConst(A->getOpcode()) || + !WebAssembly::isScalarConst(B->getOpcode())) + return false; + const MachineOperand &OpA = A->getOperand(1), &OpB = B->getOperand(1); + if ((OpA.isImm() && OpB.isImm() && OpA.getImm() == OpB.getImm()) || + (OpA.isFPImm() && OpB.isFPImm() && OpA.getFPImm() == OpB.getFPImm()) || + (OpA.isGlobal() && OpB.isGlobal() && OpA.getGlobal() == OpB.getGlobal())) + return true; + return false; } -void WebAssemblyDebugValueManager::updateReg(unsigned Reg) { - for (auto *DBI : DbgValues) - for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg)) - MO.setReg(Reg); - CurrentReg = Reg; +SmallVector<MachineInstr *, 1> +WebAssemblyDebugValueManager::getSinkableDebugValues( + MachineInstr *Insert) const { + if (DbgValues.empty()) + return {}; + // DBG_VALUEs between Def and Insert + SmallVector<MachineInstr *, 8> DbgValuesInBetween; + + if (Def->getParent() == Insert->getParent()) { + // When Def and Insert are within the same BB, check if Insert comes after + // Def, because we only support sinking. + bool DefFirst = false; + for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()), + ME = Def->getParent()->end(); + MI != ME; ++MI) { + if (&*MI == Insert) { + DefFirst = true; + break; + } + if (MI->isDebugValue()) + DbgValuesInBetween.push_back(&*MI); + } + if (!DefFirst) // Not a sink + return {}; + + } else { // Def and Insert are in different BBs + // If Def and Insert are in different BBs, we only handle a simple case in + // which Insert's BB is a successor of Def's BB. + if (!Def->getParent()->isSuccessor(Insert->getParent())) + return {}; + + // Gather DBG_VALUEs between 'Def~Def BB's end' and + // 'Insert BB's begin~Insert' + for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()), + ME = Def->getParent()->end(); + MI != ME; ++MI) { + if (MI->isDebugValue()) + DbgValuesInBetween.push_back(&*MI); + } + for (MachineBasicBlock::iterator MI = Insert->getParent()->begin(), + ME = Insert->getIterator(); + MI != ME; ++MI) { + if (MI->isDebugValue()) + DbgValuesInBetween.push_back(&*MI); + } + } + + // Gather DebugVariables that are seen between Def and Insert, excluding our + // own DBG_VALUEs in DbgValues. + SmallDenseMap<DebugVariable, SmallVector<MachineInstr *, 2>> + SeenDbgVarToDbgValues; + for (auto *DV : DbgValuesInBetween) { + if (!llvm::is_contained(DbgValues, DV)) { + DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(), + DV->getDebugLoc()->getInlinedAt()); + SeenDbgVarToDbgValues[Var].push_back(DV); + } + } + + // Gather sinkable DBG_VALUEs. We should not sink a DBG_VALUE if there is + // another DBG_VALUE between Def and Insert referring to the same + // DebugVariable. For example, + // %0 = someinst + // DBG_VALUE %0, !"a", !DIExpression() // Should not sink with %0 + // %1 = anotherinst + // DBG_VALUE %1, !"a", !DIExpression() + // Where if %0 were to sink, the DBG_VAUE should not sink with it, as that + // would re-order assignments. + SmallVector<MachineInstr *, 1> SinkableDbgValues; + MachineRegisterInfo &MRI = Def->getParent()->getParent()->getRegInfo(); + for (auto *DV : DbgValues) { + DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(), + DV->getDebugLoc()->getInlinedAt()); + auto It = SeenDbgVarToDbgValues.find(Var); + if (It == SeenDbgVarToDbgValues.end()) { + SinkableDbgValues.push_back(DV); + continue; + } + if (!WebAssembly::isScalarConst(Def->getOpcode())) + continue; + auto &OverlappingDbgValues = It->second; + bool Sinkable = true; + for (auto *OverlappingDV : OverlappingDbgValues) { + MachineOperand &DbgOp = OverlappingDV->getDebugOperand(0); + if (!DbgOp.isReg()) { + Sinkable = false; + break; + } + Register OtherReg = DbgOp.getReg(); + MachineInstr *OtherDef = MRI.getUniqueVRegDef(OtherReg); + // We have an exception to allow encoutering other DBG_VALUEs with the + // smae DebugVariables, only when they are referring to the same scalar + // CONST instruction. For example, + // %0 = CONST_I32 1 + // DBG_VALUE %0, !"a", !DIExpression() // Can sink with %0 + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"a", !DIExpression() + // When %0 were to be sunk/cloneed, the DBG_VALUE can be sunk/cloned with + // it because even though the second DBG_VALUE refers to the same + // DebugVariable, its value in effect is the same CONST instruction. + // + // This is to allow a case that can happen with RegStackify's + // "rematerializeCheapDef". For example, we have this program with two + // BBs: + // bb0: + // %0 = CONST_I32 1 + // DBG_VALUE %0, !"a", ... + // ... + // INST0 ..., $0 ... + // bb1: + // INST1 ..., $0 ... + // INST2 ..., $0 ... + // + // We process bb0 first. Because %0 is used multiple times, %0 is cloned + // before INST0: + // bb0: + // %0 = CONST_I32 1 + // DBG_VALUE %0, !"a", ... + // ... + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"a", ... + // INST0 ..., $1 ... + // + // And when we process bb1, we clone %0 and its DBG_VALUE again: + // bb0: + // %0 = CONST_I32 1 + // DBG_VALUE %0, !"a", ... + // ... + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"a", ... + // INST0 ..., $1 ... + // bb1: + // %2 = CONST_I32 1 + // DBG_VALUE %2, !"a", ... // !!! + // INST1 ..., $2 ... + // %3 = CONST_I32 1 + // DBG_VALUE %3, !"a", ... // !!! + // INST2 ..., $3 ... + // + // But (without this exception) the cloned DBG_VALUEs marked with !!! are + // not possible to be cloned, because there is a previously cloned + // 'DBG_VALUE %1, !"a"' at the end of bb0 referring to the same + // DebugVariable "a". But in this case they are OK to be cloned, because + // the interfering DBG_VALUE is pointing to the same 'CONST_I32 1', + // because it was cloned from the same instruction. + if (!OtherDef || !isSameScalarConst(Def, OtherDef)) { + Sinkable = false; + break; + } + } + if (Sinkable) + SinkableDbgValues.push_back(DV); + } + return SinkableDbgValues; +} + +// Returns true if the insertion point is the same as the current place. +// Following DBG_VALUEs for 'Def' are ignored. +bool WebAssemblyDebugValueManager::isInsertSamePlace( + MachineInstr *Insert) const { + if (Def->getParent() != Insert->getParent()) + return false; + for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()), + ME = Insert; + MI != ME; ++MI) { + if (!llvm::is_contained(DbgValues, MI)) { + return false; + } + } + return true; +} + +// Returns true if any instruction in MBB has the same debug location as DL. +// Also returns true if DL is an empty location. +static bool hasSameDebugLoc(const MachineBasicBlock *MBB, DebugLoc DL) { + for (const auto &MI : *MBB) + if (MI.getDebugLoc() == DL) + return true; + return false; +} + +// Sink 'Def', and also sink its eligible DBG_VALUEs to the place before +// 'Insert'. Convert the original DBG_VALUEs into undefs. +// +// For DBG_VALUEs to sink properly, if 'Def' and 'Insert' are within the same +// BB, 'Insert' should be below 'Def'; if they are in different BBs, 'Insert' +// should be in one of 'Def's BBs successors. Def will be sunk regardless of the +// location. +// +// This DebugValueManager's new Def and DbgValues will be updated to the newly +// sinked Def + DBG_VALUEs. +void WebAssemblyDebugValueManager::sink(MachineInstr *Insert) { + // In case Def is requested to be sunk to + // the same place, we don't need to do anything. If we actually do the sink, + // it will create unnecessary undef DBG_VALUEs. For example, if the original + // code is: + // %0 = someinst // Def + // DBG_VALUE %0, ... + // %1 = anotherinst // Insert + // + // If we actually sink %0 and the following DBG_VALUE and setting the original + // DBG_VALUE undef, the result will be: + // DBG_VALUE %noreg, ... // Unnecessary! + // %0 = someinst // Def + // DBG_VALUE %0, ... + // %1 = anotherinst // Insert + if (isInsertSamePlace(Insert)) + return; + + MachineBasicBlock *MBB = Insert->getParent(); + MachineFunction *MF = MBB->getParent(); + + // Get the list of sinkable DBG_VALUEs. This should be done before sinking + // Def, because we need to examine instructions between Def and Insert. + SmallVector<MachineInstr *, 1> SinkableDbgValues = + getSinkableDebugValues(Insert); + + // Sink Def first. + // + // When moving to a different BB, we preserve the debug loc only if the + // destination BB contains the same location. See + // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location. + if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc())) + Def->setDebugLoc(DebugLoc()); + MBB->splice(Insert, Def->getParent(), Def); + + if (DbgValues.empty()) + return; + + // Clone sinkable DBG_VALUEs and insert them. + SmallVector<MachineInstr *, 1> NewDbgValues; + for (MachineInstr *DV : SinkableDbgValues) { + MachineInstr *Clone = MF->CloneMachineInstr(DV); + MBB->insert(Insert, Clone); + NewDbgValues.push_back(Clone); + } + + // When sinking a Def and its DBG_VALUEs, we shouldn't just remove the + // original DBG_VALUE instructions; we should set them to undef not to create + // an impossible combination of variable assignments in the original program. + // For example, this is the original program in order: + // %0 = CONST_I32 0 + // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ? + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1 + // %2 = CONST_I32 2 + // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 1 + // %3 = CONST_I32 3 + // DBG_VALUE %3, !"b", !DIExpression() // a = 2, b = 3 + // + // If %2 were to sink below %3, if we just sink DBG_VALUE %1 with it, the + // debug info will show the variable "b" is updated to 2, creating the + // variable assignment combination of (a = 0, b = 3), which is not possible in + // the original program: + // %0 = CONST_I32 0 + // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ? + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1 + // %3 = CONST_I32 3 + // DBG_VALUE %3, !"b", !DIExpression() // a = 0, b = 3 (Incorrect!) + // %2 = CONST_I32 2 + // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3 + // + // To fix this,we leave an undef DBG_VALUE in its original place, so that the + // result will be + // %0 = CONST_I32 0 + // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ? + // %1 = CONST_I32 1 + // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1 + // DBG_VALUE $noreg, !"a", !DIExpression() // a = ?, b = 1 + // %3 = CONST_I32 3 + // DBG_VALUE %3, !"b", !DIExpression() // a = ?, b = 3 + // %2 = CONST_I32 2 + // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3 + // Now in the middle "a" will be shown as "optimized out", but it wouldn't + // show the impossible combination of (a = 0, b = 3). + for (MachineInstr *DV : DbgValues) + DV->setDebugValueUndef(); + + DbgValues.swap(NewDbgValues); } -void WebAssemblyDebugValueManager::clone(MachineInstr *Insert, - unsigned NewReg) { +// Clone 'Def', and also clone its eligible DBG_VALUEs to the place before +// 'Insert'. +// +// For DBG_VALUEs to be cloned properly, if 'Def' and 'Insert' are within the +// same BB, 'Insert' should be below 'Def'; if they are in different BBs, +// 'Insert' should be in one of 'Def's BBs successors. Def will be cloned +// regardless of the location. +// +// If NewReg is not $noreg, the newly cloned DBG_VALUEs will have the new +// register as its operand. +void WebAssemblyDebugValueManager::cloneSink(MachineInstr *Insert, + Register NewReg, + bool CloneDef) const { MachineBasicBlock *MBB = Insert->getParent(); MachineFunction *MF = MBB->getParent(); - for (MachineInstr *DBI : reverse(DbgValues)) { - MachineInstr *Clone = MF->CloneMachineInstr(DBI); - for (auto &MO : Clone->getDebugOperandsForReg(CurrentReg)) - MO.setReg(NewReg); + + SmallVector<MachineInstr *> SinkableDbgValues = + getSinkableDebugValues(Insert); + + // Clone Def first. + if (CloneDef) { + MachineInstr *Clone = MF->CloneMachineInstr(Def); + // When cloning to a different BB, we preserve the debug loc only if the + // destination BB contains the same location. See + // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location. + if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc())) + Clone->setDebugLoc(DebugLoc()); + if (NewReg != CurrentReg && NewReg.isValid()) + Clone->getOperand(0).setReg(NewReg); + MBB->insert(Insert, Clone); + } + + if (DbgValues.empty()) + return; + + // Clone sinkable DBG_VALUEs and insert them. + SmallVector<MachineInstr *, 1> NewDbgValues; + for (MachineInstr *DV : SinkableDbgValues) { + MachineInstr *Clone = MF->CloneMachineInstr(DV); MBB->insert(Insert, Clone); + NewDbgValues.push_back(Clone); + } + + if (NewReg != CurrentReg && NewReg.isValid()) + for (auto *DBI : NewDbgValues) + for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg)) + MO.setReg(NewReg); +} + +// Update the register for Def and DBG_VALUEs. +void WebAssemblyDebugValueManager::updateReg(Register Reg) { + if (Reg != CurrentReg && Reg.isValid()) { + for (auto *DBI : DbgValues) + for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg)) + MO.setReg(Reg); + CurrentReg = Reg; + Def->getOperand(0).setReg(Reg); } } @@ -70,3 +406,10 @@ void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) { MO.ChangeToTargetIndex(IndexType, LocalId); } } + +// Remove Def, and set its DBG_VALUEs to undef. +void WebAssemblyDebugValueManager::removeDef() { + Def->removeFromParent(); + for (MachineInstr *DV : DbgValues) + DV->setDebugValueUndef(); +} |