Path: blob/main/contrib/llvm-project/llvm/tools/llvm-diff/lib/DiffConsumer.cpp
35291 views
//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//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// This files implements the LLVM difference Consumer9//10//===----------------------------------------------------------------------===//1112#include "DiffConsumer.h"13#include "llvm/IR/Instructions.h"14#include "llvm/Support/Debug.h"15#include "llvm/Support/ErrorHandling.h"1617using namespace llvm;1819static void ComputeNumbering(const Function *F,20DenseMap<const Value *, unsigned> &Numbering) {21unsigned IN = 0;2223// Arguments get the first numbers.24for (const auto &Arg : F->args())25if (!Arg.hasName())26Numbering[&Arg] = IN++;2728// Walk the basic blocks in order.29for (const auto &Func : *F) {30if (!Func.hasName())31Numbering[&Func] = IN++;3233// Walk the instructions in order.34for (const auto &BB : Func)35// void instructions don't get numbers.36if (!BB.hasName() && !BB.getType()->isVoidTy())37Numbering[&BB] = IN++;38}3940assert(!Numbering.empty() && "asked for numbering but numbering was no-op");41}4243void Consumer::anchor() { }4445void DiffConsumer::printValue(const Value *V, bool isL) {46if (V->hasName()) {47out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();48return;49}50if (V->getType()->isVoidTy()) {51if (auto *SI = dyn_cast<StoreInst>(V)) {52out << "store to ";53printValue(SI->getPointerOperand(), isL);54} else if (auto *CI = dyn_cast<CallInst>(V)) {55out << "call to ";56printValue(CI->getCalledOperand(), isL);57} else if (auto *II = dyn_cast<InvokeInst>(V)) {58out << "invoke to ";59printValue(II->getCalledOperand(), isL);60} else {61out << *V;62}63return;64}65if (isa<Constant>(V)) {66out << *V;67return;68}6970unsigned N = contexts.size();71while (N > 0) {72--N;73DiffContext &ctxt = contexts[N];74if (!ctxt.IsFunction) continue;75if (isL) {76if (ctxt.LNumbering.empty())77ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);78out << '%' << ctxt.LNumbering[V];79return;80} else {81if (ctxt.RNumbering.empty())82ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);83out << '%' << ctxt.RNumbering[V];84return;85}86}8788out << "<anonymous>";89}9091void DiffConsumer::header() {92if (contexts.empty()) return;93for (SmallVectorImpl<DiffContext>::iterator94I = contexts.begin(), E = contexts.end(); I != E; ++I) {95if (I->Differences) continue;96if (isa<Function>(I->L)) {97// Extra newline between functions.98if (Differences) out << "\n";99100const Function *L = cast<Function>(I->L);101const Function *R = cast<Function>(I->R);102if (L->getName() != R->getName())103out << "in function " << L->getName()104<< " / " << R->getName() << ":\n";105else106out << "in function " << L->getName() << ":\n";107} else if (isa<BasicBlock>(I->L)) {108const BasicBlock *L = cast<BasicBlock>(I->L);109const BasicBlock *R = cast<BasicBlock>(I->R);110if (L->hasName() && R->hasName() && L->getName() == R->getName())111out << " in block %" << L->getName() << ":\n";112else {113out << " in block ";114printValue(L, true);115out << " / ";116printValue(R, false);117out << ":\n";118}119} else if (isa<Instruction>(I->L)) {120out << " in instruction ";121printValue(I->L, true);122out << " / ";123printValue(I->R, false);124out << ":\n";125}126127I->Differences = true;128}129}130131void DiffConsumer::indent() {132unsigned N = Indent;133while (N--) out << ' ';134}135136void DiffConsumer::reset() {137contexts.clear();138Differences = false;139Indent = 0;140}141142bool DiffConsumer::hadDifferences() const {143return Differences;144}145146void DiffConsumer::enterContext(const Value *L, const Value *R) {147contexts.push_back(DiffContext(L, R));148Indent += 2;149}150151void DiffConsumer::exitContext() {152Differences |= contexts.back().Differences;153contexts.pop_back();154Indent -= 2;155}156157void DiffConsumer::log(StringRef text) {158header();159indent();160out << text << '\n';161}162163void DiffConsumer::logf(const LogBuilder &Log) {164header();165indent();166167unsigned arg = 0;168169StringRef format = Log.getFormat();170while (true) {171size_t percent = format.find('%');172if (percent == StringRef::npos) {173out << format;174break;175}176assert(format[percent] == '%');177178if (percent > 0) out << format.substr(0, percent);179180switch (format[percent+1]) {181case '%': out << '%'; break;182case 'l': printValue(Log.getArgument(arg++), true); break;183case 'r': printValue(Log.getArgument(arg++), false); break;184default: llvm_unreachable("unknown format character");185}186187format = format.substr(percent+2);188}189190out << '\n';191}192193void DiffConsumer::logd(const DiffLogBuilder &Log) {194header();195196for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {197indent();198switch (Log.getLineKind(I)) {199case DC_match:200out << " ";201Log.getLeft(I)->print(dbgs()); dbgs() << '\n';202//printValue(Log.getLeft(I), true);203break;204case DC_left:205out << "< ";206Log.getLeft(I)->print(dbgs()); dbgs() << '\n';207//printValue(Log.getLeft(I), true);208break;209case DC_right:210out << "> ";211Log.getRight(I)->print(dbgs()); dbgs() << '\n';212//printValue(Log.getRight(I), false);213break;214}215//out << "\n";216}217}218219220