#ifndef GOUGHCOMPILE_INTERNAL_H
#define GOUGHCOMPILE_INTERNAL_H
#include "gough_internal.h"
#include "mcclellancompile.h"
#include "ue2common.h"
#include "util/charreach.h"
#include "util/flat_containers.h"
#include "util/noncopyable.h"
#include "util/order_check.h"
#include <map>
#include <memory>
#include <set>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
namespace ue2 {
struct Grey;
struct GoughSSAVar;
struct GoughSSAVarJoin;
struct GoughVertexProps {
GoughVertexProps() {}
explicit GoughVertexProps(u32 state_in) : state_id(state_in) {}
u32 state_id = ~0U;
std::vector<std::shared_ptr<GoughSSAVarJoin> > vars;
std::vector<std::pair<ReportID, GoughSSAVar *> > reports;
std::vector<std::pair<ReportID, GoughSSAVar *> > reports_eod;
};
struct GoughEdgeProps {
GoughEdgeProps(void) : top(false) {}
bool top;
CharReach reach;
std::vector<std::shared_ptr<GoughSSAVar> > vars;
};
struct GoughGraphProps {
boost::adjacency_list_traits<boost::vecS, boost::vecS>::vertex_descriptor
initial_vertex;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
GoughVertexProps, GoughEdgeProps, GoughGraphProps> GoughGraph;
typedef GoughGraph::vertex_descriptor GoughVertex;
typedef GoughGraph::edge_descriptor GoughEdge;
struct gough_edge_id {
gough_edge_id(const GoughGraph &g, const GoughEdge &e)
: src(g[source(e, g)].state_id), dest(g[target(e, g)].state_id),
first_char(g[e].reach.find_first()) {}
bool operator<(const gough_edge_id &b) const {
const gough_edge_id &a = *this;
ORDER_CHECK(src);
ORDER_CHECK(dest);
ORDER_CHECK(first_char);
return false;
}
const u32 src;
const u32 dest;
const u32 first_char;
};
struct GoughSSAVarWithInputs;
struct GoughSSAVarMin;
struct GoughSSAVarJoin;
struct GoughSSAVar : noncopyable {
GoughSSAVar(void) : seen(false), slot(INVALID_SLOT) {}
virtual ~GoughSSAVar();
const flat_set<GoughSSAVar *> &get_inputs() const {
return inputs;
}
const flat_set<GoughSSAVarWithInputs *> &get_outputs() const {
return outputs;
}
virtual void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) = 0;
virtual void generate(std::vector<gough_ins> *out) const = 0;
bool seen;
u32 slot;
void clear_outputs();
virtual void clear_all() {
clear_outputs();
}
protected:
flat_set<GoughSSAVar *> inputs;
flat_set<GoughSSAVarWithInputs *> outputs;
friend struct GoughSSAVarWithInputs;
friend struct GoughSSAVarMin;
friend struct GoughSSAVarJoin;
};
struct GoughSSAVarNew : public GoughSSAVar {
explicit GoughSSAVarNew(u32 adjust_in) : adjust(adjust_in) {}
void replace_input(GoughSSAVar *, GoughSSAVar *) override {
assert(0);
}
void generate(std::vector<gough_ins> *out) const override;
const u32 adjust;
};
struct GoughSSAVarWithInputs : public GoughSSAVar {
GoughSSAVarWithInputs(void) {}
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override = 0;
virtual void clear_inputs() = 0;
void clear_all() override;
protected:
virtual void remove_input_raw(GoughSSAVar *v) = 0;
friend struct GoughSSAVar;
};
struct GoughSSAVarMin : public GoughSSAVarWithInputs {
GoughSSAVarMin(void) {}
void generate(std::vector<gough_ins> *out) const override;
void clear_inputs() override;
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override;
virtual void add_input(GoughSSAVar *v) {
inputs.insert(v);
v->outputs.insert(this);
}
protected:
void remove_input_raw(GoughSSAVar *v) override;
};
struct GoughSSAVarJoin : public GoughSSAVarWithInputs {
GoughSSAVarJoin(void) {}
void generate(std::vector<gough_ins> *out) const override;
GoughSSAVar *get_input(const GoughEdge &prev) const;
void clear_inputs() override;
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override;
void add_input(GoughSSAVar *v, GoughEdge prev);
const flat_set<GoughEdge> &get_edges_for_input(GoughSSAVar *input) const;
const std::map<GoughSSAVar *, flat_set<GoughEdge>> &get_input_map() const;
protected:
void remove_input_raw(GoughSSAVar *v) override;
private:
std::map<GoughSSAVar *, flat_set<GoughEdge>> input_map;
};
struct gough_accel_state_info {
u32 margin;
bool two_byte;
gough_accel_state_info(u32 margin_in, bool two_byte_in)
: margin(margin_in), two_byte(two_byte_in) {
}
};
u32 assign_slots(GoughGraph &g, const Grey &grey);
void find_allowed_accel_states(const GoughGraph &g,
const std::map<gough_edge_id, std::vector<gough_ins> > &blocks,
std::map<dstate_id_t, gough_accel_state_info> *out);
bool find_normal_self_loop(GoughVertex v, const GoughGraph &g, GoughEdge *out);
}
static inline
bool operator==(const gough_ins &a, const gough_ins &b) {
return a.op == b.op && a.dest == b.dest && a.src == b.src;
}
static inline
bool operator<(const gough_ins &a, const gough_ins &b) {
return std::tie(a.op, a.src, a.dest) < std::tie(b.op, b.src, b.dest);
}
#endif