1*349cc55cSDimitry Andric //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
2*349cc55cSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*349cc55cSDimitry Andric //
7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8*349cc55cSDimitry Andric //
9*349cc55cSDimitry Andric // This files implements the LLVM difference Consumer
10*349cc55cSDimitry Andric //
11*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
12*349cc55cSDimitry Andric 
13*349cc55cSDimitry Andric #include "DiffConsumer.h"
14*349cc55cSDimitry Andric #include "llvm/IR/Instructions.h"
15*349cc55cSDimitry Andric #include "llvm/Support/Debug.h"
16*349cc55cSDimitry Andric #include "llvm/Support/ErrorHandling.h"
17*349cc55cSDimitry Andric 
18*349cc55cSDimitry Andric using namespace llvm;
19*349cc55cSDimitry Andric 
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)20*349cc55cSDimitry Andric static void ComputeNumbering(const Function *F,
21*349cc55cSDimitry Andric                              DenseMap<const Value *, unsigned> &Numbering) {
22*349cc55cSDimitry Andric   unsigned IN = 0;
23*349cc55cSDimitry Andric 
24*349cc55cSDimitry Andric   // Arguments get the first numbers.
25*349cc55cSDimitry Andric   for (const auto &Arg : F->args())
26*349cc55cSDimitry Andric     if (!Arg.hasName())
27*349cc55cSDimitry Andric       Numbering[&Arg] = IN++;
28*349cc55cSDimitry Andric 
29*349cc55cSDimitry Andric   // Walk the basic blocks in order.
30*349cc55cSDimitry Andric   for (const auto &Func : *F) {
31*349cc55cSDimitry Andric     if (!Func.hasName())
32*349cc55cSDimitry Andric       Numbering[&Func] = IN++;
33*349cc55cSDimitry Andric 
34*349cc55cSDimitry Andric     // Walk the instructions in order.
35*349cc55cSDimitry Andric     for (const auto &BB : Func)
36*349cc55cSDimitry Andric       // void instructions don't get numbers.
37*349cc55cSDimitry Andric       if (!BB.hasName() && !BB.getType()->isVoidTy())
38*349cc55cSDimitry Andric         Numbering[&BB] = IN++;
39*349cc55cSDimitry Andric   }
40*349cc55cSDimitry Andric 
41*349cc55cSDimitry Andric   assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
42*349cc55cSDimitry Andric }
43*349cc55cSDimitry Andric 
anchor()44*349cc55cSDimitry Andric void Consumer::anchor() { }
45*349cc55cSDimitry Andric 
printValue(const Value * V,bool isL)46*349cc55cSDimitry Andric void DiffConsumer::printValue(const Value *V, bool isL) {
47*349cc55cSDimitry Andric   if (V->hasName()) {
48*349cc55cSDimitry Andric     out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
49*349cc55cSDimitry Andric     return;
50*349cc55cSDimitry Andric   }
51*349cc55cSDimitry Andric   if (V->getType()->isVoidTy()) {
52*349cc55cSDimitry Andric     if (auto *SI = dyn_cast<StoreInst>(V)) {
53*349cc55cSDimitry Andric       out << "store to ";
54*349cc55cSDimitry Andric       printValue(SI->getPointerOperand(), isL);
55*349cc55cSDimitry Andric     } else if (auto *CI = dyn_cast<CallInst>(V)) {
56*349cc55cSDimitry Andric       out << "call to ";
57*349cc55cSDimitry Andric       printValue(CI->getCalledOperand(), isL);
58*349cc55cSDimitry Andric     } else if (auto *II = dyn_cast<InvokeInst>(V)) {
59*349cc55cSDimitry Andric       out << "invoke to ";
60*349cc55cSDimitry Andric       printValue(II->getCalledOperand(), isL);
61*349cc55cSDimitry Andric     } else {
62*349cc55cSDimitry Andric       out << *V;
63*349cc55cSDimitry Andric     }
64*349cc55cSDimitry Andric     return;
65*349cc55cSDimitry Andric   }
66*349cc55cSDimitry Andric   if (isa<Constant>(V)) {
67*349cc55cSDimitry Andric     out << *V;
68*349cc55cSDimitry Andric     return;
69*349cc55cSDimitry Andric   }
70*349cc55cSDimitry Andric 
71*349cc55cSDimitry Andric   unsigned N = contexts.size();
72*349cc55cSDimitry Andric   while (N > 0) {
73*349cc55cSDimitry Andric     --N;
74*349cc55cSDimitry Andric     DiffContext &ctxt = contexts[N];
75*349cc55cSDimitry Andric     if (!ctxt.IsFunction) continue;
76*349cc55cSDimitry Andric     if (isL) {
77*349cc55cSDimitry Andric       if (ctxt.LNumbering.empty())
78*349cc55cSDimitry Andric         ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
79*349cc55cSDimitry Andric       out << '%' << ctxt.LNumbering[V];
80*349cc55cSDimitry Andric       return;
81*349cc55cSDimitry Andric     } else {
82*349cc55cSDimitry Andric       if (ctxt.RNumbering.empty())
83*349cc55cSDimitry Andric         ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
84*349cc55cSDimitry Andric       out << '%' << ctxt.RNumbering[V];
85*349cc55cSDimitry Andric       return;
86*349cc55cSDimitry Andric     }
87*349cc55cSDimitry Andric   }
88*349cc55cSDimitry Andric 
89*349cc55cSDimitry Andric   out << "<anonymous>";
90*349cc55cSDimitry Andric }
91*349cc55cSDimitry Andric 
header()92*349cc55cSDimitry Andric void DiffConsumer::header() {
93*349cc55cSDimitry Andric   if (contexts.empty()) return;
94*349cc55cSDimitry Andric   for (SmallVectorImpl<DiffContext>::iterator
95*349cc55cSDimitry Andric          I = contexts.begin(), E = contexts.end(); I != E; ++I) {
96*349cc55cSDimitry Andric     if (I->Differences) continue;
97*349cc55cSDimitry Andric     if (isa<Function>(I->L)) {
98*349cc55cSDimitry Andric       // Extra newline between functions.
99*349cc55cSDimitry Andric       if (Differences) out << "\n";
100*349cc55cSDimitry Andric 
101*349cc55cSDimitry Andric       const Function *L = cast<Function>(I->L);
102*349cc55cSDimitry Andric       const Function *R = cast<Function>(I->R);
103*349cc55cSDimitry Andric       if (L->getName() != R->getName())
104*349cc55cSDimitry Andric         out << "in function " << L->getName()
105*349cc55cSDimitry Andric             << " / " << R->getName() << ":\n";
106*349cc55cSDimitry Andric       else
107*349cc55cSDimitry Andric         out << "in function " << L->getName() << ":\n";
108*349cc55cSDimitry Andric     } else if (isa<BasicBlock>(I->L)) {
109*349cc55cSDimitry Andric       const BasicBlock *L = cast<BasicBlock>(I->L);
110*349cc55cSDimitry Andric       const BasicBlock *R = cast<BasicBlock>(I->R);
111*349cc55cSDimitry Andric       if (L->hasName() && R->hasName() && L->getName() == R->getName())
112*349cc55cSDimitry Andric         out << "  in block %" << L->getName() << ":\n";
113*349cc55cSDimitry Andric       else {
114*349cc55cSDimitry Andric         out << "  in block ";
115*349cc55cSDimitry Andric         printValue(L, true);
116*349cc55cSDimitry Andric         out << " / ";
117*349cc55cSDimitry Andric         printValue(R, false);
118*349cc55cSDimitry Andric         out << ":\n";
119*349cc55cSDimitry Andric       }
120*349cc55cSDimitry Andric     } else if (isa<Instruction>(I->L)) {
121*349cc55cSDimitry Andric       out << "    in instruction ";
122*349cc55cSDimitry Andric       printValue(I->L, true);
123*349cc55cSDimitry Andric       out << " / ";
124*349cc55cSDimitry Andric       printValue(I->R, false);
125*349cc55cSDimitry Andric       out << ":\n";
126*349cc55cSDimitry Andric     }
127*349cc55cSDimitry Andric 
128*349cc55cSDimitry Andric     I->Differences = true;
129*349cc55cSDimitry Andric   }
130*349cc55cSDimitry Andric }
131*349cc55cSDimitry Andric 
indent()132*349cc55cSDimitry Andric void DiffConsumer::indent() {
133*349cc55cSDimitry Andric   unsigned N = Indent;
134*349cc55cSDimitry Andric   while (N--) out << ' ';
135*349cc55cSDimitry Andric }
136*349cc55cSDimitry Andric 
reset()137*349cc55cSDimitry Andric void DiffConsumer::reset() {
138*349cc55cSDimitry Andric   contexts.clear();
139*349cc55cSDimitry Andric   Differences = false;
140*349cc55cSDimitry Andric   Indent = 0;
141*349cc55cSDimitry Andric }
142*349cc55cSDimitry Andric 
hadDifferences() const143*349cc55cSDimitry Andric bool DiffConsumer::hadDifferences() const {
144*349cc55cSDimitry Andric   return Differences;
145*349cc55cSDimitry Andric }
146*349cc55cSDimitry Andric 
enterContext(const Value * L,const Value * R)147*349cc55cSDimitry Andric void DiffConsumer::enterContext(const Value *L, const Value *R) {
148*349cc55cSDimitry Andric   contexts.push_back(DiffContext(L, R));
149*349cc55cSDimitry Andric   Indent += 2;
150*349cc55cSDimitry Andric }
151*349cc55cSDimitry Andric 
exitContext()152*349cc55cSDimitry Andric void DiffConsumer::exitContext() {
153*349cc55cSDimitry Andric   Differences |= contexts.back().Differences;
154*349cc55cSDimitry Andric   contexts.pop_back();
155*349cc55cSDimitry Andric   Indent -= 2;
156*349cc55cSDimitry Andric }
157*349cc55cSDimitry Andric 
log(StringRef text)158*349cc55cSDimitry Andric void DiffConsumer::log(StringRef text) {
159*349cc55cSDimitry Andric   header();
160*349cc55cSDimitry Andric   indent();
161*349cc55cSDimitry Andric   out << text << '\n';
162*349cc55cSDimitry Andric }
163*349cc55cSDimitry Andric 
logf(const LogBuilder & Log)164*349cc55cSDimitry Andric void DiffConsumer::logf(const LogBuilder &Log) {
165*349cc55cSDimitry Andric   header();
166*349cc55cSDimitry Andric   indent();
167*349cc55cSDimitry Andric 
168*349cc55cSDimitry Andric   unsigned arg = 0;
169*349cc55cSDimitry Andric 
170*349cc55cSDimitry Andric   StringRef format = Log.getFormat();
171*349cc55cSDimitry Andric   while (true) {
172*349cc55cSDimitry Andric     size_t percent = format.find('%');
173*349cc55cSDimitry Andric     if (percent == StringRef::npos) {
174*349cc55cSDimitry Andric       out << format;
175*349cc55cSDimitry Andric       break;
176*349cc55cSDimitry Andric     }
177*349cc55cSDimitry Andric     assert(format[percent] == '%');
178*349cc55cSDimitry Andric 
179*349cc55cSDimitry Andric     if (percent > 0) out << format.substr(0, percent);
180*349cc55cSDimitry Andric 
181*349cc55cSDimitry Andric     switch (format[percent+1]) {
182*349cc55cSDimitry Andric     case '%': out << '%'; break;
183*349cc55cSDimitry Andric     case 'l': printValue(Log.getArgument(arg++), true); break;
184*349cc55cSDimitry Andric     case 'r': printValue(Log.getArgument(arg++), false); break;
185*349cc55cSDimitry Andric     default: llvm_unreachable("unknown format character");
186*349cc55cSDimitry Andric     }
187*349cc55cSDimitry Andric 
188*349cc55cSDimitry Andric     format = format.substr(percent+2);
189*349cc55cSDimitry Andric   }
190*349cc55cSDimitry Andric 
191*349cc55cSDimitry Andric   out << '\n';
192*349cc55cSDimitry Andric }
193*349cc55cSDimitry Andric 
logd(const DiffLogBuilder & Log)194*349cc55cSDimitry Andric void DiffConsumer::logd(const DiffLogBuilder &Log) {
195*349cc55cSDimitry Andric   header();
196*349cc55cSDimitry Andric 
197*349cc55cSDimitry Andric   for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
198*349cc55cSDimitry Andric     indent();
199*349cc55cSDimitry Andric     switch (Log.getLineKind(I)) {
200*349cc55cSDimitry Andric     case DC_match:
201*349cc55cSDimitry Andric       out << "  ";
202*349cc55cSDimitry Andric       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
203*349cc55cSDimitry Andric       //printValue(Log.getLeft(I), true);
204*349cc55cSDimitry Andric       break;
205*349cc55cSDimitry Andric     case DC_left:
206*349cc55cSDimitry Andric       out << "< ";
207*349cc55cSDimitry Andric       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
208*349cc55cSDimitry Andric       //printValue(Log.getLeft(I), true);
209*349cc55cSDimitry Andric       break;
210*349cc55cSDimitry Andric     case DC_right:
211*349cc55cSDimitry Andric       out << "> ";
212*349cc55cSDimitry Andric       Log.getRight(I)->print(dbgs()); dbgs() << '\n';
213*349cc55cSDimitry Andric       //printValue(Log.getRight(I), false);
214*349cc55cSDimitry Andric       break;
215*349cc55cSDimitry Andric     }
216*349cc55cSDimitry Andric     //out << "\n";
217*349cc55cSDimitry Andric   }
218*349cc55cSDimitry Andric }
219