Home | History | Annotate | Download | only in llvm-diff
      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 
     20 using namespace llvm;
     21 
     22 static 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 
     47 void 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 
     89 void 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 
    129 void DiffConsumer::indent() {
    130   unsigned N = Indent;
    131   while (N--) out << ' ';
    132 }
    133 
    134 bool DiffConsumer::hadDifferences() const {
    135   return Differences;
    136 }
    137 
    138 void DiffConsumer::enterContext(Value *L, Value *R) {
    139   contexts.push_back(DiffContext(L, R));
    140   Indent += 2;
    141 }
    142 
    143 void DiffConsumer::exitContext() {
    144   Differences |= contexts.back().Differences;
    145   contexts.pop_back();
    146   Indent -= 2;
    147 }
    148 
    149 void DiffConsumer::log(StringRef text) {
    150   header();
    151   indent();
    152   out << text << '\n';
    153 }
    154 
    155 void 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 
    185 void 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