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