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