16b943ff3SDimitry Andric //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
26b943ff3SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66b943ff3SDimitry Andric //
76b943ff3SDimitry Andric //===----------------------------------------------------------------------===//
86b943ff3SDimitry Andric //
958b69754SDimitry Andric // This files implements the LLVM difference Consumer
106b943ff3SDimitry Andric //
116b943ff3SDimitry Andric //===----------------------------------------------------------------------===//
126b943ff3SDimitry Andric
136b943ff3SDimitry Andric #include "DiffConsumer.h"
144a16efa3SDimitry Andric #include "llvm/IR/Instructions.h"
1571d5a254SDimitry Andric #include "llvm/Support/Debug.h"
16e6d15924SDimitry Andric #include "llvm/Support/ErrorHandling.h"
176b943ff3SDimitry Andric
186b943ff3SDimitry Andric using namespace llvm;
196b943ff3SDimitry Andric
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)20344a3780SDimitry Andric static void ComputeNumbering(const Function *F,
21344a3780SDimitry Andric DenseMap<const Value *, unsigned> &Numbering) {
226b943ff3SDimitry Andric unsigned IN = 0;
236b943ff3SDimitry Andric
246b943ff3SDimitry Andric // Arguments get the first numbers.
25344a3780SDimitry Andric for (const auto &Arg : F->args())
26344a3780SDimitry Andric if (!Arg.hasName())
27344a3780SDimitry Andric Numbering[&Arg] = IN++;
286b943ff3SDimitry Andric
296b943ff3SDimitry Andric // Walk the basic blocks in order.
30344a3780SDimitry Andric for (const auto &Func : *F) {
31344a3780SDimitry Andric if (!Func.hasName())
32344a3780SDimitry Andric Numbering[&Func] = IN++;
336b943ff3SDimitry Andric
346b943ff3SDimitry Andric // Walk the instructions in order.
35344a3780SDimitry Andric for (const auto &BB : Func)
366b943ff3SDimitry Andric // void instructions don't get numbers.
37344a3780SDimitry Andric if (!BB.hasName() && !BB.getType()->isVoidTy())
38344a3780SDimitry Andric Numbering[&BB] = IN++;
396b943ff3SDimitry Andric }
406b943ff3SDimitry Andric
416b943ff3SDimitry Andric assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
426b943ff3SDimitry Andric }
436b943ff3SDimitry Andric
anchor()4463faed5bSDimitry Andric void Consumer::anchor() { }
4563faed5bSDimitry Andric
printValue(const Value * V,bool isL)46344a3780SDimitry Andric void DiffConsumer::printValue(const Value *V, bool isL) {
476b943ff3SDimitry Andric if (V->hasName()) {
486b943ff3SDimitry Andric out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
496b943ff3SDimitry Andric return;
506b943ff3SDimitry Andric }
516b943ff3SDimitry Andric if (V->getType()->isVoidTy()) {
52cfca06d7SDimitry Andric if (auto *SI = dyn_cast<StoreInst>(V)) {
536b943ff3SDimitry Andric out << "store to ";
54cfca06d7SDimitry Andric printValue(SI->getPointerOperand(), isL);
55cfca06d7SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(V)) {
566b943ff3SDimitry Andric out << "call to ";
57cfca06d7SDimitry Andric printValue(CI->getCalledOperand(), isL);
58cfca06d7SDimitry Andric } else if (auto *II = dyn_cast<InvokeInst>(V)) {
596b943ff3SDimitry Andric out << "invoke to ";
60cfca06d7SDimitry Andric printValue(II->getCalledOperand(), isL);
616b943ff3SDimitry Andric } else {
626b943ff3SDimitry Andric out << *V;
636b943ff3SDimitry Andric }
646b943ff3SDimitry Andric return;
656b943ff3SDimitry Andric }
6663faed5bSDimitry Andric if (isa<Constant>(V)) {
6763faed5bSDimitry Andric out << *V;
6863faed5bSDimitry Andric return;
6963faed5bSDimitry Andric }
706b943ff3SDimitry Andric
716b943ff3SDimitry Andric unsigned N = contexts.size();
726b943ff3SDimitry Andric while (N > 0) {
736b943ff3SDimitry Andric --N;
746b943ff3SDimitry Andric DiffContext &ctxt = contexts[N];
756b943ff3SDimitry Andric if (!ctxt.IsFunction) continue;
766b943ff3SDimitry Andric if (isL) {
776b943ff3SDimitry Andric if (ctxt.LNumbering.empty())
786b943ff3SDimitry Andric ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
796b943ff3SDimitry Andric out << '%' << ctxt.LNumbering[V];
806b943ff3SDimitry Andric return;
816b943ff3SDimitry Andric } else {
826b943ff3SDimitry Andric if (ctxt.RNumbering.empty())
836b943ff3SDimitry Andric ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
846b943ff3SDimitry Andric out << '%' << ctxt.RNumbering[V];
856b943ff3SDimitry Andric return;
866b943ff3SDimitry Andric }
876b943ff3SDimitry Andric }
886b943ff3SDimitry Andric
896b943ff3SDimitry Andric out << "<anonymous>";
906b943ff3SDimitry Andric }
916b943ff3SDimitry Andric
header()926b943ff3SDimitry Andric void DiffConsumer::header() {
936b943ff3SDimitry Andric if (contexts.empty()) return;
946b943ff3SDimitry Andric for (SmallVectorImpl<DiffContext>::iterator
956b943ff3SDimitry Andric I = contexts.begin(), E = contexts.end(); I != E; ++I) {
966b943ff3SDimitry Andric if (I->Differences) continue;
976b943ff3SDimitry Andric if (isa<Function>(I->L)) {
986b943ff3SDimitry Andric // Extra newline between functions.
996b943ff3SDimitry Andric if (Differences) out << "\n";
1006b943ff3SDimitry Andric
101344a3780SDimitry Andric const Function *L = cast<Function>(I->L);
102344a3780SDimitry Andric const Function *R = cast<Function>(I->R);
1036b943ff3SDimitry Andric if (L->getName() != R->getName())
1046b943ff3SDimitry Andric out << "in function " << L->getName()
1056b943ff3SDimitry Andric << " / " << R->getName() << ":\n";
1066b943ff3SDimitry Andric else
1076b943ff3SDimitry Andric out << "in function " << L->getName() << ":\n";
1086b943ff3SDimitry Andric } else if (isa<BasicBlock>(I->L)) {
109344a3780SDimitry Andric const BasicBlock *L = cast<BasicBlock>(I->L);
110344a3780SDimitry Andric const BasicBlock *R = cast<BasicBlock>(I->R);
1116b943ff3SDimitry Andric if (L->hasName() && R->hasName() && L->getName() == R->getName())
1126b943ff3SDimitry Andric out << " in block %" << L->getName() << ":\n";
1136b943ff3SDimitry Andric else {
1146b943ff3SDimitry Andric out << " in block ";
1156b943ff3SDimitry Andric printValue(L, true);
1166b943ff3SDimitry Andric out << " / ";
1176b943ff3SDimitry Andric printValue(R, false);
1186b943ff3SDimitry Andric out << ":\n";
1196b943ff3SDimitry Andric }
1206b943ff3SDimitry Andric } else if (isa<Instruction>(I->L)) {
1216b943ff3SDimitry Andric out << " in instruction ";
1226b943ff3SDimitry Andric printValue(I->L, true);
1236b943ff3SDimitry Andric out << " / ";
1246b943ff3SDimitry Andric printValue(I->R, false);
1256b943ff3SDimitry Andric out << ":\n";
1266b943ff3SDimitry Andric }
1276b943ff3SDimitry Andric
1286b943ff3SDimitry Andric I->Differences = true;
1296b943ff3SDimitry Andric }
1306b943ff3SDimitry Andric }
1316b943ff3SDimitry Andric
indent()1326b943ff3SDimitry Andric void DiffConsumer::indent() {
1336b943ff3SDimitry Andric unsigned N = Indent;
1346b943ff3SDimitry Andric while (N--) out << ' ';
1356b943ff3SDimitry Andric }
1366b943ff3SDimitry Andric
reset()137c0981da4SDimitry Andric void DiffConsumer::reset() {
138c0981da4SDimitry Andric contexts.clear();
139c0981da4SDimitry Andric Differences = false;
140c0981da4SDimitry Andric Indent = 0;
141c0981da4SDimitry Andric }
142c0981da4SDimitry Andric
hadDifferences() const1436b943ff3SDimitry Andric bool DiffConsumer::hadDifferences() const {
1446b943ff3SDimitry Andric return Differences;
1456b943ff3SDimitry Andric }
1466b943ff3SDimitry Andric
enterContext(const Value * L,const Value * R)147344a3780SDimitry Andric void DiffConsumer::enterContext(const Value *L, const Value *R) {
1486b943ff3SDimitry Andric contexts.push_back(DiffContext(L, R));
1496b943ff3SDimitry Andric Indent += 2;
1506b943ff3SDimitry Andric }
1516b943ff3SDimitry Andric
exitContext()1526b943ff3SDimitry Andric void DiffConsumer::exitContext() {
1536b943ff3SDimitry Andric Differences |= contexts.back().Differences;
1546b943ff3SDimitry Andric contexts.pop_back();
1556b943ff3SDimitry Andric Indent -= 2;
1566b943ff3SDimitry Andric }
1576b943ff3SDimitry Andric
log(StringRef text)1586b943ff3SDimitry Andric void DiffConsumer::log(StringRef text) {
1596b943ff3SDimitry Andric header();
1606b943ff3SDimitry Andric indent();
1616b943ff3SDimitry Andric out << text << '\n';
1626b943ff3SDimitry Andric }
1636b943ff3SDimitry Andric
logf(const LogBuilder & Log)1646b943ff3SDimitry Andric void DiffConsumer::logf(const LogBuilder &Log) {
1656b943ff3SDimitry Andric header();
1666b943ff3SDimitry Andric indent();
1676b943ff3SDimitry Andric
1686b943ff3SDimitry Andric unsigned arg = 0;
1696b943ff3SDimitry Andric
1706b943ff3SDimitry Andric StringRef format = Log.getFormat();
1716b943ff3SDimitry Andric while (true) {
1726b943ff3SDimitry Andric size_t percent = format.find('%');
1736b943ff3SDimitry Andric if (percent == StringRef::npos) {
1746b943ff3SDimitry Andric out << format;
1756b943ff3SDimitry Andric break;
1766b943ff3SDimitry Andric }
1776b943ff3SDimitry Andric assert(format[percent] == '%');
1786b943ff3SDimitry Andric
1796b943ff3SDimitry Andric if (percent > 0) out << format.substr(0, percent);
1806b943ff3SDimitry Andric
1816b943ff3SDimitry Andric switch (format[percent+1]) {
1826b943ff3SDimitry Andric case '%': out << '%'; break;
1836b943ff3SDimitry Andric case 'l': printValue(Log.getArgument(arg++), true); break;
1846b943ff3SDimitry Andric case 'r': printValue(Log.getArgument(arg++), false); break;
1856b943ff3SDimitry Andric default: llvm_unreachable("unknown format character");
1866b943ff3SDimitry Andric }
1876b943ff3SDimitry Andric
1886b943ff3SDimitry Andric format = format.substr(percent+2);
1896b943ff3SDimitry Andric }
1906b943ff3SDimitry Andric
1916b943ff3SDimitry Andric out << '\n';
1926b943ff3SDimitry Andric }
1936b943ff3SDimitry Andric
logd(const DiffLogBuilder & Log)1946b943ff3SDimitry Andric void DiffConsumer::logd(const DiffLogBuilder &Log) {
1956b943ff3SDimitry Andric header();
1966b943ff3SDimitry Andric
1976b943ff3SDimitry Andric for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1986b943ff3SDimitry Andric indent();
1996b943ff3SDimitry Andric switch (Log.getLineKind(I)) {
2006b943ff3SDimitry Andric case DC_match:
2016b943ff3SDimitry Andric out << " ";
20271d5a254SDimitry Andric Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2036b943ff3SDimitry Andric //printValue(Log.getLeft(I), true);
2046b943ff3SDimitry Andric break;
2056b943ff3SDimitry Andric case DC_left:
2066b943ff3SDimitry Andric out << "< ";
20771d5a254SDimitry Andric Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2086b943ff3SDimitry Andric //printValue(Log.getLeft(I), true);
2096b943ff3SDimitry Andric break;
2106b943ff3SDimitry Andric case DC_right:
2116b943ff3SDimitry Andric out << "> ";
21271d5a254SDimitry Andric Log.getRight(I)->print(dbgs()); dbgs() << '\n';
2136b943ff3SDimitry Andric //printValue(Log.getRight(I), false);
2146b943ff3SDimitry Andric break;
2156b943ff3SDimitry Andric }
2166b943ff3SDimitry Andric //out << "\n";
2176b943ff3SDimitry Andric }
2186b943ff3SDimitry Andric }
219