brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.7 KiB · da37174 Raw
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