#ifndef __CodeTree__
#define __CodeTree__
#include "Forwards.hpp"
#include "Lib/Allocator.hpp"
#include "Lib/DArray.hpp"
#include "Lib/DHMap.hpp"
#include "Lib/Stack.hpp"
#include "Lib/Vector.hpp"
#include "Kernel/FlatTerm.hpp"
#define LOG_OP(x)
namespace Indexing {
using namespace Lib;
using namespace Kernel;
class CodeTree
{
public:
struct ILStruct;
struct SearchStruct;
struct CodeOp;
protected:
void (*_onCodeOpDestroying)(CodeOp* op);
public:
CodeTree();
~CodeTree();
struct LitInfo
{
LitInfo() {}
LitInfo(Clause* cl, unsigned litIndex);
void dispose();
static LitInfo getReversed(const LitInfo& li);
static LitInfo getOpposite(const LitInfo& li);
unsigned liIndex;
unsigned litIndex;
FlatTerm* ft;
bool opposite;
};
struct MatchInfo
{
unsigned liIndex;
TermList bindings[1];
private:
void init(ILStruct* ils, unsigned liIndex, DArray<TermList>& bindingArray);
static MatchInfo* alloc(unsigned bindCnt);
void destroy(unsigned bindCnt);
friend struct ILStruct;
MatchInfo();
~MatchInfo();
void operator delete(void*);
void* operator new(size_t,unsigned length);
};
struct alignas(8) ILStruct
{
ILStruct(const Literal* lit, unsigned varCnt, Stack<unsigned>& gvnStack);
~ILStruct();
void putIntoSequence(ILStruct* previous_);
bool equalsForOpMatching(const ILStruct& o) const;
void ensureFreshness(unsigned globalTimestamp);
USE_ALLOCATOR(ILStruct);
struct GVArrComparator;
unsigned depth;
ILStruct* previous;
unsigned varCnt;
unsigned* globalVarNumbers;
unsigned* sortedGlobalVarNumbers;
unsigned* globalVarPermutation;
unsigned timestamp;
void addMatch(unsigned liIndex, DArray<TermList>& bindingArray);
void deleteMatch(unsigned matchIndex);
MatchInfo*& getMatch(unsigned matchIndex);
unsigned matchCnt;
bool visited;
bool finished;
bool noNonOppositeMatches;
private:
DArray<MatchInfo*> matches;
};
enum Instruction
{
SUCCESS_OR_FAIL = 0,
CHECK_GROUND_TERM = 1,
LIT_END = 2,
CHECK_FUN = 3,
ASSIGN_VAR = 4,
CHECK_VAR = 5,
SEARCH_STRUCT = 6,
};
static const unsigned INSTRUCTION_BITS = 3;
static_assert(SEARCH_STRUCT < 1 << INSTRUCTION_BITS, "Instruction should fit within INSTRUCTION_BITS");
struct CodeOp
{
template<class T> static CodeOp getSuccess(T* ptr)
{
ASS(ptr); CodeOp res;
res._setData(ptr);
res._setInstruction(SUCCESS_OR_FAIL);
ASS(res.isSuccess());
return res;
}
static CodeOp getLitEnd(ILStruct* ils);
static CodeOp getTermOp(Instruction i, unsigned num);
static CodeOp getGroundTermCheck(const Term* trm);
bool equalsForOpMatching(const CodeOp& o) const;
inline bool isSuccess() const { static_assert(SUCCESS_OR_FAIL==0); return _instruction()==SUCCESS_OR_FAIL && _content; }
inline bool isFail() const { static_assert(SUCCESS_OR_FAIL==0); return !_content; }
inline bool isLitEnd() const { return _instruction()==LIT_END; }
inline bool isSearchStruct() const { return _instruction()==SEARCH_STRUCT; }
inline bool isCheckFun() const { return _instruction()==CHECK_FUN; }
inline bool isCheckGroundTerm() const { return _instruction()==CHECK_GROUND_TERM; }
inline Term* getTargetTerm() const
{
ASS(isCheckGroundTerm());
return _data<Term>();
}
template<class T> inline T* getSuccessResult() { ASS(isSuccess()); return _data<T>(); }
inline ILStruct* getILS() { ASS(isLitEnd()); return _data<ILStruct>(); }
inline const ILStruct* getILS() const { return _data<ILStruct>(); }
const SearchStruct* getSearchStruct() const;
SearchStruct* getSearchStruct();
inline CodeOp* alternative() const { return _alternative; }
inline CodeOp*& alternative() { return _alternative; }
inline void setAlternative(CodeOp* op) { ASS_NEQ(op, this); _alternative=op; }
void makeFail() { static_assert(SUCCESS_OR_FAIL==0); _content = 0; }
friend std::ostream& operator<<(std::ostream& out, const CodeOp& op);
BITFIELD(64,
BITFIELD_MEMBER(unsigned, _arg, _setArg, CHAR_BIT * sizeof(unsigned) - INSTRUCTION_BITS,
BITFIELD_MEMBER(unsigned, _instruction, _setInstruction, INSTRUCTION_BITS,
END_BITFIELD
)))
static_assert(sizeof(void *) <= sizeof(uint64_t), "must be able to fit a pointer into a 64-bit integer");
template<class T>
BITFIELD_PTR_GET(T, _data, INSTRUCTION_BITS)
template<class T>
BITFIELD_PTR_SET(T, _setData, INSTRUCTION_BITS)
private:
uint64_t _content = 0;
CodeOp* _alternative = 0;
};
struct SearchStruct
{
void destroy();
template<bool doInsert>
bool getTargetOpPtr(const CodeOp& insertedOp, CodeOp**& tgt);
CodeOp* getTargetOp(const FlatTerm::Entry* ftPos);
inline size_t length() const { return targets.size(); }
enum Kind
{
FN_STRUCT,
GROUND_TERM_STRUCT
};
CodeOp landingOp;
Kind kind;
std::vector<CodeOp*> targets;
protected:
SearchStruct(Kind kind, size_t length);
};
template<SearchStruct::Kind k>
struct SearchStructImpl
: public SearchStruct
{
SearchStructImpl(size_t length);
using T = typename std::conditional<k==SearchStruct::FN_STRUCT,unsigned,Term*>::type;
template<bool doInsert> CodeOp*& targetOp(const T& val);
std::vector<T> values;
};
using FnSearchStruct = SearchStructImpl<SearchStruct::FN_STRUCT>;
using GroundTermSearchStruct = SearchStructImpl<SearchStruct::GROUND_TERM_STRUCT>;
typedef Vector<CodeOp> CodeBlock;
typedef Stack<CodeOp> CodeStack;
struct BaseMatcher
{
public:
CodeOp* op;
protected:
bool doCheckGroundTerm();
size_t tp;
FlatTerm* ft;
};
inline bool isEmpty() const { return !_entryPoint; }
inline CodeOp* getEntryPoint() const { ASS(!isEmpty()); return &(*_entryPoint)[0]; }
static CodeBlock* firstOpToCodeBlock(CodeOp* op);
template<class Visitor>
void visitAllOps(Visitor visitor) const;
friend std::ostream& operator<<(std::ostream& out, const CodeTree& ct);
typedef DHMap<unsigned,unsigned> VarMap;
template<bool forLits>
struct Compiler
{
Compiler(CodeStack& code);
void updateCodeTree(CodeTree* tree);
void nextLit();
void handleTerm(const Term* trm);
void handleVar(unsigned var, Stack<unsigned>* globalCounterparts = nullptr);
void handleSubterms(const Term* trm, Stack<unsigned>& globalCounterparts);
CodeStack& code;
unsigned nextVarNum;
unsigned nextGlobalVarNum;
VarMap varMap;
VarMap globalVarMap;
};
using LitCompiler = Compiler<true>;
using TermCompiler = Compiler<false>;
static CodeBlock* buildBlock(CodeStack& code, size_t cnt, ILStruct* prev);
void incorporate(CodeStack& code);
template<SearchStruct::Kind k>
void compressCheckOps(CodeOp* chainStart);
void optimizeMemoryAfterRemoval(Stack<CodeOp*>* firstsInBlocks, CodeOp* removedOp);
template<bool checkRange>
struct RemovingMatcher
: public BaseMatcher
{
public:
bool next();
bool keepRecycled() const
{ return bindings.keepRecycled()
|| btStack.keepRecycled()
|| (firstsInBlocks && firstsInBlocks->keepRecycled()); }
protected:
void init(CodeOp* entry_, LitInfo* linfos_, size_t linfoCnt_,
CodeTree* tree_, Stack<CodeOp*>* firstsInBlocks_);
bool prepareLiteral();
bool backtrack();
bool doSearchStruct();
bool doCheckFun();
bool doAssignVar();
bool doCheckVar();
struct BTPoint
{
BTPoint(size_t tp, CodeOp* op, size_t fibDepth)
: tp(tp), op(op), fibDepth(fibDepth) {}
size_t tp;
CodeOp* op;
size_t fibDepth;
};
DArray<unsigned> bindings;
DHSet<unsigned> range;
Stack<BTPoint> btStack;
Stack<CodeOp*>* firstsInBlocks;
bool fresh;
size_t curLInfo;
CodeOp* entry;
size_t initFIBDepth;
LitInfo* linfos;
size_t linfoCnt;
bool matchingClauses;
CodeTree* tree;
};
struct BTPoint
{
BTPoint() {}
BTPoint(size_t tp, CodeOp* op) : tp(tp), op(op) {}
size_t tp;
CodeOp* op;
};
typedef Stack<BTPoint> BTStack;
typedef DArray<TermList> BindingArray;
struct Matcher
: public BaseMatcher
{
void init(CodeTree* tree, CodeOp* entry_);
inline bool finished() const { return !_fresh && !_matched; }
inline bool matched() const { return _matched && op->isLitEnd(); }
inline bool success() const { return _matched && op->isSuccess(); }
private:
bool backtrack();
bool doSearchStruct();
bool doCheckFun();
void doAssignVar();
bool doCheckVar();
protected:
bool execute();
bool prepareLiteral();
public:
BindingArray bindings;
bool keepRecycled() const { return bindings.keepRecycled(); }
protected:
bool _fresh;
bool _matched;
BTStack btStack;
CodeOp* entry;
CodeTree* tree;
LitInfo* linfos;
size_t linfoCnt;
size_t curLInfo;
};
void incTimeStamp();
bool _clauseCodeTree;
unsigned _curTimeStamp;
unsigned _maxVarCnt;
CodeBlock* _entryPoint;
};
}
#endif