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