mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@109774 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			174 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- DifferenceEngine.h - Module comparator ------------------*- 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 engine,
 | |
| // which structurally compares functions within a module.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #ifndef _LLVM_DIFFERENCE_ENGINE_H_
 | |
| #define _LLVM_DIFFERENCE_ENGINE_H_
 | |
| 
 | |
| #include "llvm/ADT/SmallVector.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| 
 | |
| #include <utility>
 | |
| 
 | |
| namespace llvm {
 | |
|   class Function;
 | |
|   class GlobalValue;
 | |
|   class Instruction;
 | |
|   class LLVMContext;
 | |
|   class Module;
 | |
|   class Twine;
 | |
|   class Value;
 | |
| 
 | |
|   /// 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<Value*, 4> 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<Instruction*,Instruction*> DiffRecord;
 | |
|       SmallVector<DiffRecord, 20> 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) { Diff.push_back(DiffRecord(L, 0)); }
 | |
|       void addRight(Instruction *R) { Diff.push_back(DiffRecord(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:
 | |
|       ~Consumer() {}
 | |
|     };
 | |
| 
 | |
|     /// A RAII object for recording the current context.
 | |
|     struct Context {
 | |
|       Context(DifferenceEngine &Engine, Value *L, Value *R) : Engine(Engine) {
 | |
|         Engine.consumer.enterContext(L, R);
 | |
|       }
 | |
| 
 | |
|       ~Context() {
 | |
|         Engine.consumer.exitContext();
 | |
|       }
 | |
| 
 | |
|     private:
 | |
|       DifferenceEngine &Engine;
 | |
|     };
 | |
| 
 | |
|     /// An oracle for answering whether two values are equivalent as
 | |
|     /// operands.
 | |
|     struct Oracle {
 | |
|       virtual bool operator()(Value *L, Value *R) = 0;
 | |
| 
 | |
|     protected:
 | |
|       ~Oracle() {}
 | |
|     };
 | |
| 
 | |
|     DifferenceEngine(LLVMContext &context, Consumer &consumer)
 | |
|       : context(context), consumer(consumer), globalValueOracle(0) {}
 | |
| 
 | |
|     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);
 | |
|     }
 | |
| 
 | |
|     /// Installs an oracle to decide whether two global values are
 | |
|     /// equivalent as operands.  Without an oracle, global values are
 | |
|     /// considered equivalent as operands precisely when they have the
 | |
|     /// same name.
 | |
|     void setGlobalValueOracle(Oracle *oracle) {
 | |
|       globalValueOracle = oracle;
 | |
|     }
 | |
| 
 | |
|     /// Determines whether two global values are equivalent.
 | |
|     bool equivalentAsOperands(GlobalValue *L, GlobalValue *R);
 | |
| 
 | |
|   private:
 | |
|     LLVMContext &context;
 | |
|     Consumer &consumer;
 | |
|     Oracle *globalValueOracle;
 | |
|   };
 | |
| }
 | |
| 
 | |
| #endif
 |