14d293f21SBill Wendling //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
24d293f21SBill Wendling //
34d293f21SBill Wendling // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d293f21SBill Wendling // See https://llvm.org/LICENSE.txt for license information.
54d293f21SBill Wendling // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d293f21SBill Wendling //
74d293f21SBill Wendling //===----------------------------------------------------------------------===//
84d293f21SBill Wendling //
94d293f21SBill Wendling // This files implements the LLVM difference Consumer
104d293f21SBill Wendling //
114d293f21SBill Wendling //===----------------------------------------------------------------------===//
124d293f21SBill Wendling
134d293f21SBill Wendling #include "DiffConsumer.h"
144d293f21SBill Wendling #include "llvm/IR/Instructions.h"
154d293f21SBill Wendling #include "llvm/Support/Debug.h"
164d293f21SBill Wendling #include "llvm/Support/ErrorHandling.h"
174d293f21SBill Wendling
184d293f21SBill Wendling using namespace llvm;
194d293f21SBill Wendling
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)204d293f21SBill Wendling static void ComputeNumbering(const Function *F,
214d293f21SBill Wendling DenseMap<const Value *, unsigned> &Numbering) {
224d293f21SBill Wendling unsigned IN = 0;
234d293f21SBill Wendling
244d293f21SBill Wendling // Arguments get the first numbers.
254d293f21SBill Wendling for (const auto &Arg : F->args())
264d293f21SBill Wendling if (!Arg.hasName())
274d293f21SBill Wendling Numbering[&Arg] = IN++;
284d293f21SBill Wendling
294d293f21SBill Wendling // Walk the basic blocks in order.
304d293f21SBill Wendling for (const auto &Func : *F) {
314d293f21SBill Wendling if (!Func.hasName())
324d293f21SBill Wendling Numbering[&Func] = IN++;
334d293f21SBill Wendling
344d293f21SBill Wendling // Walk the instructions in order.
354d293f21SBill Wendling for (const auto &BB : Func)
364d293f21SBill Wendling // void instructions don't get numbers.
374d293f21SBill Wendling if (!BB.hasName() && !BB.getType()->isVoidTy())
384d293f21SBill Wendling Numbering[&BB] = IN++;
394d293f21SBill Wendling }
404d293f21SBill Wendling
414d293f21SBill Wendling assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
424d293f21SBill Wendling }
434d293f21SBill Wendling
anchor()444d293f21SBill Wendling void Consumer::anchor() { }
454d293f21SBill Wendling
printValue(const Value * V,bool isL)464d293f21SBill Wendling void DiffConsumer::printValue(const Value *V, bool isL) {
474d293f21SBill Wendling if (V->hasName()) {
484d293f21SBill Wendling out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
494d293f21SBill Wendling return;
504d293f21SBill Wendling }
514d293f21SBill Wendling if (V->getType()->isVoidTy()) {
524d293f21SBill Wendling if (auto *SI = dyn_cast<StoreInst>(V)) {
534d293f21SBill Wendling out << "store to ";
544d293f21SBill Wendling printValue(SI->getPointerOperand(), isL);
554d293f21SBill Wendling } else if (auto *CI = dyn_cast<CallInst>(V)) {
564d293f21SBill Wendling out << "call to ";
574d293f21SBill Wendling printValue(CI->getCalledOperand(), isL);
584d293f21SBill Wendling } else if (auto *II = dyn_cast<InvokeInst>(V)) {
594d293f21SBill Wendling out << "invoke to ";
604d293f21SBill Wendling printValue(II->getCalledOperand(), isL);
614d293f21SBill Wendling } else {
624d293f21SBill Wendling out << *V;
634d293f21SBill Wendling }
644d293f21SBill Wendling return;
654d293f21SBill Wendling }
664d293f21SBill Wendling if (isa<Constant>(V)) {
674d293f21SBill Wendling out << *V;
684d293f21SBill Wendling return;
694d293f21SBill Wendling }
704d293f21SBill Wendling
714d293f21SBill Wendling unsigned N = contexts.size();
724d293f21SBill Wendling while (N > 0) {
734d293f21SBill Wendling --N;
744d293f21SBill Wendling DiffContext &ctxt = contexts[N];
754d293f21SBill Wendling if (!ctxt.IsFunction) continue;
764d293f21SBill Wendling if (isL) {
774d293f21SBill Wendling if (ctxt.LNumbering.empty())
784d293f21SBill Wendling ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
794d293f21SBill Wendling out << '%' << ctxt.LNumbering[V];
804d293f21SBill Wendling return;
814d293f21SBill Wendling } else {
824d293f21SBill Wendling if (ctxt.RNumbering.empty())
834d293f21SBill Wendling ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
844d293f21SBill Wendling out << '%' << ctxt.RNumbering[V];
854d293f21SBill Wendling return;
864d293f21SBill Wendling }
874d293f21SBill Wendling }
884d293f21SBill Wendling
894d293f21SBill Wendling out << "<anonymous>";
904d293f21SBill Wendling }
914d293f21SBill Wendling
header()924d293f21SBill Wendling void DiffConsumer::header() {
934d293f21SBill Wendling if (contexts.empty()) return;
944d293f21SBill Wendling for (SmallVectorImpl<DiffContext>::iterator
954d293f21SBill Wendling I = contexts.begin(), E = contexts.end(); I != E; ++I) {
964d293f21SBill Wendling if (I->Differences) continue;
974d293f21SBill Wendling if (isa<Function>(I->L)) {
984d293f21SBill Wendling // Extra newline between functions.
994d293f21SBill Wendling if (Differences) out << "\n";
1004d293f21SBill Wendling
1014d293f21SBill Wendling const Function *L = cast<Function>(I->L);
1024d293f21SBill Wendling const Function *R = cast<Function>(I->R);
1034d293f21SBill Wendling if (L->getName() != R->getName())
1044d293f21SBill Wendling out << "in function " << L->getName()
1054d293f21SBill Wendling << " / " << R->getName() << ":\n";
1064d293f21SBill Wendling else
1074d293f21SBill Wendling out << "in function " << L->getName() << ":\n";
1084d293f21SBill Wendling } else if (isa<BasicBlock>(I->L)) {
1094d293f21SBill Wendling const BasicBlock *L = cast<BasicBlock>(I->L);
1104d293f21SBill Wendling const BasicBlock *R = cast<BasicBlock>(I->R);
1114d293f21SBill Wendling if (L->hasName() && R->hasName() && L->getName() == R->getName())
1124d293f21SBill Wendling out << " in block %" << L->getName() << ":\n";
1134d293f21SBill Wendling else {
1144d293f21SBill Wendling out << " in block ";
1154d293f21SBill Wendling printValue(L, true);
1164d293f21SBill Wendling out << " / ";
1174d293f21SBill Wendling printValue(R, false);
1184d293f21SBill Wendling out << ":\n";
1194d293f21SBill Wendling }
1204d293f21SBill Wendling } else if (isa<Instruction>(I->L)) {
1214d293f21SBill Wendling out << " in instruction ";
1224d293f21SBill Wendling printValue(I->L, true);
1234d293f21SBill Wendling out << " / ";
1244d293f21SBill Wendling printValue(I->R, false);
1254d293f21SBill Wendling out << ":\n";
1264d293f21SBill Wendling }
1274d293f21SBill Wendling
1284d293f21SBill Wendling I->Differences = true;
1294d293f21SBill Wendling }
1304d293f21SBill Wendling }
1314d293f21SBill Wendling
indent()1324d293f21SBill Wendling void DiffConsumer::indent() {
1334d293f21SBill Wendling unsigned N = Indent;
1344d293f21SBill Wendling while (N--) out << ' ';
1354d293f21SBill Wendling }
1364d293f21SBill Wendling
reset()13739809eb1SBill Wendling void DiffConsumer::reset() {
138*b61359f9SBill Wendling contexts.clear();
13939809eb1SBill Wendling Differences = false;
14039809eb1SBill Wendling Indent = 0;
14139809eb1SBill Wendling }
14239809eb1SBill Wendling
hadDifferences() const1434d293f21SBill Wendling bool DiffConsumer::hadDifferences() const {
1444d293f21SBill Wendling return Differences;
1454d293f21SBill Wendling }
1464d293f21SBill Wendling
enterContext(const Value * L,const Value * R)1474d293f21SBill Wendling void DiffConsumer::enterContext(const Value *L, const Value *R) {
1484d293f21SBill Wendling contexts.push_back(DiffContext(L, R));
1494d293f21SBill Wendling Indent += 2;
1504d293f21SBill Wendling }
1514d293f21SBill Wendling
exitContext()1524d293f21SBill Wendling void DiffConsumer::exitContext() {
1534d293f21SBill Wendling Differences |= contexts.back().Differences;
1544d293f21SBill Wendling contexts.pop_back();
1554d293f21SBill Wendling Indent -= 2;
1564d293f21SBill Wendling }
1574d293f21SBill Wendling
log(StringRef text)1584d293f21SBill Wendling void DiffConsumer::log(StringRef text) {
1594d293f21SBill Wendling header();
1604d293f21SBill Wendling indent();
1614d293f21SBill Wendling out << text << '\n';
1624d293f21SBill Wendling }
1634d293f21SBill Wendling
logf(const LogBuilder & Log)1644d293f21SBill Wendling void DiffConsumer::logf(const LogBuilder &Log) {
1654d293f21SBill Wendling header();
1664d293f21SBill Wendling indent();
1674d293f21SBill Wendling
1684d293f21SBill Wendling unsigned arg = 0;
1694d293f21SBill Wendling
1704d293f21SBill Wendling StringRef format = Log.getFormat();
1714d293f21SBill Wendling while (true) {
1724d293f21SBill Wendling size_t percent = format.find('%');
1734d293f21SBill Wendling if (percent == StringRef::npos) {
1744d293f21SBill Wendling out << format;
1754d293f21SBill Wendling break;
1764d293f21SBill Wendling }
1774d293f21SBill Wendling assert(format[percent] == '%');
1784d293f21SBill Wendling
1794d293f21SBill Wendling if (percent > 0) out << format.substr(0, percent);
1804d293f21SBill Wendling
1814d293f21SBill Wendling switch (format[percent+1]) {
1824d293f21SBill Wendling case '%': out << '%'; break;
1834d293f21SBill Wendling case 'l': printValue(Log.getArgument(arg++), true); break;
1844d293f21SBill Wendling case 'r': printValue(Log.getArgument(arg++), false); break;
1854d293f21SBill Wendling default: llvm_unreachable("unknown format character");
1864d293f21SBill Wendling }
1874d293f21SBill Wendling
1884d293f21SBill Wendling format = format.substr(percent+2);
1894d293f21SBill Wendling }
1904d293f21SBill Wendling
1914d293f21SBill Wendling out << '\n';
1924d293f21SBill Wendling }
1934d293f21SBill Wendling
logd(const DiffLogBuilder & Log)1944d293f21SBill Wendling void DiffConsumer::logd(const DiffLogBuilder &Log) {
1954d293f21SBill Wendling header();
1964d293f21SBill Wendling
1974d293f21SBill Wendling for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1984d293f21SBill Wendling indent();
1994d293f21SBill Wendling switch (Log.getLineKind(I)) {
2004d293f21SBill Wendling case DC_match:
2014d293f21SBill Wendling out << " ";
2024d293f21SBill Wendling Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2034d293f21SBill Wendling //printValue(Log.getLeft(I), true);
2044d293f21SBill Wendling break;
2054d293f21SBill Wendling case DC_left:
2064d293f21SBill Wendling out << "< ";
2074d293f21SBill Wendling Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2084d293f21SBill Wendling //printValue(Log.getLeft(I), true);
2094d293f21SBill Wendling break;
2104d293f21SBill Wendling case DC_right:
2114d293f21SBill Wendling out << "> ";
2124d293f21SBill Wendling Log.getRight(I)->print(dbgs()); dbgs() << '\n';
2134d293f21SBill Wendling //printValue(Log.getRight(I), false);
2144d293f21SBill Wendling break;
2154d293f21SBill Wendling }
2164d293f21SBill Wendling //out << "\n";
2174d293f21SBill Wendling }
2184d293f21SBill Wendling }
219