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 Consumer::anchor() { }
     48 
     49 void 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 
     95 void 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 
    135 void DiffConsumer::indent() {
    136   unsigned N = Indent;
    137   while (N--) out << ' ';
    138 }
    139 
    140 bool DiffConsumer::hadDifferences() const {
    141   return Differences;
    142 }
    143 
    144 void DiffConsumer::enterContext(Value *L, Value *R) {
    145   contexts.push_back(DiffContext(L, R));
    146   Indent += 2;
    147 }
    148 
    149 void DiffConsumer::exitContext() {
    150   Differences |= contexts.back().Differences;
    151   contexts.pop_back();
    152   Indent -= 2;
    153 }
    154 
    155 void DiffConsumer::log(StringRef text) {
    156   header();
    157   indent();
    158   out << text << '\n';
    159 }
    160 
    161 void 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 
    191 void 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