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