summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/r600/sb/sb_valtable.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_valtable.h')
-rw-r--r--src/gallium/drivers/r600/sb/sb_valtable.h655
1 files changed, 655 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sb/sb_valtable.h b/src/gallium/drivers/r600/sb/sb_valtable.h
new file mode 100644
index 0000000000..661d4412a7
--- /dev/null
+++ b/src/gallium/drivers/r600/sb/sb_valtable.h
@@ -0,0 +1,655 @@
+/*
+ * 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 SB_VALTABLE_H_
+#define SB_VALTABLE_H_
+
+#include <stdint.h>
+#include <iostream>
+#include <vector>
+#include <set>
+#include <algorithm>
+
+#include "sb_bc.h"
+
+namespace r600_sb {
+
+enum special_regs {
+ SV_ALU_PRED = 128,
+ SV_EXEC_MASK,
+ SV_AR_INDEX,
+ SV_VALID_MASK
+};
+
+class node;
+class value;
+class shader;
+
+struct sel_chan
+{
+ unsigned id;
+
+ sel_chan(unsigned id = 0) : id(id) {}
+ sel_chan(unsigned sel, unsigned chan) : id(((sel << 2) | chan) + 1) {}
+
+ unsigned sel() const { return sel(id); }
+ unsigned chan() const {return chan(id); }
+ operator unsigned() const {return id;}
+
+ static unsigned sel(unsigned idx) { return (idx-1) >> 2; }
+ static unsigned chan(unsigned idx) { return (idx-1) & 3; }
+};
+
+inline std::ostream& operator <<(std::ostream& o, sel_chan r) {
+ static const char * ch = "xyzw";
+ o << r.sel() << "." << ch[r.chan()];
+ return o;
+}
+
+typedef std::vector<value*> vvec;
+
+class sb_pool {
+protected:
+ static const unsigned SB_POOL_ALIGN = 8;
+ static const unsigned SB_POOL_DEFAULT_BLOCK_SIZE = (1 << 16);
+
+ typedef std::vector<void*> block_vector;
+
+ unsigned block_size;
+ block_vector blocks;
+ unsigned total_size;
+
+public:
+ sb_pool(unsigned block_size = SB_POOL_DEFAULT_BLOCK_SIZE)
+ : block_size(block_size), blocks(), total_size() {}
+
+ virtual ~sb_pool() { free_all(); }
+
+ void* allocate(unsigned sz);
+
+protected:
+ void free_all();
+};
+
+template <typename V, typename Comp = std::less<V> >
+class sb_set {
+ typedef std::vector<V> data_vector;
+ data_vector vec;
+public:
+
+ typedef typename data_vector::iterator iterator;
+ typedef typename data_vector::const_iterator const_iterator;
+
+ sb_set() : vec() {}
+ ~sb_set() { }
+
+ iterator begin() { return vec.begin(); }
+ iterator end() { return vec.end(); }
+ const_iterator begin() const { return vec.begin(); }
+ const_iterator end() const { return vec.end(); }
+
+ void add_set(const sb_set& s) {
+ data_vector t;
+ t.reserve(vec.size() + s.vec.size());
+ std::set_union(vec.begin(), vec.end(), s.vec.begin(), s.vec.end(),
+ std::inserter(t, t.begin()), Comp());
+ vec.swap(t);
+ }
+
+ iterator lower_bound(const V& v) {
+ return std::lower_bound(vec.begin(), vec.end(), v, Comp());
+ }
+
+ std::pair<iterator, bool> insert(const V& v) {
+ iterator P = lower_bound(v);
+ if (P != vec.end() && is_equal(*P, v))
+ return std::make_pair(P, false);
+ return std::make_pair(vec.insert(P, v), true);
+ }
+
+ unsigned erase(const V& v) {
+ iterator P = lower_bound(v);
+ if (P == vec.end() || !is_equal(*P, v))
+ return 0;
+ vec.erase(P);
+ return 1;
+ }
+
+ void clear() { vec.clear(); }
+
+ bool empty() { return vec.empty(); }
+
+ bool is_equal(const V& v1, const V& v2) {
+ return !Comp()(v1, v2) && !Comp()(v2, v1);
+ }
+
+ iterator find(const V& v) {
+ iterator P = lower_bound(v);
+ return (P != vec.end() && is_equal(*P, v)) ? P : vec.end();
+ }
+
+ unsigned size() { return vec.size(); }
+ void erase(iterator I) { vec.erase(I); }
+};
+
+template <typename K, typename V, typename KComp = std::less<K> >
+class sb_map {
+ typedef std::pair<K, V> datatype;
+
+ struct Comp {
+ bool operator()(const datatype &v1, const datatype &v2) {
+ return KComp()(v1.first, v2.first);
+ }
+ };
+
+ typedef sb_set<datatype, Comp> dataset;
+
+ dataset set;
+
+public:
+
+ sb_map() : set() {}
+
+ typedef typename dataset::iterator iterator;
+
+ iterator begin() { return set.begin(); }
+ iterator end() { return set.end(); }
+
+ void clear() { set.clear(); }
+
+ V& operator[](const K& key) {
+ datatype P = std::make_pair(key, V());
+ iterator F = set.find(P);
+ if (F == set.end()) {
+ return (*(set.insert(P).first)).second;
+ } else {
+ return (*F).second;
+ }
+ }
+
+ std::pair<iterator, bool> insert(const datatype& d) {
+ return set.insert(d);
+ }
+
+ iterator find(const K& key) {
+ return set.find(std::make_pair(key, V()));
+ }
+
+ unsigned erase(const K& key) {
+ return set.erase(std::make_pair(key, V()));
+ }
+
+ void erase(iterator I) {
+ set.erase(I);
+ }
+};
+
+class sb_bitset {
+ typedef uint32_t basetype;
+ static const unsigned bt_bits = sizeof(basetype) << 3;
+ std::vector<basetype> data;
+ unsigned bit_size;
+
+public:
+
+ sb_bitset() : data(), bit_size() {}
+
+ bool get(unsigned id);
+ void set(unsigned id, bool bit = true);
+ bool set_chk(unsigned id, bool bit = true);
+
+ void clear();
+ void resize(unsigned size);
+
+ unsigned size() { return bit_size; }
+
+ unsigned find_bit(unsigned start = 0);
+
+ void swap(sb_bitset & bs2);
+
+ bool operator==(const sb_bitset &bs2);
+ bool operator!=(const sb_bitset &bs2) { return !(*this == bs2); }
+
+ sb_bitset& operator|=(const sb_bitset &bs2) {
+ if (bit_size < bs2.bit_size) {
+ resize(bs2.bit_size);
+ }
+
+ for (unsigned i = 0, c = std::min(data.size(), bs2.data.size()); i < c;
+ ++i) {
+ data[i] |= bs2.data[i];
+ }
+ return *this;
+ }
+
+ sb_bitset& operator&=(const sb_bitset &bs2);
+ sb_bitset& mask(const sb_bitset &bs2);
+
+ friend sb_bitset operator|(const sb_bitset &b1, const sb_bitset &b2) {
+ sb_bitset nbs(b1);
+ nbs |= b2;
+ return nbs;
+ }
+};
+
+class value;
+
+enum value_kind {
+ VLK_REG,
+ VLK_REL_REG,
+ VLK_SPECIAL_REG,
+ VLK_TEMP,
+
+ VLK_CONST,
+ VLK_KCACHE,
+ VLK_PARAM,
+ VLK_SPECIAL_CONST,
+
+ VLK_UNDEF
+};
+
+
+
+class sb_value_pool : protected sb_pool {
+ unsigned aligned_elt_size;
+
+public:
+ sb_value_pool(unsigned elt_size, unsigned block_elts = 256)
+ : sb_pool(block_elts * (aligned_elt_size = ((elt_size +
+ SB_POOL_ALIGN - 1) & ~(SB_POOL_ALIGN - 1)))) {}
+
+ virtual ~sb_value_pool() { delete_all(); }
+
+ value* create(value_kind k, sel_chan regid, unsigned ver);
+
+ value* operator[](unsigned id) {
+ unsigned offset = id * aligned_elt_size;
+ unsigned block_id;
+ if (offset < block_size) {
+ block_id = 0;
+ } else {
+ block_id = offset / block_size;
+ offset = offset % block_size;
+ }
+ return (value*)((char*)blocks[block_id] + offset);
+ }
+
+ unsigned size() { return total_size / aligned_elt_size; }
+
+protected:
+ void delete_all();
+};
+
+
+
+
+
+class sb_value_set {
+
+ sb_bitset bs;
+
+public:
+ sb_value_set() : bs() {}
+
+ class iterator {
+ sb_value_pool &vp;
+ sb_value_set *s;
+ unsigned nb;
+ public:
+ iterator(shader &sh, sb_value_set *s, unsigned nb = 0);
+
+
+ iterator& operator++() {
+ if (nb + 1 < s->bs.size())
+ nb = s->bs.find_bit(nb + 1);
+ else
+ nb = s->bs.size();
+ return *this;
+ }
+ bool operator !=(const iterator &i) {
+ return s != i.s || nb != i.nb;
+ }
+ bool operator ==(const iterator &i) { return !(*this != i); }
+ value* operator *() {
+ return vp[nb];
+ }
+
+
+ };
+
+ iterator begin(shader &sh) {
+ return iterator(sh, this, bs.size() ? bs.find_bit(0) : 0);
+ }
+ iterator end(shader &sh) { return iterator(sh, this, bs.size()); }
+
+ bool add_set_checked(sb_value_set & s2);
+
+ void add_set(sb_value_set & s2) {
+ if (bs.size() < s2.bs.size())
+ bs.resize(s2.bs.size());
+ bs |= s2.bs;
+ }
+
+ void remove_set(sb_value_set & s2);
+
+ bool add_vec(vvec &vv);
+
+ bool add_val(value *v);
+ bool contains(value *v);
+
+ bool remove_val(value *v);
+
+ bool remove_vec(vvec &vv);
+
+ void clear();
+
+ bool empty();
+};
+
+typedef sb_value_set val_set;
+
+struct gpr_array {
+ sel_chan base_gpr; // original gpr
+ sel_chan gpr; // assigned by regalloc
+ unsigned array_size;
+
+ gpr_array(sel_chan base_gpr, unsigned array_size) : base_gpr(base_gpr),
+ array_size(array_size) {}
+
+ unsigned hash() { return (base_gpr << 10) * array_size; }
+
+ val_set interferences;
+ vvec refs;
+
+ bool is_dead();
+
+};
+
+typedef std::vector<gpr_array*> regarray_vec;
+
+enum value_flags {
+ VLF_UNDEF = (1 << 0),
+ VLF_READONLY = (1 << 1),
+ VLF_DEAD = (1 << 2),
+
+ VLF_PIN_REG = (1 << 3),
+ VLF_PIN_CHAN = (1 << 4),
+
+ // opposite to alu clause local value - goes through alu clause boundary
+ // (can't use temp gpr, can't recolor in the alu scheduler, etc)
+ VLF_GLOBAL = (1 << 5),
+ VLF_FIXED = (1 << 6),
+ VLF_PVPS = (1 << 7),
+
+ VLF_PREALLOC = (1 << 8)
+};
+
+inline value_flags operator |(value_flags l, value_flags r) {
+ return (value_flags)((unsigned)l|(unsigned)r);
+}
+inline value_flags operator &(value_flags l, value_flags r) {
+ return (value_flags)((unsigned)l&(unsigned)r);
+}
+inline value_flags operator ~(value_flags l) {
+ return (value_flags)(~(unsigned)l);
+}
+inline value_flags& operator |=(value_flags &l, value_flags r) {
+ l = l | r;
+ return l;
+}
+inline value_flags& operator &=(value_flags &l, value_flags r) {
+ l = l & r;
+ return l;
+}
+
+struct value;
+
+std::ostream& operator << (std::ostream &o, value &v);
+
+typedef uint32_t value_hash;
+
+enum use_kind {
+ UK_SRC,
+ UK_SRC_REL,
+ UK_DST_REL,
+ UK_MAYDEF,
+ UK_MAYUSE,
+ UK_PRED,
+ UK_COND
+};
+
+struct use_info {
+ use_info *next;
+ node *op;
+ use_kind kind;
+ int arg;
+
+ use_info(node *n, use_kind kind, int arg, use_info* next)
+ : next(next), op(n), kind(kind), arg(arg) {}
+};
+
+enum constraint_kind {
+ CK_SAME_REG,
+ CK_PACKED_BS,
+ CK_PHI
+};
+
+class shader;
+class sb_value_pool;
+class ra_chunk;
+class ra_constraint;
+
+class value {
+protected:
+ value(unsigned sh_id, value_kind k, sel_chan select, unsigned ver = 0)
+ : kind(k), flags(),
+ rel(), array(),
+ version(ver), select(select), pin_gpr(select), gpr(),
+ gvn_source(), ghash(),
+ def(), adef(), uses(), constraint(), chunk(),
+ literal_value(), uid(sh_id) {}
+
+ ~value() { delete_uses(); }
+
+ friend class sb_value_pool;
+public:
+ value_kind kind;
+ value_flags flags;
+
+ vvec mdef;
+ vvec muse;
+ value *rel;
+ gpr_array *array;
+
+ unsigned version;
+
+ sel_chan select;
+ sel_chan pin_gpr;
+ sel_chan gpr;
+
+ value *gvn_source;
+ value_hash ghash;
+
+ node *def, *adef;
+ use_info *uses;
+
+ ra_constraint *constraint;
+ ra_chunk *chunk;
+
+ literal literal_value;
+
+ bool is_const() { return kind == VLK_CONST || kind == VLK_UNDEF; }
+
+ bool is_AR() {
+ return is_special_reg() && select == sel_chan(SV_AR_INDEX, 0);
+ }
+
+ node* any_def() {
+ assert(!(def && adef));
+ return def ? def : adef;
+ }
+
+ value* gvalue() {
+ value *v = this;
+ while (v->gvn_source && v != v->gvn_source)
+ // FIXME we really shouldn't have such chains
+ v = v->gvn_source;
+ return v;
+ }
+
+ bool is_float_0_or_1() {
+ value *v = gvalue();
+ return v->is_const() && (v->literal_value == literal(0)
+ || v->literal_value == literal(1.0f));
+ }
+
+ bool is_undef() { return gvalue()->kind == VLK_UNDEF; }
+
+ bool is_any_gpr() {
+ return (kind == VLK_REG || kind == VLK_TEMP);
+ }
+
+ bool is_agpr() {
+ return array && is_any_gpr();
+ }
+
+ // scalar gpr, as opposed to element of gpr array
+ bool is_sgpr() {
+ return !array && is_any_gpr();
+ }
+
+ bool is_special_reg() { return kind == VLK_SPECIAL_REG; }
+ bool is_any_reg() { return is_any_gpr() || is_special_reg(); }
+ bool is_kcache() { return kind == VLK_KCACHE; }
+ bool is_rel() { return kind == VLK_REL_REG; }
+ bool is_readonly() { return flags & VLF_READONLY; }
+
+ bool is_chan_pinned() { return flags & VLF_PIN_CHAN; }
+ bool is_reg_pinned() { return flags & VLF_PIN_REG; }
+
+ bool is_global();
+ void set_global();
+ void set_prealloc();
+
+ bool is_prealloc();
+
+ bool is_fixed();
+ void fix();
+
+ bool is_dead() { return flags & VLF_DEAD; }
+
+ literal & get_const_value() {
+ value *v = gvalue();
+ assert(v->is_const());
+ return v->literal_value;
+ }
+
+ // true if needs to be encoded as literal in alu
+ bool is_literal() {
+ return is_const()
+ && literal_value != literal(0)
+ && literal_value != literal(1)
+ && literal_value != literal(-1)
+ && literal_value != literal(0.5)
+ && literal_value != literal(1.0);
+ }
+
+ void add_use(node *n, use_kind kind, int arg);
+
+ value_hash hash();
+ value_hash rel_hash();
+
+ void assign_source(value *v) {
+ assert(!gvn_source || gvn_source == this);
+ gvn_source = v->gvalue();
+ }
+
+ bool v_equal(value *v) { return gvalue() == v->gvalue(); }
+
+ unsigned use_count();
+ void delete_uses();
+
+ sel_chan get_final_gpr() {
+ if (array && array->gpr) {
+ int reg_offset = select.sel() - array->base_gpr.sel();
+ if (rel && rel->is_const())
+ reg_offset += rel->get_const_value().i;
+ return array->gpr + (reg_offset << 2);
+ } else {
+ return gpr;
+ }
+ }
+
+ unsigned get_final_chan() {
+ if (array) {
+ assert(array->gpr);
+ return array->gpr.chan();
+ } else {
+ assert(gpr);
+ return gpr.chan();
+ }
+ }
+
+ val_set interferences;
+ unsigned uid;
+};
+
+class expr_handler;
+
+class value_table {
+ typedef std::vector<value*> vt_item;
+ typedef std::vector<vt_item> vt_table;
+
+ expr_handler &ex;
+
+ unsigned size_bits;
+ unsigned size;
+ unsigned size_mask;
+
+ vt_table hashtable;
+
+ unsigned cnt;
+
+public:
+
+ value_table(expr_handler &ex, unsigned size_bits = 10)
+ : ex(ex), size_bits(size_bits), size(1u << size_bits),
+ size_mask(size - 1), hashtable(size), cnt() {}
+
+ ~value_table() {}
+
+ void add_value(value* v);
+
+ bool expr_equal(value* l, value* r);
+
+ unsigned count() { return cnt; }
+
+ void get_values(vvec & v);
+};
+
+} // namespace r600_sb
+
+#endif /* SB_VALTABLE_H_ */