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 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 Consumer::anchor() { }
48
49void DiffConsumer::printValue(Value *V, bool isL) {
50  if (V->hasName()) {
51    out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
52    return;
53  }
54  if (V->getType()->isVoidTy()) {
55    if (isa<StoreInst>(V)) {
56      out << "store to ";
57      printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
58    } else if (isa<CallInst>(V)) {
59      out << "call to ";
60      printValue(cast<CallInst>(V)->getCalledValue(), isL);
61    } else if (isa<InvokeInst>(V)) {
62      out << "invoke to ";
63      printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
64    } else {
65      out << *V;
66    }
67    return;
68  }
69  if (isa<Constant>(V)) {
70    out << *V;
71    return;
72  }
73
74  unsigned N = contexts.size();
75  while (N > 0) {
76    --N;
77    DiffContext &ctxt = contexts[N];
78    if (!ctxt.IsFunction) continue;
79    if (isL) {
80      if (ctxt.LNumbering.empty())
81        ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
82      out << '%' << ctxt.LNumbering[V];
83      return;
84    } else {
85      if (ctxt.RNumbering.empty())
86        ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
87      out << '%' << ctxt.RNumbering[V];
88      return;
89    }
90  }
91
92  out << "<anonymous>";
93}
94
95void DiffConsumer::header() {
96  if (contexts.empty()) return;
97  for (SmallVectorImpl<DiffContext>::iterator
98         I = contexts.begin(), E = contexts.end(); I != E; ++I) {
99    if (I->Differences) continue;
100    if (isa<Function>(I->L)) {
101      // Extra newline between functions.
102      if (Differences) out << "\n";
103
104      Function *L = cast<Function>(I->L);
105      Function *R = cast<Function>(I->R);
106      if (L->getName() != R->getName())
107        out << "in function " << L->getName()
108            << " / " << R->getName() << ":\n";
109      else
110        out << "in function " << L->getName() << ":\n";
111    } else if (isa<BasicBlock>(I->L)) {
112      BasicBlock *L = cast<BasicBlock>(I->L);
113      BasicBlock *R = cast<BasicBlock>(I->R);
114      if (L->hasName() && R->hasName() && L->getName() == R->getName())
115        out << "  in block %" << L->getName() << ":\n";
116      else {
117        out << "  in block ";
118        printValue(L, true);
119        out << " / ";
120        printValue(R, false);
121        out << ":\n";
122      }
123    } else if (isa<Instruction>(I->L)) {
124      out << "    in instruction ";
125      printValue(I->L, true);
126      out << " / ";
127      printValue(I->R, false);
128      out << ":\n";
129    }
130
131    I->Differences = true;
132  }
133}
134
135void DiffConsumer::indent() {
136  unsigned N = Indent;
137  while (N--) out << ' ';
138}
139
140bool DiffConsumer::hadDifferences() const {
141  return Differences;
142}
143
144void DiffConsumer::enterContext(Value *L, Value *R) {
145  contexts.push_back(DiffContext(L, R));
146  Indent += 2;
147}
148
149void DiffConsumer::exitContext() {
150  Differences |= contexts.back().Differences;
151  contexts.pop_back();
152  Indent -= 2;
153}
154
155void DiffConsumer::log(StringRef text) {
156  header();
157  indent();
158  out << text << '\n';
159}
160
161void DiffConsumer::logf(const LogBuilder &Log) {
162  header();
163  indent();
164
165  unsigned arg = 0;
166
167  StringRef format = Log.getFormat();
168  while (true) {
169    size_t percent = format.find('%');
170    if (percent == StringRef::npos) {
171      out << format;
172      break;
173    }
174    assert(format[percent] == '%');
175
176    if (percent > 0) out << format.substr(0, percent);
177
178    switch (format[percent+1]) {
179    case '%': out << '%'; break;
180    case 'l': printValue(Log.getArgument(arg++), true); break;
181    case 'r': printValue(Log.getArgument(arg++), false); break;
182    default: llvm_unreachable("unknown format character");
183    }
184
185    format = format.substr(percent+2);
186  }
187
188  out << '\n';
189}
190
191void DiffConsumer::logd(const DiffLogBuilder &Log) {
192  header();
193
194  for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
195    indent();
196    switch (Log.getLineKind(I)) {
197    case DC_match:
198      out << "  ";
199      Log.getLeft(I)->dump();
200      //printValue(Log.getLeft(I), true);
201      break;
202    case DC_left:
203      out << "< ";
204      Log.getLeft(I)->dump();
205      //printValue(Log.getLeft(I), true);
206      break;
207    case DC_right:
208      out << "> ";
209      Log.getRight(I)->dump();
210      //printValue(Log.getRight(I), false);
211      break;
212    }
213    //out << "\n";
214  }
215}
216