DiffConsumer.cpp revision bd3c5ecd37e760f0430c9cbd1fda5740eb7c0e27
17d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
27d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//
37d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//                     The LLVM Compiler Infrastructure
47d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//
57d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin// This file is distributed under the University of Illinois Open Source
67d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin// License. See LICENSE.TXT for details.
77d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//
87d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//===----------------------------------------------------------------------===//
97d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//
107d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin// This files implements the the LLVM difference Consumer
117d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//
127d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin//===----------------------------------------------------------------------===//
137d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
147d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin#include "DiffConsumer.h"
157d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
167d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin#include "llvm/Module.h"
177d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin#include "llvm/Instructions.h"
187d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin#include "llvm/Support/ErrorHandling.h"
197d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
207d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinusing namespace llvm;
217d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
227d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinstatic void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering){
237d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  unsigned IN = 0;
247d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
257d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  // Arguments get the first numbers.
267d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  for (Function::arg_iterator
277d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin         AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
287d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (!AI->hasName())
297d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Numbering[&*AI] = IN++;
307d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
317d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  // Walk the basic blocks in order.
327d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
337d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (!FI->hasName())
347d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Numbering[&*FI] = IN++;
357d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
367d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    // Walk the instructions in order.
377d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
387d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      // void instructions don't get numbers.
397d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (!BI->hasName() && !BI->getType()->isVoidTy())
407d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        Numbering[&*BI] = IN++;
417d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
427d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
437d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
447d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
457d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
467d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
477d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::printValue(Value *V, bool isL) {
487d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  if (V->hasName()) {
497d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
507d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    return;
517d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
527d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  if (V->getType()->isVoidTy()) {
537d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (isa<StoreInst>(V)) {
547d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "store to ";
557d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
567d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else if (isa<CallInst>(V)) {
577d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "call to ";
587d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      printValue(cast<CallInst>(V)->getCalledValue(), isL);
597d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else if (isa<InvokeInst>(V)) {
607d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "invoke to ";
617d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
627d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else {
637d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << *V;
647d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
657d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    return;
667d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
67bd3c5ecd37e760f0430c9cbd1fda5740eb7c0e27John McCall  if (dyn_cast<Constant>(V)) {
68bd3c5ecd37e760f0430c9cbd1fda5740eb7c0e27John McCall    out << *V;
69bd3c5ecd37e760f0430c9cbd1fda5740eb7c0e27John McCall    return;
70bd3c5ecd37e760f0430c9cbd1fda5740eb7c0e27John McCall  }
717d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
727d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  unsigned N = contexts.size();
737d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  while (N > 0) {
747d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    --N;
757d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    DiffContext &ctxt = contexts[N];
767d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (!ctxt.IsFunction) continue;
777d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (isL) {
787d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (ctxt.LNumbering.empty())
797d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
807d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << '%' << ctxt.LNumbering[V];
817d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      return;
827d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else {
837d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (ctxt.RNumbering.empty())
847d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
857d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << '%' << ctxt.RNumbering[V];
867d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      return;
877d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
887d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
897d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
907d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  out << "<anonymous>";
917d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
927d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
937d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::header() {
947d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  if (contexts.empty()) return;
957d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  for (SmallVectorImpl<DiffContext>::iterator
967d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin         I = contexts.begin(), E = contexts.end(); I != E; ++I) {
977d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (I->Differences) continue;
987d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (isa<Function>(I->L)) {
997d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      // Extra newline between functions.
1007d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (Differences) out << "\n";
1017d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1027d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Function *L = cast<Function>(I->L);
1037d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Function *R = cast<Function>(I->R);
1047d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (L->getName() != R->getName())
1057d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << "in function " << L->getName()
1067d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin            << " / " << R->getName() << ":\n";
1077d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      else
1087d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << "in function " << L->getName() << ":\n";
1097d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else if (isa<BasicBlock>(I->L)) {
1107d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      BasicBlock *L = cast<BasicBlock>(I->L);
1117d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      BasicBlock *R = cast<BasicBlock>(I->R);
1127d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      if (L->hasName() && R->hasName() && L->getName() == R->getName())
1137d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << "  in block %" << L->getName() << ":\n";
1147d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      else {
1157d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << "  in block ";
1167d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        printValue(L, true);
1177d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << " / ";
1187d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        printValue(R, false);
1197d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin        out << ":\n";
1207d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      }
1217d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    } else if (isa<Instruction>(I->L)) {
1227d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "    in instruction ";
1237d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      printValue(I->L, true);
1247d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << " / ";
1257d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      printValue(I->R, false);
1267d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << ":\n";
1277d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
1287d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1297d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    I->Differences = true;
1307d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
1317d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1327d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1337d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::indent() {
1347d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  unsigned N = Indent;
1357d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  while (N--) out << ' ';
1367d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1377d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1387d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinbool DiffConsumer::hadDifferences() const {
1397d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  return Differences;
1407d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1417d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1427d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::enterContext(Value *L, Value *R) {
1437d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  contexts.push_back(DiffContext(L, R));
1447d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  Indent += 2;
1457d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1467d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1477d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::exitContext() {
1487d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  Differences |= contexts.back().Differences;
1497d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  contexts.pop_back();
1507d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  Indent -= 2;
1517d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1527d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1537d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::log(StringRef text) {
1547d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  header();
1557d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  indent();
1567d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  out << text << '\n';
1577d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1587d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1597d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::logf(const LogBuilder &Log) {
1607d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  header();
1617d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  indent();
1627d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1637d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  unsigned arg = 0;
1647d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1657d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  StringRef format = Log.getFormat();
1667d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  while (true) {
1677d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    size_t percent = format.find('%');
1687d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (percent == StringRef::npos) {
1697d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << format;
1707d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      break;
1717d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
1727d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    assert(format[percent] == '%');
1737d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1747d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    if (percent > 0) out << format.substr(0, percent);
1757d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1767d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    switch (format[percent+1]) {
1777d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case '%': out << '%'; break;
1787d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case 'l': printValue(Log.getArgument(arg++), true); break;
1797d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case 'r': printValue(Log.getArgument(arg++), false); break;
1807d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    default: llvm_unreachable("unknown format character");
1817d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
1827d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1837d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    format = format.substr(percent+2);
1847d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
1857d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1867d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  out << '\n';
1877d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
1887d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1897d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golinvoid DiffConsumer::logd(const DiffLogBuilder &Log) {
1907d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  header();
1917d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin
1927d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1937d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    indent();
1947d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    switch (Log.getLineKind(I)) {
1957d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case DC_match:
1967d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "  ";
1977d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Log.getLeft(I)->dump();
1987d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      //printValue(Log.getLeft(I), true);
1997d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      break;
2007d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case DC_left:
2017d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "< ";
2027d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Log.getLeft(I)->dump();
2037d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      //printValue(Log.getLeft(I), true);
2047d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      break;
2057d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    case DC_right:
2067d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      out << "> ";
2077d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      Log.getRight(I)->dump();
2087d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      //printValue(Log.getRight(I), false);
2097d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin      break;
2107d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    }
2117d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin    //out << "\n";
2127d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin  }
2137d4fc4fb345ee8a1de15c718a854b5f38c1e6e46Renato Golin}
214