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