10b57cec5SDimitry Andric //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This files implements the LLVM difference Consumer
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "DiffConsumer.h"
140b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
160b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)20*5f7ddb14SDimitry Andric static void ComputeNumbering(const Function *F,
21*5f7ddb14SDimitry Andric DenseMap<const Value *, unsigned> &Numbering) {
220b57cec5SDimitry Andric unsigned IN = 0;
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric // Arguments get the first numbers.
25*5f7ddb14SDimitry Andric for (const auto &Arg : F->args())
26*5f7ddb14SDimitry Andric if (!Arg.hasName())
27*5f7ddb14SDimitry Andric Numbering[&Arg] = IN++;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric // Walk the basic blocks in order.
30*5f7ddb14SDimitry Andric for (const auto &Func : *F) {
31*5f7ddb14SDimitry Andric if (!Func.hasName())
32*5f7ddb14SDimitry Andric Numbering[&Func] = IN++;
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric // Walk the instructions in order.
35*5f7ddb14SDimitry Andric for (const auto &BB : Func)
360b57cec5SDimitry Andric // void instructions don't get numbers.
37*5f7ddb14SDimitry Andric if (!BB.hasName() && !BB.getType()->isVoidTy())
38*5f7ddb14SDimitry Andric Numbering[&BB] = IN++;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric
anchor()440b57cec5SDimitry Andric void Consumer::anchor() { }
450b57cec5SDimitry Andric
printValue(const Value * V,bool isL)46*5f7ddb14SDimitry Andric void DiffConsumer::printValue(const Value *V, bool isL) {
470b57cec5SDimitry Andric if (V->hasName()) {
480b57cec5SDimitry Andric out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
490b57cec5SDimitry Andric return;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric if (V->getType()->isVoidTy()) {
525ffd83dbSDimitry Andric if (auto *SI = dyn_cast<StoreInst>(V)) {
530b57cec5SDimitry Andric out << "store to ";
545ffd83dbSDimitry Andric printValue(SI->getPointerOperand(), isL);
555ffd83dbSDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(V)) {
560b57cec5SDimitry Andric out << "call to ";
575ffd83dbSDimitry Andric printValue(CI->getCalledOperand(), isL);
585ffd83dbSDimitry Andric } else if (auto *II = dyn_cast<InvokeInst>(V)) {
590b57cec5SDimitry Andric out << "invoke to ";
605ffd83dbSDimitry Andric printValue(II->getCalledOperand(), isL);
610b57cec5SDimitry Andric } else {
620b57cec5SDimitry Andric out << *V;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric return;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric if (isa<Constant>(V)) {
670b57cec5SDimitry Andric out << *V;
680b57cec5SDimitry Andric return;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric unsigned N = contexts.size();
720b57cec5SDimitry Andric while (N > 0) {
730b57cec5SDimitry Andric --N;
740b57cec5SDimitry Andric DiffContext &ctxt = contexts[N];
750b57cec5SDimitry Andric if (!ctxt.IsFunction) continue;
760b57cec5SDimitry Andric if (isL) {
770b57cec5SDimitry Andric if (ctxt.LNumbering.empty())
780b57cec5SDimitry Andric ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
790b57cec5SDimitry Andric out << '%' << ctxt.LNumbering[V];
800b57cec5SDimitry Andric return;
810b57cec5SDimitry Andric } else {
820b57cec5SDimitry Andric if (ctxt.RNumbering.empty())
830b57cec5SDimitry Andric ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
840b57cec5SDimitry Andric out << '%' << ctxt.RNumbering[V];
850b57cec5SDimitry Andric return;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric out << "<anonymous>";
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
header()920b57cec5SDimitry Andric void DiffConsumer::header() {
930b57cec5SDimitry Andric if (contexts.empty()) return;
940b57cec5SDimitry Andric for (SmallVectorImpl<DiffContext>::iterator
950b57cec5SDimitry Andric I = contexts.begin(), E = contexts.end(); I != E; ++I) {
960b57cec5SDimitry Andric if (I->Differences) continue;
970b57cec5SDimitry Andric if (isa<Function>(I->L)) {
980b57cec5SDimitry Andric // Extra newline between functions.
990b57cec5SDimitry Andric if (Differences) out << "\n";
1000b57cec5SDimitry Andric
101*5f7ddb14SDimitry Andric const Function *L = cast<Function>(I->L);
102*5f7ddb14SDimitry Andric const Function *R = cast<Function>(I->R);
1030b57cec5SDimitry Andric if (L->getName() != R->getName())
1040b57cec5SDimitry Andric out << "in function " << L->getName()
1050b57cec5SDimitry Andric << " / " << R->getName() << ":\n";
1060b57cec5SDimitry Andric else
1070b57cec5SDimitry Andric out << "in function " << L->getName() << ":\n";
1080b57cec5SDimitry Andric } else if (isa<BasicBlock>(I->L)) {
109*5f7ddb14SDimitry Andric const BasicBlock *L = cast<BasicBlock>(I->L);
110*5f7ddb14SDimitry Andric const BasicBlock *R = cast<BasicBlock>(I->R);
1110b57cec5SDimitry Andric if (L->hasName() && R->hasName() && L->getName() == R->getName())
1120b57cec5SDimitry Andric out << " in block %" << L->getName() << ":\n";
1130b57cec5SDimitry Andric else {
1140b57cec5SDimitry Andric out << " in block ";
1150b57cec5SDimitry Andric printValue(L, true);
1160b57cec5SDimitry Andric out << " / ";
1170b57cec5SDimitry Andric printValue(R, false);
1180b57cec5SDimitry Andric out << ":\n";
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric } else if (isa<Instruction>(I->L)) {
1210b57cec5SDimitry Andric out << " in instruction ";
1220b57cec5SDimitry Andric printValue(I->L, true);
1230b57cec5SDimitry Andric out << " / ";
1240b57cec5SDimitry Andric printValue(I->R, false);
1250b57cec5SDimitry Andric out << ":\n";
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric I->Differences = true;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
indent()1320b57cec5SDimitry Andric void DiffConsumer::indent() {
1330b57cec5SDimitry Andric unsigned N = Indent;
1340b57cec5SDimitry Andric while (N--) out << ' ';
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric
hadDifferences() const1370b57cec5SDimitry Andric bool DiffConsumer::hadDifferences() const {
1380b57cec5SDimitry Andric return Differences;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
enterContext(const Value * L,const Value * R)141*5f7ddb14SDimitry Andric void DiffConsumer::enterContext(const Value *L, const Value *R) {
1420b57cec5SDimitry Andric contexts.push_back(DiffContext(L, R));
1430b57cec5SDimitry Andric Indent += 2;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
exitContext()1460b57cec5SDimitry Andric void DiffConsumer::exitContext() {
1470b57cec5SDimitry Andric Differences |= contexts.back().Differences;
1480b57cec5SDimitry Andric contexts.pop_back();
1490b57cec5SDimitry Andric Indent -= 2;
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric
log(StringRef text)1520b57cec5SDimitry Andric void DiffConsumer::log(StringRef text) {
1530b57cec5SDimitry Andric header();
1540b57cec5SDimitry Andric indent();
1550b57cec5SDimitry Andric out << text << '\n';
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
logf(const LogBuilder & Log)1580b57cec5SDimitry Andric void DiffConsumer::logf(const LogBuilder &Log) {
1590b57cec5SDimitry Andric header();
1600b57cec5SDimitry Andric indent();
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric unsigned arg = 0;
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric StringRef format = Log.getFormat();
1650b57cec5SDimitry Andric while (true) {
1660b57cec5SDimitry Andric size_t percent = format.find('%');
1670b57cec5SDimitry Andric if (percent == StringRef::npos) {
1680b57cec5SDimitry Andric out << format;
1690b57cec5SDimitry Andric break;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric assert(format[percent] == '%');
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric if (percent > 0) out << format.substr(0, percent);
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric switch (format[percent+1]) {
1760b57cec5SDimitry Andric case '%': out << '%'; break;
1770b57cec5SDimitry Andric case 'l': printValue(Log.getArgument(arg++), true); break;
1780b57cec5SDimitry Andric case 'r': printValue(Log.getArgument(arg++), false); break;
1790b57cec5SDimitry Andric default: llvm_unreachable("unknown format character");
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric format = format.substr(percent+2);
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric out << '\n';
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
logd(const DiffLogBuilder & Log)1880b57cec5SDimitry Andric void DiffConsumer::logd(const DiffLogBuilder &Log) {
1890b57cec5SDimitry Andric header();
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1920b57cec5SDimitry Andric indent();
1930b57cec5SDimitry Andric switch (Log.getLineKind(I)) {
1940b57cec5SDimitry Andric case DC_match:
1950b57cec5SDimitry Andric out << " ";
1960b57cec5SDimitry Andric Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
1970b57cec5SDimitry Andric //printValue(Log.getLeft(I), true);
1980b57cec5SDimitry Andric break;
1990b57cec5SDimitry Andric case DC_left:
2000b57cec5SDimitry Andric out << "< ";
2010b57cec5SDimitry Andric Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2020b57cec5SDimitry Andric //printValue(Log.getLeft(I), true);
2030b57cec5SDimitry Andric break;
2040b57cec5SDimitry Andric case DC_right:
2050b57cec5SDimitry Andric out << "> ";
2060b57cec5SDimitry Andric Log.getRight(I)->print(dbgs()); dbgs() << '\n';
2070b57cec5SDimitry Andric //printValue(Log.getRight(I), false);
2080b57cec5SDimitry Andric break;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric //out << "\n";
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric }
213