summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/r600/sb/sb_ir.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_ir.h')
-rw-r--r--src/gallium/drivers/r600/sb/sb_ir.h522
1 files changed, 522 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sb/sb_ir.h b/src/gallium/drivers/r600/sb/sb_ir.h
new file mode 100644
index 0000000000..cb3df2d747
--- /dev/null
+++ b/src/gallium/drivers/r600/sb/sb_ir.h
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Vadim Girlin
+ */
+
+#ifndef R600_SB_IR_H_
+#define R600_SB_IR_H_
+
+#include <algorithm>
+
+namespace r600_sb {
+
+class sb_context;
+
+enum node_type {
+ NT_UNKNOWN,
+ NT_LIST,
+ NT_OP,
+ NT_REGION,
+ NT_REPEAT,
+ NT_DEPART,
+ NT_IF,
+};
+
+enum node_subtype {
+ NST_UNKNOWN,
+ NST_LIST,
+ NST_ALU_GROUP,
+ NST_ALU_CLAUSE,
+ NST_ALU_INST,
+ NST_ALU_PACKED_INST,
+ NST_CF_INST,
+ NST_FETCH_INST,
+ NST_TEX_CLAUSE,
+ NST_VTX_CLAUSE,
+
+ NST_BB,
+
+ NST_PHI,
+ NST_PSI,
+ NST_COPY,
+
+ NST_LOOP_PHI_CONTAINER,
+ NST_LOOP_CONTINUE,
+ NST_LOOP_BREAK
+};
+
+enum node_flags {
+ NF_EMPTY = 0,
+ NF_DEAD = (1 << 0),
+ NF_REG_CONSTRAINT = (1 << 1),
+ NF_CHAN_CONSTRAINT = (1 << 2),
+ NF_ALU_4SLOT = (1 << 3),
+ NF_CONTAINER = (1 << 4),
+
+ NF_COPY_MOV = (1 << 5),
+
+ NF_DONT_KILL = (1 << 6),
+ NF_DONT_HOIST = (1 << 7),
+ NF_DONT_MOVE = (1 << 8),
+
+ // for KILLxx - we want to schedule them as early as possible
+ NF_SCHEDULE_EARLY = (1 << 9)
+};
+
+inline node_flags operator |(node_flags l, node_flags r) {
+ return (node_flags)((unsigned)l|(unsigned)r);
+}
+inline node_flags& operator |=(node_flags &l, node_flags r) {
+ l = l | r;
+ return l;
+}
+
+inline node_flags& operator &=(node_flags &l, node_flags r) {
+ l = (node_flags)((unsigned)l & (unsigned)r);
+ return l;
+}
+
+inline node_flags operator ~(node_flags r) {
+ return (node_flags)~(unsigned)r;
+}
+
+struct node_stats {
+ unsigned alu_count;
+ unsigned alu_kill_count;
+ unsigned alu_copy_mov_count;
+ unsigned cf_count;
+ unsigned fetch_count;
+ unsigned region_count;
+ unsigned loop_count;
+ unsigned phi_count;
+ unsigned loop_phi_count;
+ unsigned depart_count;
+ unsigned repeat_count;
+ unsigned if_count;
+
+ node_stats() : alu_count(), alu_kill_count(), alu_copy_mov_count(),
+ cf_count(), fetch_count(), region_count(),
+ loop_count(), phi_count(), loop_phi_count(), depart_count(),
+ repeat_count(), if_count() {}
+
+ void dump();
+};
+
+class shader;
+
+class vpass;
+
+class container_node;
+class region_node;
+
+class node {
+
+protected:
+ node(node_type nt, node_subtype nst, node_flags flags = NF_EMPTY)
+ : prev(), next(), parent(),
+ type(nt), subtype(nst), flags(flags),
+ pred(), dst(), src() {}
+
+ virtual ~node() {};
+
+public:
+ node *prev, *next;
+ container_node *parent;
+
+ node_type type;
+ node_subtype subtype;
+ node_flags flags;
+
+ value *pred;
+
+ vvec dst;
+ vvec src;
+
+ virtual bool is_valid() { return true; }
+ virtual bool accept(vpass &p, bool enter);
+
+ void insert_before(node *n);
+ void insert_after(node *n);
+ void replace_with(node *n);
+ void remove();
+
+ virtual value_hash hash();
+ value_hash hash_src();
+
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ bool is_container() { return flags & NF_CONTAINER; }
+
+ bool is_alu_packed() { return subtype == NST_ALU_PACKED_INST; }
+ bool is_alu_inst() { return subtype == NST_ALU_INST; }
+ bool is_alu_group() { return subtype == NST_ALU_GROUP; }
+ bool is_alu_clause() { return subtype == NST_ALU_CLAUSE; }
+
+ bool is_fetch_clause() {
+ return subtype == NST_TEX_CLAUSE || subtype == NST_VTX_CLAUSE;
+ }
+
+ bool is_copy() { return subtype == NST_COPY; }
+ bool is_copy_mov() { return flags & NF_COPY_MOV; }
+ bool is_any_alu() { return is_alu_inst() || is_alu_packed() || is_copy(); }
+
+ bool is_fetch_inst() { return subtype == NST_FETCH_INST; }
+ bool is_cf_inst() { return subtype == NST_CF_INST; }
+
+ bool is_region() { return type == NT_REGION; }
+ bool is_depart() { return type == NT_DEPART; }
+ bool is_repeat() { return type == NT_REPEAT; }
+ bool is_if() { return type == NT_IF; }
+ bool is_bb() { return subtype == NST_BB; }
+
+ bool is_phi() { return subtype == NST_PHI; }
+
+ bool is_dead() { return flags & NF_DEAD; }
+
+ bool is_cf_op(unsigned op);
+ bool is_alu_op(unsigned op);
+ bool is_fetch_op(unsigned op);
+
+ unsigned cf_op_flags();
+ unsigned alu_op_flags();
+ unsigned alu_op_slot_flags();
+ unsigned fetch_op_flags();
+
+ bool is_mova();
+ bool is_pred_set();
+
+ bool vec_uses_ar(vvec &vv) {
+ for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
+ value *v = *I;
+ if (v && v->rel && !v->rel->is_const())
+ return true;
+ }
+ return false;
+ }
+
+ bool uses_ar() {
+ return vec_uses_ar(dst) || vec_uses_ar(src);
+ }
+
+
+ region_node* get_parent_region();
+
+ friend class shader;
+};
+
+class container_node : public node {
+public:
+
+ container_node(node_type nt = NT_LIST, node_subtype nst = NST_LIST,
+ node_flags flags = NF_EMPTY)
+ : node(nt, nst, flags | NF_CONTAINER), first(), last(),
+ live_after(), live_before() {}
+
+ // child items list
+ node *first, *last;
+
+ val_set live_after;
+ val_set live_before;
+
+ class iterator {
+ node *p;
+ public:
+ iterator(node *pp = NULL) : p(pp) {}
+ iterator & operator ++() { p = p->next; return *this;}
+ iterator & operator --() { p = p->prev; return *this;}
+ node* operator *() { return p; }
+ node* operator ->() { return p; }
+ const iterator advance(int n) {
+ if (!n) return *this;
+ iterator I(p);
+ if (n > 0) while (n--) ++I;
+ else while (n++) --I;
+ return I;
+ }
+ const iterator operator +(int n) { return advance(n); }
+ const iterator operator -(int n) { return advance(-n); }
+ bool operator !=(const iterator &i) { return p != i.p; }
+ bool operator ==(const iterator &i) { return p == i.p; }
+ };
+
+ class riterator {
+ iterator i;
+ public:
+ riterator(node *p = NULL) : i(p) {}
+ riterator & operator ++() { --i; return *this;}
+ riterator & operator --() { ++i; return *this;}
+ node* operator *() { return *i; }
+ node* operator ->() { return *i; }
+ bool operator !=(const riterator &r) { return i != r.i; }
+ bool operator ==(const riterator &r) { return i == r.i; }
+ };
+
+ iterator begin() { return first; }
+ iterator end() { return NULL; }
+ riterator rbegin() { return last; }
+ riterator rend() { return NULL; }
+
+ bool empty() { assert(first != NULL || first == last); return !first; }
+ unsigned count();
+
+ // used with node containers that represent shceduling queues
+ // ignores copies and takes into account alu_packed_node items
+ unsigned real_alu_count();
+
+ void push_back(node *n);
+ void push_front(node *n);
+
+ void insert_node_before(node *s, node *n);
+ void insert_node_after(node *s, node *n);
+
+ void append_from(container_node *c);
+
+ // remove range [b..e) from some container and assign to this container
+ void move(iterator b, iterator e);
+
+ void expand();
+ void expand(container_node *n);
+ void remove_node(node *n);
+
+ node *cut(iterator b, iterator e);
+
+ void clear() { first = last = NULL; }
+
+ virtual bool is_valid() { return true; }
+ virtual bool accept(vpass &p, bool enter);
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ node* front() { return first; }
+ node* back() { return last; }
+
+ void collect_stats(node_stats &s);
+
+ friend class shader;
+
+
+};
+
+typedef container_node::iterator node_iterator;
+typedef container_node::riterator node_riterator;
+
+class alu_group_node : public container_node {
+protected:
+ alu_group_node() : container_node(NT_LIST, NST_ALU_GROUP), literals() {}
+public:
+
+ std::vector<literal> literals;
+
+ virtual bool is_valid() { return subtype == NST_ALU_GROUP; }
+ virtual bool accept(vpass &p, bool enter);
+
+
+ unsigned literal_chan(literal l) {
+ std::vector<literal>::iterator F =
+ std::find(literals.begin(), literals.end(), l);
+ assert(F != literals.end());
+ return F - literals.begin();
+ }
+
+ friend class shader;
+};
+
+class cf_node : public container_node {
+protected:
+ cf_node() : container_node(NT_OP, NST_CF_INST), bc(), jump_target(),
+ jump_after_target() {};
+public:
+ bc_cf bc;
+
+ cf_node *jump_target;
+ bool jump_after_target;
+
+ virtual bool is_valid() { return subtype == NST_CF_INST; }
+ virtual bool accept(vpass &p, bool enter);
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ void jump(cf_node *c) { jump_target = c; jump_after_target = false; }
+ void jump_after(cf_node *c) { jump_target = c; jump_after_target = true; }
+
+ friend class shader;
+};
+
+class alu_node : public node {
+protected:
+ alu_node() : node(NT_OP, NST_ALU_INST), bc() {};
+public:
+ bc_alu bc;
+
+ virtual bool is_valid() { return subtype == NST_ALU_INST; }
+ virtual bool accept(vpass &p, bool enter);
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ unsigned forced_bank_swizzle() {
+ return ((bc.op_ptr->flags & AF_INTERP) && (bc.slot_flags == AF_4V)) ?
+ VEC_210 : 0;
+ }
+
+ // return param index + 1 if instruction references interpolation param,
+ // otherwise 0
+ unsigned interp_param();
+
+ alu_group_node *get_alu_group_node();
+
+ friend class shader;
+};
+
+// for multi-slot instrs - DOT/INTERP/... (maybe useful for 64bit pairs later)
+class alu_packed_node : public container_node {
+protected:
+ alu_packed_node() : container_node(NT_OP, NST_ALU_PACKED_INST) {}
+public:
+
+ const alu_op_info* op_ptr() {
+ return static_cast<alu_node*>(first)->bc.op_ptr;
+ }
+ unsigned op() { return static_cast<alu_node*>(first)->bc.op; }
+ void init_args();
+
+ virtual bool is_valid() { return subtype == NST_ALU_PACKED_INST; }
+ virtual bool accept(vpass &p, bool enter);
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ unsigned get_slot_mask();
+ void update_packed_items(sb_context &ctx);
+
+ friend class shader;
+};
+
+class fetch_node : public node {
+protected:
+ fetch_node() : node(NT_OP, NST_FETCH_INST), bc() {};
+public:
+ bc_fetch bc;
+
+ virtual bool is_valid() { return subtype == NST_FETCH_INST; }
+ virtual bool accept(vpass &p, bool enter);
+ virtual bool fold_dispatch(expr_handler *ex);
+
+ bool uses_grad() { return bc.op_ptr->flags & FF_USEGRAD; }
+
+ friend class shader;
+};
+
+class region_node;
+
+class repeat_node : public container_node {
+protected:
+ repeat_node(region_node *target, unsigned id)
+ : container_node(NT_REPEAT, NST_LIST), target(target), rep_id(id) {}
+public:
+ region_node *target;
+ unsigned rep_id;
+
+ virtual bool accept(vpass &p, bool enter);
+
+ friend class shader;
+};
+
+class depart_node : public container_node {
+protected:
+ depart_node(region_node *target, unsigned id)
+ : container_node(NT_DEPART, NST_LIST), target(target), dep_id(id) {}
+public:
+ region_node *target;
+ unsigned dep_id;
+
+ virtual bool accept(vpass &p, bool enter);
+
+ friend class shader;
+};
+
+class if_node : public container_node {
+protected:
+ if_node() : container_node(NT_IF, NST_LIST), cond() {};
+public:
+ value *cond; // glued to pseudo output (dst[2]) of the PRED_SETxxx
+
+ virtual bool accept(vpass &p, bool enter);
+
+ friend class shader;
+};
+
+typedef std::vector<depart_node*> depart_vec;
+typedef std::vector<repeat_node*> repeat_vec;
+
+class region_node : public container_node {
+protected:
+ region_node(unsigned id) : container_node(NT_REGION, NST_LIST), region_id(id),
+ loop_phi(), phi(), vars_defined(), departs(), repeats() {}
+public:
+ unsigned region_id;
+
+ container_node *loop_phi;
+ container_node *phi;
+
+ val_set vars_defined;
+
+ depart_vec departs;
+ repeat_vec repeats;
+
+ virtual bool accept(vpass &p, bool enter);
+
+ unsigned dep_count() { return departs.size(); }
+ unsigned rep_count() { return repeats.size() + 1; }
+
+ bool is_loop() { return !repeats.empty(); }
+
+ container_node* get_entry_code_location() {
+ node *p = first;
+ while (p && (p->is_depart() || p->is_repeat()))
+ p = static_cast<container_node*>(p)->first;
+
+ container_node *c = static_cast<container_node*>(p);
+ if (c->is_bb())
+ return c;
+ else
+ return c->parent;
+ }
+
+ void expand_depart(depart_node *d);
+ void expand_repeat(repeat_node *r);
+
+ friend class shader;
+};
+
+class bb_node : public container_node {
+protected:
+ bb_node(unsigned id, unsigned loop_level)
+ : container_node(NT_LIST, NST_BB), id(id), loop_level(loop_level) {}
+public:
+ unsigned id;
+ unsigned loop_level;
+
+ virtual bool accept(vpass &p, bool enter);
+
+ friend class shader;
+};
+
+} // namespace r600_sb
+
+#endif /* R600_SB_IR_H_ */