From 7d4fc4fb345ee8a1de15c718a854b5f38c1e6e46 Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Mon, 14 Mar 2011 22:22:46 +0000 Subject: This patch is a big refactoring of llvm-diff. It doesn't add new features, but it re-organizes the old features, so I can insert the MetadataEngine to use the same infrastructure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127627 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/llvm-diff/CMakeLists.txt | 2 + tools/llvm-diff/DiffConsumer.cpp | 209 +++++++++++++++++++++++++++++++++ tools/llvm-diff/DiffConsumer.h | 91 +++++++++++++++ tools/llvm-diff/DiffLog.cpp | 53 +++++++++ tools/llvm-diff/DiffLog.h | 80 +++++++++++++ tools/llvm-diff/DifferenceEngine.cpp | 24 ++-- tools/llvm-diff/DifferenceEngine.h | 96 +-------------- tools/llvm-diff/llvm-diff.cpp | 218 +---------------------------------- 8 files changed, 452 insertions(+), 321 deletions(-) create mode 100644 tools/llvm-diff/DiffConsumer.cpp create mode 100644 tools/llvm-diff/DiffConsumer.h create mode 100644 tools/llvm-diff/DiffLog.cpp create mode 100644 tools/llvm-diff/DiffLog.h (limited to 'tools/llvm-diff') diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt index f6d65c947a..c59d69ea0d 100644 --- a/tools/llvm-diff/CMakeLists.txt +++ b/tools/llvm-diff/CMakeLists.txt @@ -2,5 +2,7 @@ set(LLVM_LINK_COMPONENTS support asmparser bitreader) add_llvm_tool(llvm-diff llvm-diff.cpp + DiffConsumer.cpp + DiffLog.cpp DifferenceEngine.cpp ) diff --git a/tools/llvm-diff/DiffConsumer.cpp b/tools/llvm-diff/DiffConsumer.cpp new file mode 100644 index 0000000000..c23e8fb91a --- /dev/null +++ b/tools/llvm-diff/DiffConsumer.cpp @@ -0,0 +1,209 @@ +//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files implements the the LLVM difference Consumer +// +//===----------------------------------------------------------------------===// + +#include "DiffConsumer.h" + +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +static void ComputeNumbering(Function *F, DenseMap &Numbering){ + unsigned IN = 0; + + // Arguments get the first numbers. + for (Function::arg_iterator + AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) + if (!AI->hasName()) + Numbering[&*AI] = IN++; + + // Walk the basic blocks in order. + for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { + if (!FI->hasName()) + Numbering[&*FI] = IN++; + + // Walk the instructions in order. + for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) + // void instructions don't get numbers. + if (!BI->hasName() && !BI->getType()->isVoidTy()) + Numbering[&*BI] = IN++; + } + + assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); +} + + +void DiffConsumer::printValue(Value *V, bool isL) { + if (V->hasName()) { + out << (isa(V) ? '@' : '%') << V->getName(); + return; + } + if (V->getType()->isVoidTy()) { + if (isa(V)) { + out << "store to "; + printValue(cast(V)->getPointerOperand(), isL); + } else if (isa(V)) { + out << "call to "; + printValue(cast(V)->getCalledValue(), isL); + } else if (isa(V)) { + out << "invoke to "; + printValue(cast(V)->getCalledValue(), isL); + } else { + out << *V; + } + return; + } + + unsigned N = contexts.size(); + while (N > 0) { + --N; + DiffContext &ctxt = contexts[N]; + if (!ctxt.IsFunction) continue; + if (isL) { + if (ctxt.LNumbering.empty()) + ComputeNumbering(cast(ctxt.L), ctxt.LNumbering); + out << '%' << ctxt.LNumbering[V]; + return; + } else { + if (ctxt.RNumbering.empty()) + ComputeNumbering(cast(ctxt.R), ctxt.RNumbering); + out << '%' << ctxt.RNumbering[V]; + return; + } + } + + out << ""; +} + +void DiffConsumer::header() { + if (contexts.empty()) return; + for (SmallVectorImpl::iterator + I = contexts.begin(), E = contexts.end(); I != E; ++I) { + if (I->Differences) continue; + if (isa(I->L)) { + // Extra newline between functions. + if (Differences) out << "\n"; + + Function *L = cast(I->L); + Function *R = cast(I->R); + if (L->getName() != R->getName()) + out << "in function " << L->getName() + << " / " << R->getName() << ":\n"; + else + out << "in function " << L->getName() << ":\n"; + } else if (isa(I->L)) { + BasicBlock *L = cast(I->L); + BasicBlock *R = cast(I->R); + if (L->hasName() && R->hasName() && L->getName() == R->getName()) + out << " in block %" << L->getName() << ":\n"; + else { + out << " in block "; + printValue(L, true); + out << " / "; + printValue(R, false); + out << ":\n"; + } + } else if (isa(I->L)) { + out << " in instruction "; + printValue(I->L, true); + out << " / "; + printValue(I->R, false); + out << ":\n"; + } + + I->Differences = true; + } +} + +void DiffConsumer::indent() { + unsigned N = Indent; + while (N--) out << ' '; +} + +bool DiffConsumer::hadDifferences() const { + return Differences; +} + +void DiffConsumer::enterContext(Value *L, Value *R) { + contexts.push_back(DiffContext(L, R)); + Indent += 2; +} + +void DiffConsumer::exitContext() { + Differences |= contexts.back().Differences; + contexts.pop_back(); + Indent -= 2; +} + +void DiffConsumer::log(StringRef text) { + header(); + indent(); + out << text << '\n'; +} + +void DiffConsumer::logf(const LogBuilder &Log) { + header(); + indent(); + + unsigned arg = 0; + + StringRef format = Log.getFormat(); + while (true) { + size_t percent = format.find('%'); + if (percent == StringRef::npos) { + out << format; + break; + } + assert(format[percent] == '%'); + + if (percent > 0) out << format.substr(0, percent); + + switch (format[percent+1]) { + case '%': out << '%'; break; + case 'l': printValue(Log.getArgument(arg++), true); break; + case 'r': printValue(Log.getArgument(arg++), false); break; + default: llvm_unreachable("unknown format character"); + } + + format = format.substr(percent+2); + } + + out << '\n'; +} + +void DiffConsumer::logd(const DiffLogBuilder &Log) { + header(); + + for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { + indent(); + switch (Log.getLineKind(I)) { + case DC_match: + out << " "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DC_left: + out << "< "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DC_right: + out << "> "; + Log.getRight(I)->dump(); + //printValue(Log.getRight(I), false); + break; + } + //out << "\n"; + } +} diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h new file mode 100644 index 0000000000..e5510ccee5 --- /dev/null +++ b/tools/llvm-diff/DiffConsumer.h @@ -0,0 +1,91 @@ +//===-- DiffConsumer.h - Difference Consumer --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference Consumer +// +//===----------------------------------------------------------------------===// + +#ifndef _LLVM_DIFFCONSUMER_H_ +#define _LLVM_DIFFCONSUMER_H_ + +#include "DiffLog.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Casting.h" + +namespace llvm { + class Module; + class Value; + class Function; + + /// The interface for consumers of difference data. + struct Consumer { + /// Record that a local context has been entered. Left and + /// Right are IR "containers" of some sort which are being + /// considered for structural equivalence: global variables, + /// functions, blocks, instructions, etc. + virtual void enterContext(Value *Left, Value *Right) = 0; + + /// Record that a local context has been exited. + virtual void exitContext() = 0; + + /// Record a difference within the current context. + virtual void log(StringRef Text) = 0; + + /// Record a formatted difference within the current context. + virtual void logf(const LogBuilder &Log) = 0; + + /// Record a line-by-line instruction diff. + virtual void logd(const DiffLogBuilder &Log) = 0; + + protected: + virtual ~Consumer() {} + }; + + class DiffConsumer : public Consumer { + private: + struct DiffContext { + DiffContext(Value *L, Value *R) + : L(L), R(R), Differences(false), IsFunction(isa(L)) {} + Value *L; + Value *R; + bool Differences; + bool IsFunction; + DenseMap LNumbering; + DenseMap RNumbering; + }; + + raw_ostream &out; + Module *LModule; + Module *RModule; + SmallVector contexts; + bool Differences; + unsigned Indent; + + void printValue(Value *V, bool isL); + void header(); + void indent(); + + public: + DiffConsumer(Module *L, Module *R) + : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} + + bool hadDifferences() const; + void enterContext(Value *L, Value *R); + void exitContext(); + void log(StringRef text); + void logf(const LogBuilder &Log); + void logd(const DiffLogBuilder &Log); + }; +} + +#endif diff --git a/tools/llvm-diff/DiffLog.cpp b/tools/llvm-diff/DiffLog.cpp new file mode 100644 index 0000000000..9cc0c889fd --- /dev/null +++ b/tools/llvm-diff/DiffLog.cpp @@ -0,0 +1,53 @@ +//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference log builder. +// +//===----------------------------------------------------------------------===// + +#include "DiffLog.h" +#include "DiffConsumer.h" + +#include "llvm/Instructions.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +LogBuilder::~LogBuilder() { + consumer.logf(*this); +} + +StringRef LogBuilder::getFormat() const { return Format; } + +unsigned LogBuilder::getNumArguments() const { return Arguments.size(); } +Value *LogBuilder::getArgument(unsigned I) const { return Arguments[I]; } + +DiffLogBuilder::~DiffLogBuilder() { consumer.logd(*this); } + +void DiffLogBuilder::addMatch(Instruction *L, Instruction *R) { + Diff.push_back(DiffRecord(L, R)); +} +void DiffLogBuilder::addLeft(Instruction *L) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(L, DiffRecord::second_type(0))); +} +void DiffLogBuilder::addRight(Instruction *R) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(DiffRecord::first_type(0), R)); +} + +unsigned DiffLogBuilder::getNumLines() const { return Diff.size(); } + +DiffChange DiffLogBuilder::getLineKind(unsigned I) const { + return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left) + : DC_right); +} +Instruction *DiffLogBuilder::getLeft(unsigned I) const { return Diff[I].first; } +Instruction *DiffLogBuilder::getRight(unsigned I) const { return Diff[I].second; } diff --git a/tools/llvm-diff/DiffLog.h b/tools/llvm-diff/DiffLog.h new file mode 100644 index 0000000000..43e318ac4e --- /dev/null +++ b/tools/llvm-diff/DiffLog.h @@ -0,0 +1,80 @@ +//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference log builder. +// +//===----------------------------------------------------------------------===// + +#ifndef _LLVM_DIFFLOG_H_ +#define _LLVM_DIFFLOG_H_ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class Instruction; + class Value; + class Consumer; + + /// Trichotomy assumption + enum DiffChange { DC_match, DC_left, DC_right }; + + /// A temporary-object class for building up log messages. + class LogBuilder { + Consumer &consumer; + + /// The use of a stored StringRef here is okay because + /// LogBuilder should be used only as a temporary, and as a + /// temporary it will be destructed before whatever temporary + /// might be initializing this format. + StringRef Format; + + SmallVector Arguments; + + public: + LogBuilder(Consumer &c, StringRef Format) + : consumer(c), Format(Format) {} + + LogBuilder &operator<<(Value *V) { + Arguments.push_back(V); + return *this; + } + + ~LogBuilder(); + + StringRef getFormat() const; + unsigned getNumArguments() const; + Value *getArgument(unsigned I) const; + }; + + /// A temporary-object class for building up diff messages. + class DiffLogBuilder { + typedef std::pair DiffRecord; + SmallVector Diff; + + Consumer &consumer; + + public: + DiffLogBuilder(Consumer &c) : consumer(c) {} + ~DiffLogBuilder(); + + void addMatch(Instruction *L, Instruction *R); + // HACK: VS 2010 has a bug in the stdlib that requires this. + void addLeft(Instruction *L); + void addRight(Instruction *R); + + unsigned getNumLines() const; + DiffChange getLineKind(unsigned I) const; + Instruction *getLeft(unsigned I) const; + Instruction *getRight(unsigned I) const; + }; + +} + +#endif diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index b0a24d0737..3cf178e7f1 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -506,30 +506,30 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, for (unsigned I = 0; I != NL+1; ++I) { Cur[I].Cost = I * LeftCost; for (unsigned J = 0; J != I; ++J) - Cur[I].Path.push_back(DifferenceEngine::DC_left); + Cur[I].Path.push_back(DC_left); } for (BasicBlock::iterator RI = RStart; RI != RE; ++RI) { // Initialize the first row. Next[0] = Cur[0]; Next[0].Cost += RightCost; - Next[0].Path.push_back(DifferenceEngine::DC_right); + Next[0].Path.push_back(DC_right); unsigned Index = 1; for (BasicBlock::iterator LI = LStart; LI != LE; ++LI, ++Index) { if (matchForBlockDiff(&*LI, &*RI)) { Next[Index] = Cur[Index-1]; Next[Index].Cost += MatchCost; - Next[Index].Path.push_back(DifferenceEngine::DC_match); + Next[Index].Path.push_back(DC_match); TentativeValues.insert(std::make_pair(&*LI, &*RI)); } else if (Next[Index-1].Cost <= Cur[Index].Cost) { Next[Index] = Next[Index-1]; Next[Index].Cost += LeftCost; - Next[Index].Path.push_back(DifferenceEngine::DC_left); + Next[Index].Path.push_back(DC_left); } else { Next[Index] = Cur[Index]; Next[Index].Cost += RightCost; - Next[Index].Path.push_back(DifferenceEngine::DC_right); + Next[Index].Path.push_back(DC_right); } } @@ -543,23 +543,23 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, SmallVectorImpl &Path = Cur[NL].Path; BasicBlock::iterator LI = LStart, RI = RStart; - DifferenceEngine::DiffLogBuilder Diff(Engine); + DiffLogBuilder Diff(Engine.getConsumer()); // Drop trailing matches. - while (Path.back() == DifferenceEngine::DC_match) + while (Path.back() == DC_match) Path.pop_back(); // Skip leading matches. SmallVectorImpl::iterator PI = Path.begin(), PE = Path.end(); - while (PI != PE && *PI == DifferenceEngine::DC_match) { + while (PI != PE && *PI == DC_match) { unify(&*LI, &*RI); ++PI, ++LI, ++RI; } for (; PI != PE; ++PI) { - switch (static_cast(*PI)) { - case DifferenceEngine::DC_match: + switch (static_cast(*PI)) { + case DC_match: assert(LI != LE && RI != RE); { Instruction *L = &*LI, *R = &*RI; @@ -569,13 +569,13 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, ++LI; ++RI; break; - case DifferenceEngine::DC_left: + case DC_left: assert(LI != LE); Diff.addLeft(&*LI); ++LI; break; - case DifferenceEngine::DC_right: + case DC_right: assert(RI != RE); Diff.addRight(&*RI); ++RI; diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h index 6eefb06118..5b4f80b99e 100644 --- a/tools/llvm-diff/DifferenceEngine.h +++ b/tools/llvm-diff/DifferenceEngine.h @@ -17,6 +17,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "DiffLog.h" +#include "DiffConsumer.h" #include @@ -32,95 +34,6 @@ namespace llvm { /// A class for performing structural comparisons of LLVM assembly. class DifferenceEngine { public: - /// A temporary-object class for building up log messages. - class LogBuilder { - DifferenceEngine &Engine; - - /// The use of a stored StringRef here is okay because - /// LogBuilder should be used only as a temporary, and as a - /// temporary it will be destructed before whatever temporary - /// might be initializing this format. - StringRef Format; - - SmallVector Arguments; - - public: - LogBuilder(DifferenceEngine &Engine, StringRef Format) - : Engine(Engine), Format(Format) {} - - LogBuilder &operator<<(Value *V) { - Arguments.push_back(V); - return *this; - } - - ~LogBuilder() { - Engine.consumer.logf(*this); - } - - StringRef getFormat() const { return Format; } - - unsigned getNumArguments() const { return Arguments.size(); } - Value *getArgument(unsigned I) const { return Arguments[I]; } - }; - - enum DiffChange { DC_match, DC_left, DC_right }; - - /// A temporary-object class for building up diff messages. - class DiffLogBuilder { - typedef std::pair DiffRecord; - SmallVector Diff; - - DifferenceEngine &Engine; - - public: - DiffLogBuilder(DifferenceEngine &Engine) : Engine(Engine) {} - ~DiffLogBuilder() { Engine.consumer.logd(*this); } - - void addMatch(Instruction *L, Instruction *R) { - Diff.push_back(DiffRecord(L, R)); - } - void addLeft(Instruction *L) { - // HACK: VS 2010 has a bug in the stdlib that requires this. - Diff.push_back(DiffRecord(L, DiffRecord::second_type(0))); - } - void addRight(Instruction *R) { - // HACK: VS 2010 has a bug in the stdlib that requires this. - Diff.push_back(DiffRecord(DiffRecord::first_type(0), R)); - } - - unsigned getNumLines() const { return Diff.size(); } - DiffChange getLineKind(unsigned I) const { - return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left) - : DC_right); - } - Instruction *getLeft(unsigned I) const { return Diff[I].first; } - Instruction *getRight(unsigned I) const { return Diff[I].second; } - }; - - /// The interface for consumers of difference data. - struct Consumer { - /// Record that a local context has been entered. Left and - /// Right are IR "containers" of some sort which are being - /// considered for structural equivalence: global variables, - /// functions, blocks, instructions, etc. - virtual void enterContext(Value *Left, Value *Right) = 0; - - /// Record that a local context has been exited. - virtual void exitContext() = 0; - - /// Record a difference within the current context. - virtual void log(StringRef Text) = 0; - - /// Record a formatted difference within the current context. - virtual void logf(const LogBuilder &Log) = 0; - - /// Record a line-by-line instruction diff. - virtual void logd(const DiffLogBuilder &Log) = 0; - - protected: - virtual ~Consumer() {} - }; - /// A RAII object for recording the current context. struct Context { Context(DifferenceEngine &Engine, Value *L, Value *R) : Engine(Engine) { @@ -149,14 +62,13 @@ namespace llvm { void diff(Module *L, Module *R); void diff(Function *L, Function *R); - void log(StringRef text) { consumer.log(text); } - LogBuilder logf(StringRef text) { - return LogBuilder(*this, text); + return LogBuilder(consumer, text); } + Consumer& getConsumer() const { return consumer; } /// Installs an oracle to decide whether two global values are /// equivalent as operands. Without an oracle, global values are diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index b932ccc743..76853f1e43 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "DiffLog.h" #include "DifferenceEngine.h" -#include "llvm/Instructions.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Type.h" @@ -21,7 +21,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/IRReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -43,221 +42,6 @@ static Module *ReadModule(LLVMContext &Context, StringRef Name) { return M; } -namespace { - struct DiffContext { - DiffContext(Value *L, Value *R) - : L(L), R(R), Differences(false), IsFunction(isa(L)) {} - Value *L; - Value *R; - bool Differences; - bool IsFunction; - DenseMap LNumbering; - DenseMap RNumbering; - }; -} - -static void ComputeNumbering(Function *F, DenseMap &Numbering){ - unsigned IN = 0; - - // Arguments get the first numbers. - for (Function::arg_iterator - AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) - if (!AI->hasName()) - Numbering[&*AI] = IN++; - - // Walk the basic blocks in order. - for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { - if (!FI->hasName()) - Numbering[&*FI] = IN++; - - // Walk the instructions in order. - for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) - // void instructions don't get numbers. - if (!BI->hasName() && !BI->getType()->isVoidTy()) - Numbering[&*BI] = IN++; - } - - assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); -} - -namespace { -class DiffConsumer : public DifferenceEngine::Consumer { -private: - raw_ostream &out; - Module *LModule; - Module *RModule; - SmallVector contexts; - bool Differences; - unsigned Indent; - - void printValue(Value *V, bool isL) { - if (V->hasName()) { - out << (isa(V) ? '@' : '%') << V->getName(); - return; - } - if (V->getType()->isVoidTy()) { - if (isa(V)) { - out << "store to "; - printValue(cast(V)->getPointerOperand(), isL); - } else if (isa(V)) { - out << "call to "; - printValue(cast(V)->getCalledValue(), isL); - } else if (isa(V)) { - out << "invoke to "; - printValue(cast(V)->getCalledValue(), isL); - } else { - out << *V; - } - return; - } - - unsigned N = contexts.size(); - while (N > 0) { - --N; - DiffContext &ctxt = contexts[N]; - if (!ctxt.IsFunction) continue; - if (isL) { - if (ctxt.LNumbering.empty()) - ComputeNumbering(cast(ctxt.L), ctxt.LNumbering); - out << '%' << ctxt.LNumbering[V]; - return; - } else { - if (ctxt.RNumbering.empty()) - ComputeNumbering(cast(ctxt.R), ctxt.RNumbering); - out << '%' << ctxt.RNumbering[V]; - return; - } - } - - out << ""; - } - - void header() { - if (contexts.empty()) return; - for (SmallVectorImpl::iterator - I = contexts.begin(), E = contexts.end(); I != E; ++I) { - if (I->Differences) continue; - if (isa(I->L)) { - // Extra newline between functions. - if (Differences) out << "\n"; - - Function *L = cast(I->L); - Function *R = cast(I->R); - if (L->getName() != R->getName()) - out << "in function " << L->getName() - << " / " << R->getName() << ":\n"; - else - out << "in function " << L->getName() << ":\n"; - } else if (isa(I->L)) { - BasicBlock *L = cast(I->L); - BasicBlock *R = cast(I->R); - if (L->hasName() && R->hasName() && L->getName() == R->getName()) - out << " in block %" << L->getName() << ":\n"; - else { - out << " in block "; - printValue(L, true); - out << " / "; - printValue(R, false); - out << ":\n"; - } - } else if (isa(I->L)) { - out << " in instruction "; - printValue(I->L, true); - out << " / "; - printValue(I->R, false); - out << ":\n"; - } - - I->Differences = true; - } - } - - void indent() { - unsigned N = Indent; - while (N--) out << ' '; - } - -public: - DiffConsumer(Module *L, Module *R) - : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} - - bool hadDifferences() const { return Differences; } - - void enterContext(Value *L, Value *R) { - contexts.push_back(DiffContext(L, R)); - Indent += 2; - } - void exitContext() { - Differences |= contexts.back().Differences; - contexts.pop_back(); - Indent -= 2; - } - - void log(StringRef text) { - header(); - indent(); - out << text << '\n'; - } - - void logf(const DifferenceEngine::LogBuilder &Log) { - header(); - indent(); - - unsigned arg = 0; - - StringRef format = Log.getFormat(); - while (true) { - size_t percent = format.find('%'); - if (percent == StringRef::npos) { - out << format; - break; - } - assert(format[percent] == '%'); - - if (percent > 0) out << format.substr(0, percent); - - switch (format[percent+1]) { - case '%': out << '%'; break; - case 'l': printValue(Log.getArgument(arg++), true); break; - case 'r': printValue(Log.getArgument(arg++), false); break; - default: llvm_unreachable("unknown format character"); - } - - format = format.substr(percent+2); - } - - out << '\n'; - } - - void logd(const DifferenceEngine::DiffLogBuilder &Log) { - header(); - - for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { - indent(); - switch (Log.getLineKind(I)) { - case DifferenceEngine::DC_match: - out << " "; - Log.getLeft(I)->dump(); - //printValue(Log.getLeft(I), true); - break; - case DifferenceEngine::DC_left: - out << "< "; - Log.getLeft(I)->dump(); - //printValue(Log.getLeft(I), true); - break; - case DifferenceEngine::DC_right: - out << "> "; - Log.getRight(I)->dump(); - //printValue(Log.getRight(I), false); - break; - } - //out << "\n"; - } - } - -}; -} // end anonymous namespace - static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R, StringRef Name) { // Drop leading sigils from the global name. -- cgit v1.2.3