diff options
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_ir.h')
-rw-r--r-- | src/gallium/drivers/r600/sb/sb_ir.h | 522 |
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_ */ |