Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp
35266 views
//===-- WebAssemblyDebugValueManager.cpp - WebAssembly DebugValue Manager -===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements the manager for MachineInstr DebugValues.10///11//===----------------------------------------------------------------------===//1213#include "WebAssemblyDebugValueManager.h"14#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"15#include "WebAssembly.h"16#include "WebAssemblyMachineFunctionInfo.h"17#include "llvm/CodeGen/MachineInstr.h"18#include "llvm/IR/DebugInfoMetadata.h"19#include "llvm/IR/Function.h"2021using namespace llvm;2223WebAssemblyDebugValueManager::WebAssemblyDebugValueManager(MachineInstr *Def)24: Def(Def) {25if (!Def->getMF()->getFunction().getSubprogram())26return;2728// This code differs from MachineInstr::collectDebugValues in that it scans29// the whole BB, not just contiguous DBG_VALUEs, until another definition to30// the same register is encountered.31if (!Def->getOperand(0).isReg())32return;33CurrentReg = Def->getOperand(0).getReg();3435for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),36ME = Def->getParent()->end();37MI != ME; ++MI) {38// If another definition appears, stop39if (MI->definesRegister(CurrentReg, /*TRI=*/nullptr))40break;41if (MI->isDebugValue() && MI->hasDebugOperandForReg(CurrentReg))42DbgValues.push_back(&*MI);43}44}4546// Returns true if both A and B are the same CONST_I32/I64/F32/F64 instructions.47// Doesn't include CONST_V128.48static bool isSameScalarConst(const MachineInstr *A, const MachineInstr *B) {49if (A->getOpcode() != B->getOpcode() ||50!WebAssembly::isScalarConst(A->getOpcode()) ||51!WebAssembly::isScalarConst(B->getOpcode()))52return false;53const MachineOperand &OpA = A->getOperand(1), &OpB = B->getOperand(1);54if ((OpA.isImm() && OpB.isImm() && OpA.getImm() == OpB.getImm()) ||55(OpA.isFPImm() && OpB.isFPImm() && OpA.getFPImm() == OpB.getFPImm()) ||56(OpA.isGlobal() && OpB.isGlobal() && OpA.getGlobal() == OpB.getGlobal()))57return true;58return false;59}6061SmallVector<MachineInstr *, 1>62WebAssemblyDebugValueManager::getSinkableDebugValues(63MachineInstr *Insert) const {64if (DbgValues.empty())65return {};66// DBG_VALUEs between Def and Insert67SmallVector<MachineInstr *, 8> DbgValuesInBetween;6869if (Def->getParent() == Insert->getParent()) {70// When Def and Insert are within the same BB, check if Insert comes after71// Def, because we only support sinking.72bool DefFirst = false;73for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),74ME = Def->getParent()->end();75MI != ME; ++MI) {76if (&*MI == Insert) {77DefFirst = true;78break;79}80if (MI->isDebugValue())81DbgValuesInBetween.push_back(&*MI);82}83if (!DefFirst) // Not a sink84return {};8586} else { // Def and Insert are in different BBs87// If Def and Insert are in different BBs, we only handle a simple case in88// which Insert's BB is a successor of Def's BB.89if (!Def->getParent()->isSuccessor(Insert->getParent()))90return {};9192// Gather DBG_VALUEs between 'Def~Def BB's end' and93// 'Insert BB's begin~Insert'94for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),95ME = Def->getParent()->end();96MI != ME; ++MI) {97if (MI->isDebugValue())98DbgValuesInBetween.push_back(&*MI);99}100for (MachineBasicBlock::iterator MI = Insert->getParent()->begin(),101ME = Insert->getIterator();102MI != ME; ++MI) {103if (MI->isDebugValue())104DbgValuesInBetween.push_back(&*MI);105}106}107108// Gather DebugVariables that are seen between Def and Insert, excluding our109// own DBG_VALUEs in DbgValues.110SmallDenseMap<DebugVariable, SmallVector<MachineInstr *, 2>>111SeenDbgVarToDbgValues;112for (auto *DV : DbgValuesInBetween) {113if (!llvm::is_contained(DbgValues, DV)) {114DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(),115DV->getDebugLoc()->getInlinedAt());116SeenDbgVarToDbgValues[Var].push_back(DV);117}118}119120// Gather sinkable DBG_VALUEs. We should not sink a DBG_VALUE if there is121// another DBG_VALUE between Def and Insert referring to the same122// DebugVariable. For example,123// %0 = someinst124// DBG_VALUE %0, !"a", !DIExpression() // Should not sink with %0125// %1 = anotherinst126// DBG_VALUE %1, !"a", !DIExpression()127// Where if %0 were to sink, the DBG_VAUE should not sink with it, as that128// would re-order assignments.129SmallVector<MachineInstr *, 1> SinkableDbgValues;130MachineRegisterInfo &MRI = Def->getParent()->getParent()->getRegInfo();131for (auto *DV : DbgValues) {132DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(),133DV->getDebugLoc()->getInlinedAt());134auto It = SeenDbgVarToDbgValues.find(Var);135if (It == SeenDbgVarToDbgValues.end()) {136SinkableDbgValues.push_back(DV);137continue;138}139if (!WebAssembly::isScalarConst(Def->getOpcode()))140continue;141auto &OverlappingDbgValues = It->second;142bool Sinkable = true;143for (auto *OverlappingDV : OverlappingDbgValues) {144MachineOperand &DbgOp = OverlappingDV->getDebugOperand(0);145if (!DbgOp.isReg()) {146Sinkable = false;147break;148}149Register OtherReg = DbgOp.getReg();150MachineInstr *OtherDef = MRI.getUniqueVRegDef(OtherReg);151// We have an exception to allow encoutering other DBG_VALUEs with the152// smae DebugVariables, only when they are referring to the same scalar153// CONST instruction. For example,154// %0 = CONST_I32 1155// DBG_VALUE %0, !"a", !DIExpression() // Can sink with %0156// %1 = CONST_I32 1157// DBG_VALUE %1, !"a", !DIExpression()158// When %0 were to be sunk/cloneed, the DBG_VALUE can be sunk/cloned with159// it because even though the second DBG_VALUE refers to the same160// DebugVariable, its value in effect is the same CONST instruction.161//162// This is to allow a case that can happen with RegStackify's163// "rematerializeCheapDef". For example, we have this program with two164// BBs:165// bb0:166// %0 = CONST_I32 1167// DBG_VALUE %0, !"a", ...168// ...169// INST0 ..., $0 ...170// bb1:171// INST1 ..., $0 ...172// INST2 ..., $0 ...173//174// We process bb0 first. Because %0 is used multiple times, %0 is cloned175// before INST0:176// bb0:177// %0 = CONST_I32 1178// DBG_VALUE %0, !"a", ...179// ...180// %1 = CONST_I32 1181// DBG_VALUE %1, !"a", ...182// INST0 ..., $1 ...183//184// And when we process bb1, we clone %0 and its DBG_VALUE again:185// bb0:186// %0 = CONST_I32 1187// DBG_VALUE %0, !"a", ...188// ...189// %1 = CONST_I32 1190// DBG_VALUE %1, !"a", ...191// INST0 ..., $1 ...192// bb1:193// %2 = CONST_I32 1194// DBG_VALUE %2, !"a", ... // !!!195// INST1 ..., $2 ...196// %3 = CONST_I32 1197// DBG_VALUE %3, !"a", ... // !!!198// INST2 ..., $3 ...199//200// But (without this exception) the cloned DBG_VALUEs marked with !!! are201// not possible to be cloned, because there is a previously cloned202// 'DBG_VALUE %1, !"a"' at the end of bb0 referring to the same203// DebugVariable "a". But in this case they are OK to be cloned, because204// the interfering DBG_VALUE is pointing to the same 'CONST_I32 1',205// because it was cloned from the same instruction.206if (!OtherDef || !isSameScalarConst(Def, OtherDef)) {207Sinkable = false;208break;209}210}211if (Sinkable)212SinkableDbgValues.push_back(DV);213}214return SinkableDbgValues;215}216217// Returns true if the insertion point is the same as the current place.218// Following DBG_VALUEs for 'Def' are ignored.219bool WebAssemblyDebugValueManager::isInsertSamePlace(220MachineInstr *Insert) const {221if (Def->getParent() != Insert->getParent())222return false;223for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),224ME = Insert;225MI != ME; ++MI) {226if (!llvm::is_contained(DbgValues, MI)) {227return false;228}229}230return true;231}232233// Returns true if any instruction in MBB has the same debug location as DL.234// Also returns true if DL is an empty location.235static bool hasSameDebugLoc(const MachineBasicBlock *MBB, DebugLoc DL) {236for (const auto &MI : *MBB)237if (MI.getDebugLoc() == DL)238return true;239return false;240}241242// Sink 'Def', and also sink its eligible DBG_VALUEs to the place before243// 'Insert'. Convert the original DBG_VALUEs into undefs.244//245// For DBG_VALUEs to sink properly, if 'Def' and 'Insert' are within the same246// BB, 'Insert' should be below 'Def'; if they are in different BBs, 'Insert'247// should be in one of 'Def's BBs successors. Def will be sunk regardless of the248// location.249//250// This DebugValueManager's new Def and DbgValues will be updated to the newly251// sinked Def + DBG_VALUEs.252void WebAssemblyDebugValueManager::sink(MachineInstr *Insert) {253// In case Def is requested to be sunk to254// the same place, we don't need to do anything. If we actually do the sink,255// it will create unnecessary undef DBG_VALUEs. For example, if the original256// code is:257// %0 = someinst // Def258// DBG_VALUE %0, ...259// %1 = anotherinst // Insert260//261// If we actually sink %0 and the following DBG_VALUE and setting the original262// DBG_VALUE undef, the result will be:263// DBG_VALUE %noreg, ... // Unnecessary!264// %0 = someinst // Def265// DBG_VALUE %0, ...266// %1 = anotherinst // Insert267if (isInsertSamePlace(Insert))268return;269270MachineBasicBlock *MBB = Insert->getParent();271MachineFunction *MF = MBB->getParent();272273// Get the list of sinkable DBG_VALUEs. This should be done before sinking274// Def, because we need to examine instructions between Def and Insert.275SmallVector<MachineInstr *, 1> SinkableDbgValues =276getSinkableDebugValues(Insert);277278// Sink Def first.279//280// When moving to a different BB, we preserve the debug loc only if the281// destination BB contains the same location. See282// https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location.283if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc()))284Def->setDebugLoc(DebugLoc());285MBB->splice(Insert, Def->getParent(), Def);286287if (DbgValues.empty())288return;289290// Clone sinkable DBG_VALUEs and insert them.291SmallVector<MachineInstr *, 1> NewDbgValues;292for (MachineInstr *DV : SinkableDbgValues) {293MachineInstr *Clone = MF->CloneMachineInstr(DV);294MBB->insert(Insert, Clone);295NewDbgValues.push_back(Clone);296}297298// When sinking a Def and its DBG_VALUEs, we shouldn't just remove the299// original DBG_VALUE instructions; we should set them to undef not to create300// an impossible combination of variable assignments in the original program.301// For example, this is the original program in order:302// %0 = CONST_I32 0303// DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?304// %1 = CONST_I32 1305// DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1306// %2 = CONST_I32 2307// DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 1308// %3 = CONST_I32 3309// DBG_VALUE %3, !"b", !DIExpression() // a = 2, b = 3310//311// If %2 were to sink below %3, if we just sink DBG_VALUE %1 with it, the312// debug info will show the variable "b" is updated to 2, creating the313// variable assignment combination of (a = 0, b = 3), which is not possible in314// the original program:315// %0 = CONST_I32 0316// DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?317// %1 = CONST_I32 1318// DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1319// %3 = CONST_I32 3320// DBG_VALUE %3, !"b", !DIExpression() // a = 0, b = 3 (Incorrect!)321// %2 = CONST_I32 2322// DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3323//324// To fix this,we leave an undef DBG_VALUE in its original place, so that the325// result will be326// %0 = CONST_I32 0327// DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?328// %1 = CONST_I32 1329// DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1330// DBG_VALUE $noreg, !"a", !DIExpression() // a = ?, b = 1331// %3 = CONST_I32 3332// DBG_VALUE %3, !"b", !DIExpression() // a = ?, b = 3333// %2 = CONST_I32 2334// DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3335// Now in the middle "a" will be shown as "optimized out", but it wouldn't336// show the impossible combination of (a = 0, b = 3).337for (MachineInstr *DV : DbgValues)338DV->setDebugValueUndef();339340DbgValues.swap(NewDbgValues);341}342343// Clone 'Def', and also clone its eligible DBG_VALUEs to the place before344// 'Insert'.345//346// For DBG_VALUEs to be cloned properly, if 'Def' and 'Insert' are within the347// same BB, 'Insert' should be below 'Def'; if they are in different BBs,348// 'Insert' should be in one of 'Def's BBs successors. Def will be cloned349// regardless of the location.350//351// If NewReg is not $noreg, the newly cloned DBG_VALUEs will have the new352// register as its operand.353void WebAssemblyDebugValueManager::cloneSink(MachineInstr *Insert,354Register NewReg,355bool CloneDef) const {356MachineBasicBlock *MBB = Insert->getParent();357MachineFunction *MF = MBB->getParent();358359SmallVector<MachineInstr *> SinkableDbgValues =360getSinkableDebugValues(Insert);361362// Clone Def first.363if (CloneDef) {364MachineInstr *Clone = MF->CloneMachineInstr(Def);365// When cloning to a different BB, we preserve the debug loc only if the366// destination BB contains the same location. See367// https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location.368if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc()))369Clone->setDebugLoc(DebugLoc());370if (NewReg != CurrentReg && NewReg.isValid())371Clone->getOperand(0).setReg(NewReg);372MBB->insert(Insert, Clone);373}374375if (DbgValues.empty())376return;377378// Clone sinkable DBG_VALUEs and insert them.379SmallVector<MachineInstr *, 1> NewDbgValues;380for (MachineInstr *DV : SinkableDbgValues) {381MachineInstr *Clone = MF->CloneMachineInstr(DV);382MBB->insert(Insert, Clone);383NewDbgValues.push_back(Clone);384}385386if (NewReg != CurrentReg && NewReg.isValid())387for (auto *DBI : NewDbgValues)388for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))389MO.setReg(NewReg);390}391392// Update the register for Def and DBG_VALUEs.393void WebAssemblyDebugValueManager::updateReg(Register Reg) {394if (Reg != CurrentReg && Reg.isValid()) {395for (auto *DBI : DbgValues)396for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))397MO.setReg(Reg);398CurrentReg = Reg;399Def->getOperand(0).setReg(Reg);400}401}402403void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) {404for (auto *DBI : DbgValues) {405auto IndexType = DBI->isIndirectDebugValue()406? llvm::WebAssembly::TI_LOCAL_INDIRECT407: llvm::WebAssembly::TI_LOCAL;408for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))409MO.ChangeToTargetIndex(IndexType, LocalId);410}411}412413// Remove Def, and set its DBG_VALUEs to undef.414void WebAssemblyDebugValueManager::removeDef() {415Def->removeFromParent();416for (MachineInstr *DV : DbgValues)417DV->setDebugValueUndef();418}419420421