420 lines · cpp
1//===-- WebAssemblyDebugValueManager.cpp - WebAssembly DebugValue Manager -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements the manager for MachineInstr DebugValues.11///12//===----------------------------------------------------------------------===//13 14#include "WebAssemblyDebugValueManager.h"15#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"16#include "WebAssembly.h"17#include "WebAssemblyMachineFunctionInfo.h"18#include "llvm/CodeGen/MachineInstr.h"19#include "llvm/IR/DebugInfoMetadata.h"20#include "llvm/IR/Function.h"21 22using namespace llvm;23 24WebAssemblyDebugValueManager::WebAssemblyDebugValueManager(MachineInstr *Def)25 : Def(Def) {26 if (!Def->getMF()->getFunction().getSubprogram())27 return;28 29 // This code differs from MachineInstr::collectDebugValues in that it scans30 // the whole BB, not just contiguous DBG_VALUEs, until another definition to31 // the same register is encountered.32 if (!Def->getOperand(0).isReg())33 return;34 CurrentReg = Def->getOperand(0).getReg();35 36 for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),37 ME = Def->getParent()->end();38 MI != ME; ++MI) {39 // If another definition appears, stop40 if (MI->definesRegister(CurrentReg, /*TRI=*/nullptr))41 break;42 if (MI->isDebugValue() && MI->hasDebugOperandForReg(CurrentReg))43 DbgValues.push_back(&*MI);44 }45}46 47// Returns true if both A and B are the same CONST_I32/I64/F32/F64 instructions.48// Doesn't include CONST_V128.49static bool isSameScalarConst(const MachineInstr *A, const MachineInstr *B) {50 if (A->getOpcode() != B->getOpcode() ||51 !WebAssembly::isScalarConst(A->getOpcode()) ||52 !WebAssembly::isScalarConst(B->getOpcode()))53 return false;54 const MachineOperand &OpA = A->getOperand(1), &OpB = B->getOperand(1);55 if ((OpA.isImm() && OpB.isImm() && OpA.getImm() == OpB.getImm()) ||56 (OpA.isFPImm() && OpB.isFPImm() && OpA.getFPImm() == OpB.getFPImm()) ||57 (OpA.isGlobal() && OpB.isGlobal() && OpA.getGlobal() == OpB.getGlobal()))58 return true;59 return false;60}61 62SmallVector<MachineInstr *, 1>63WebAssemblyDebugValueManager::getSinkableDebugValues(64 MachineInstr *Insert) const {65 if (DbgValues.empty())66 return {};67 // DBG_VALUEs between Def and Insert68 SmallVector<MachineInstr *, 8> DbgValuesInBetween;69 70 if (Def->getParent() == Insert->getParent()) {71 // When Def and Insert are within the same BB, check if Insert comes after72 // Def, because we only support sinking.73 bool DefFirst = false;74 for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),75 ME = Def->getParent()->end();76 MI != ME; ++MI) {77 if (&*MI == Insert) {78 DefFirst = true;79 break;80 }81 if (MI->isDebugValue())82 DbgValuesInBetween.push_back(&*MI);83 }84 if (!DefFirst) // Not a sink85 return {};86 87 } else { // Def and Insert are in different BBs88 // If Def and Insert are in different BBs, we only handle a simple case in89 // which Insert's BB is a successor of Def's BB.90 if (!Def->getParent()->isSuccessor(Insert->getParent()))91 return {};92 93 // Gather DBG_VALUEs between 'Def~Def BB's end' and94 // 'Insert BB's begin~Insert'95 for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),96 ME = Def->getParent()->end();97 MI != ME; ++MI) {98 if (MI->isDebugValue())99 DbgValuesInBetween.push_back(&*MI);100 }101 for (MachineBasicBlock::iterator MI = Insert->getParent()->begin(),102 ME = Insert->getIterator();103 MI != ME; ++MI) {104 if (MI->isDebugValue())105 DbgValuesInBetween.push_back(&*MI);106 }107 }108 109 // Gather DebugVariables that are seen between Def and Insert, excluding our110 // own DBG_VALUEs in DbgValues.111 SmallDenseMap<DebugVariable, SmallVector<MachineInstr *, 2>>112 SeenDbgVarToDbgValues;113 for (auto *DV : DbgValuesInBetween) {114 if (!llvm::is_contained(DbgValues, DV)) {115 DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(),116 DV->getDebugLoc()->getInlinedAt());117 SeenDbgVarToDbgValues[Var].push_back(DV);118 }119 }120 121 // Gather sinkable DBG_VALUEs. We should not sink a DBG_VALUE if there is122 // another DBG_VALUE between Def and Insert referring to the same123 // DebugVariable. For example,124 // %0 = someinst125 // DBG_VALUE %0, !"a", !DIExpression() // Should not sink with %0126 // %1 = anotherinst127 // DBG_VALUE %1, !"a", !DIExpression()128 // Where if %0 were to sink, the DBG_VAUE should not sink with it, as that129 // would re-order assignments.130 SmallVector<MachineInstr *, 1> SinkableDbgValues;131 MachineRegisterInfo &MRI = Def->getParent()->getParent()->getRegInfo();132 for (auto *DV : DbgValues) {133 DebugVariable Var(DV->getDebugVariable(), DV->getDebugExpression(),134 DV->getDebugLoc()->getInlinedAt());135 auto It = SeenDbgVarToDbgValues.find(Var);136 if (It == SeenDbgVarToDbgValues.end()) {137 SinkableDbgValues.push_back(DV);138 continue;139 }140 if (!WebAssembly::isScalarConst(Def->getOpcode()))141 continue;142 auto &OverlappingDbgValues = It->second;143 bool Sinkable = true;144 for (auto *OverlappingDV : OverlappingDbgValues) {145 MachineOperand &DbgOp = OverlappingDV->getDebugOperand(0);146 if (!DbgOp.isReg()) {147 Sinkable = false;148 break;149 }150 Register OtherReg = DbgOp.getReg();151 MachineInstr *OtherDef = MRI.getUniqueVRegDef(OtherReg);152 // We have an exception to allow encoutering other DBG_VALUEs with the153 // smae DebugVariables, only when they are referring to the same scalar154 // CONST instruction. For example,155 // %0 = CONST_I32 1156 // DBG_VALUE %0, !"a", !DIExpression() // Can sink with %0157 // %1 = CONST_I32 1158 // DBG_VALUE %1, !"a", !DIExpression()159 // When %0 were to be sunk/cloneed, the DBG_VALUE can be sunk/cloned with160 // it because even though the second DBG_VALUE refers to the same161 // DebugVariable, its value in effect is the same CONST instruction.162 //163 // This is to allow a case that can happen with RegStackify's164 // "rematerializeCheapDef". For example, we have this program with two165 // BBs:166 // bb0:167 // %0 = CONST_I32 1168 // DBG_VALUE %0, !"a", ...169 // ...170 // INST0 ..., $0 ...171 // bb1:172 // INST1 ..., $0 ...173 // INST2 ..., $0 ...174 //175 // We process bb0 first. Because %0 is used multiple times, %0 is cloned176 // before INST0:177 // bb0:178 // %0 = CONST_I32 1179 // DBG_VALUE %0, !"a", ...180 // ...181 // %1 = CONST_I32 1182 // DBG_VALUE %1, !"a", ...183 // INST0 ..., $1 ...184 //185 // And when we process bb1, we clone %0 and its DBG_VALUE again:186 // bb0:187 // %0 = CONST_I32 1188 // DBG_VALUE %0, !"a", ...189 // ...190 // %1 = CONST_I32 1191 // DBG_VALUE %1, !"a", ...192 // INST0 ..., $1 ...193 // bb1:194 // %2 = CONST_I32 1195 // DBG_VALUE %2, !"a", ... // !!!196 // INST1 ..., $2 ...197 // %3 = CONST_I32 1198 // DBG_VALUE %3, !"a", ... // !!!199 // INST2 ..., $3 ...200 //201 // But (without this exception) the cloned DBG_VALUEs marked with !!! are202 // not possible to be cloned, because there is a previously cloned203 // 'DBG_VALUE %1, !"a"' at the end of bb0 referring to the same204 // DebugVariable "a". But in this case they are OK to be cloned, because205 // the interfering DBG_VALUE is pointing to the same 'CONST_I32 1',206 // because it was cloned from the same instruction.207 if (!OtherDef || !isSameScalarConst(Def, OtherDef)) {208 Sinkable = false;209 break;210 }211 }212 if (Sinkable)213 SinkableDbgValues.push_back(DV);214 }215 return SinkableDbgValues;216}217 218// Returns true if the insertion point is the same as the current place.219// Following DBG_VALUEs for 'Def' are ignored.220bool WebAssemblyDebugValueManager::isInsertSamePlace(221 MachineInstr *Insert) const {222 if (Def->getParent() != Insert->getParent())223 return false;224 for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),225 ME = Insert;226 MI != ME; ++MI) {227 if (!llvm::is_contained(DbgValues, MI)) {228 return false;229 }230 }231 return true;232}233 234// Returns true if any instruction in MBB has the same debug location as DL.235// Also returns true if DL is an empty location.236static bool hasSameDebugLoc(const MachineBasicBlock *MBB, DebugLoc DL) {237 for (const auto &MI : *MBB)238 if (MI.getDebugLoc() == DL)239 return true;240 return false;241}242 243// Sink 'Def', and also sink its eligible DBG_VALUEs to the place before244// 'Insert'. Convert the original DBG_VALUEs into undefs.245//246// For DBG_VALUEs to sink properly, if 'Def' and 'Insert' are within the same247// BB, 'Insert' should be below 'Def'; if they are in different BBs, 'Insert'248// should be in one of 'Def's BBs successors. Def will be sunk regardless of the249// location.250//251// This DebugValueManager's new Def and DbgValues will be updated to the newly252// sinked Def + DBG_VALUEs.253void WebAssemblyDebugValueManager::sink(MachineInstr *Insert) {254 // In case Def is requested to be sunk to255 // the same place, we don't need to do anything. If we actually do the sink,256 // it will create unnecessary undef DBG_VALUEs. For example, if the original257 // code is:258 // %0 = someinst // Def259 // DBG_VALUE %0, ...260 // %1 = anotherinst // Insert261 //262 // If we actually sink %0 and the following DBG_VALUE and setting the original263 // DBG_VALUE undef, the result will be:264 // DBG_VALUE %noreg, ... // Unnecessary!265 // %0 = someinst // Def266 // DBG_VALUE %0, ...267 // %1 = anotherinst // Insert268 if (isInsertSamePlace(Insert))269 return;270 271 MachineBasicBlock *MBB = Insert->getParent();272 MachineFunction *MF = MBB->getParent();273 274 // Get the list of sinkable DBG_VALUEs. This should be done before sinking275 // Def, because we need to examine instructions between Def and Insert.276 SmallVector<MachineInstr *, 1> SinkableDbgValues =277 getSinkableDebugValues(Insert);278 279 // Sink Def first.280 //281 // When moving to a different BB, we preserve the debug loc only if the282 // destination BB contains the same location. See283 // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location.284 if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc()))285 Def->setDebugLoc(DebugLoc());286 MBB->splice(Insert, Def->getParent(), Def);287 288 if (DbgValues.empty())289 return;290 291 // Clone sinkable DBG_VALUEs and insert them.292 SmallVector<MachineInstr *, 1> NewDbgValues;293 for (MachineInstr *DV : SinkableDbgValues) {294 MachineInstr *Clone = MF->CloneMachineInstr(DV);295 MBB->insert(Insert, Clone);296 NewDbgValues.push_back(Clone);297 }298 299 // When sinking a Def and its DBG_VALUEs, we shouldn't just remove the300 // original DBG_VALUE instructions; we should set them to undef not to create301 // an impossible combination of variable assignments in the original program.302 // For example, this is the original program in order:303 // %0 = CONST_I32 0304 // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?305 // %1 = CONST_I32 1306 // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1307 // %2 = CONST_I32 2308 // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 1309 // %3 = CONST_I32 3310 // DBG_VALUE %3, !"b", !DIExpression() // a = 2, b = 3311 //312 // If %2 were to sink below %3, if we just sink DBG_VALUE %1 with it, the313 // debug info will show the variable "b" is updated to 2, creating the314 // variable assignment combination of (a = 0, b = 3), which is not possible in315 // the original program:316 // %0 = CONST_I32 0317 // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?318 // %1 = CONST_I32 1319 // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1320 // %3 = CONST_I32 3321 // DBG_VALUE %3, !"b", !DIExpression() // a = 0, b = 3 (Incorrect!)322 // %2 = CONST_I32 2323 // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3324 //325 // To fix this,we leave an undef DBG_VALUE in its original place, so that the326 // result will be327 // %0 = CONST_I32 0328 // DBG_VALUE %0, !"a", !DIExpression() // a = 0, b = ?329 // %1 = CONST_I32 1330 // DBG_VALUE %1, !"b", !DIExpression() // a = 0, b = 1331 // DBG_VALUE $noreg, !"a", !DIExpression() // a = ?, b = 1332 // %3 = CONST_I32 3333 // DBG_VALUE %3, !"b", !DIExpression() // a = ?, b = 3334 // %2 = CONST_I32 2335 // DBG_VALUE %2, !"a", !DIExpression() // a = 2, b = 3336 // Now in the middle "a" will be shown as "optimized out", but it wouldn't337 // show the impossible combination of (a = 0, b = 3).338 for (MachineInstr *DV : DbgValues)339 DV->setDebugValueUndef();340 341 DbgValues.swap(NewDbgValues);342}343 344// Clone 'Def', and also clone its eligible DBG_VALUEs to the place before345// 'Insert'.346//347// For DBG_VALUEs to be cloned properly, if 'Def' and 'Insert' are within the348// same BB, 'Insert' should be below 'Def'; if they are in different BBs,349// 'Insert' should be in one of 'Def's BBs successors. Def will be cloned350// regardless of the location.351//352// If NewReg is not $noreg, the newly cloned DBG_VALUEs will have the new353// register as its operand.354void WebAssemblyDebugValueManager::cloneSink(MachineInstr *Insert,355 Register NewReg,356 bool CloneDef) const {357 MachineBasicBlock *MBB = Insert->getParent();358 MachineFunction *MF = MBB->getParent();359 360 SmallVector<MachineInstr *> SinkableDbgValues =361 getSinkableDebugValues(Insert);362 363 // Clone Def first.364 if (CloneDef) {365 MachineInstr *Clone = MF->CloneMachineInstr(Def);366 // When cloning to a different BB, we preserve the debug loc only if the367 // destination BB contains the same location. See368 // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location.369 if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc()))370 Clone->setDebugLoc(DebugLoc());371 if (NewReg != CurrentReg && NewReg.isValid())372 Clone->getOperand(0).setReg(NewReg);373 MBB->insert(Insert, Clone);374 }375 376 if (DbgValues.empty())377 return;378 379 // Clone sinkable DBG_VALUEs and insert them.380 SmallVector<MachineInstr *, 1> NewDbgValues;381 for (MachineInstr *DV : SinkableDbgValues) {382 MachineInstr *Clone = MF->CloneMachineInstr(DV);383 MBB->insert(Insert, Clone);384 NewDbgValues.push_back(Clone);385 }386 387 if (NewReg != CurrentReg && NewReg.isValid())388 for (auto *DBI : NewDbgValues)389 for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))390 MO.setReg(NewReg);391}392 393// Update the register for Def and DBG_VALUEs.394void WebAssemblyDebugValueManager::updateReg(Register Reg) {395 if (Reg != CurrentReg && Reg.isValid()) {396 for (auto *DBI : DbgValues)397 for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))398 MO.setReg(Reg);399 CurrentReg = Reg;400 Def->getOperand(0).setReg(Reg);401 }402}403 404void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) {405 for (auto *DBI : DbgValues) {406 auto IndexType = DBI->isIndirectDebugValue()407 ? llvm::WebAssembly::TI_LOCAL_INDIRECT408 : llvm::WebAssembly::TI_LOCAL;409 for (auto &MO : DBI->getDebugOperandsForReg(CurrentReg))410 MO.ChangeToTargetIndex(IndexType, LocalId);411 }412}413 414// Remove Def, and set its DBG_VALUEs to undef.415void WebAssemblyDebugValueManager::removeDef() {416 Def->removeFromParent();417 for (MachineInstr *DV : DbgValues)418 DV->setDebugValueUndef();419}420