brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.7 KiB · 5ff9b3d Raw
224 lines · cpp
1//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//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// This files implements the LLVM difference Consumer10//11//===----------------------------------------------------------------------===//12 13#include "DiffConsumer.h"14#include "llvm/IR/Instructions.h"15#include "llvm/Support/Debug.h"16#include "llvm/Support/ErrorHandling.h"17#include "llvm/Support/WithColor.h"18#include "llvm/Support/raw_ostream.h"19 20using namespace llvm;21 22static void ComputeNumbering(const Function *F,23                             DenseMap<const Value *, unsigned> &Numbering) {24  unsigned IN = 0;25 26  // Arguments get the first numbers.27  for (const auto &Arg : F->args())28    if (!Arg.hasName())29      Numbering[&Arg] = IN++;30 31  // Walk the basic blocks in order.32  for (const auto &Func : *F) {33    if (!Func.hasName())34      Numbering[&Func] = IN++;35 36    // Walk the instructions in order.37    for (const auto &BB : Func)38      // void instructions don't get numbers.39      if (!BB.hasName() && !BB.getType()->isVoidTy())40        Numbering[&BB] = IN++;41  }42 43  assert(!Numbering.empty() && "asked for numbering but numbering was no-op");44}45 46void Consumer::anchor() { }47 48void DiffConsumer::printValue(const Value *V, bool isL) {49  if (V->hasName()) {50    out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();51    return;52  }53  if (V->getType()->isVoidTy()) {54    if (auto *SI = dyn_cast<StoreInst>(V)) {55      out << "store to ";56      printValue(SI->getPointerOperand(), isL);57    } else if (auto *CI = dyn_cast<CallInst>(V)) {58      out << "call to ";59      printValue(CI->getCalledOperand(), isL);60    } else if (auto *II = dyn_cast<InvokeInst>(V)) {61      out << "invoke to ";62      printValue(II->getCalledOperand(), isL);63    } else {64      out << *V;65    }66    return;67  }68  if (isa<Constant>(V)) {69    out << *V;70    return;71  }72 73  unsigned N = contexts.size();74  while (N > 0) {75    --N;76    DiffContext &ctxt = contexts[N];77    if (!ctxt.IsFunction) continue;78    if (isL) {79      if (ctxt.LNumbering.empty())80        ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);81      out << '%' << ctxt.LNumbering[V];82      return;83    } else {84      if (ctxt.RNumbering.empty())85        ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);86      out << '%' << ctxt.RNumbering[V];87      return;88    }89  }90 91  out << "<anonymous>";92}93 94void DiffConsumer::header() {95  if (contexts.empty()) return;96  for (SmallVectorImpl<DiffContext>::iterator97         I = contexts.begin(), E = contexts.end(); I != E; ++I) {98    if (I->Differences) continue;99    if (isa<Function>(I->L)) {100      // Extra newline between functions.101      if (Differences) out << "\n";102 103      const Function *L = cast<Function>(I->L);104      const Function *R = cast<Function>(I->R);105      if (L->getName() != R->getName())106        out << "in function " << L->getName()107            << " / " << R->getName() << ":\n";108      else109        out << "in function " << L->getName() << ":\n";110    } else if (isa<BasicBlock>(I->L)) {111      const BasicBlock *L = cast<BasicBlock>(I->L);112      const BasicBlock *R = cast<BasicBlock>(I->R);113      if (L->hasName() && R->hasName() && L->getName() == R->getName())114        out << "  in block %" << L->getName() << ":\n";115      else {116        out << "  in block ";117        printValue(L, true);118        out << " / ";119        printValue(R, false);120        out << ":\n";121      }122    } else if (isa<Instruction>(I->L)) {123      out << "    in instruction ";124      printValue(I->L, true);125      out << " / ";126      printValue(I->R, false);127      out << ":\n";128    }129 130    I->Differences = true;131  }132}133 134void DiffConsumer::indent() {135  unsigned N = Indent;136  while (N--) out << ' ';137}138 139void DiffConsumer::reset() {140  contexts.clear();141  Differences = false;142  Indent = 0;143}144 145bool DiffConsumer::hadDifferences() const {146  return Differences;147}148 149void DiffConsumer::enterContext(const Value *L, const Value *R) {150  contexts.push_back(DiffContext(L, R));151  Indent += 2;152}153 154void DiffConsumer::exitContext() {155  Differences |= contexts.back().Differences;156  contexts.pop_back();157  Indent -= 2;158}159 160void DiffConsumer::log(StringRef text) {161  header();162  indent();163  out << text << '\n';164}165 166void DiffConsumer::logf(const LogBuilder &Log) {167  header();168  indent();169 170  unsigned arg = 0;171 172  StringRef format = Log.getFormat();173  while (true) {174    size_t percent = format.find('%');175    if (percent == StringRef::npos) {176      out << format;177      break;178    }179    assert(format[percent] == '%');180 181    if (percent > 0) out << format.substr(0, percent);182 183    switch (format[percent+1]) {184    case '%': out << '%'; break;185    case 'l': printValue(Log.getArgument(arg++), true); break;186    case 'r': printValue(Log.getArgument(arg++), false); break;187    default: llvm_unreachable("unknown format character");188    }189 190    format = format.substr(percent+2);191  }192 193  out << '\n';194}195 196void DiffConsumer::logd(const DiffLogBuilder &Log) {197  header();198 199  for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {200    indent();201    switch (Log.getLineKind(I)) {202    case DC_match:203      out << "  ";204      Log.getLeft(I)->print(dbgs());205      dbgs() << '\n';206      break;207    case DC_left: {208      auto LeftColor = llvm::WithColor(out, raw_ostream::RED);209      LeftColor << "< ";210      Log.getLeft(I)->print(LeftColor);211      LeftColor << '\n';212      break;213    }214    case DC_right: {215      auto RightColor = llvm::WithColor(out, raw_ostream::GREEN);216      RightColor << "> ";217      Log.getRight(I)->print(RightColor);218      RightColor << '\n';219      break;220    }221    }222  }223}224