Path: blob/21.2-virgl/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h
4574 views
/*1* Copyright 2011 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#ifndef __NV50_IR_UTIL_H__23#define __NV50_IR_UTIL_H__2425#include <new>26#include <assert.h>27#include <stdio.h>28#include <memory>29#include <map>3031#ifndef NDEBUG32# include <typeinfo>33#endif3435#include "util/u_inlines.h"36#include "util/u_memory.h"3738#define ERROR(args...) _debug_printf("ERROR: " args)39#define WARN(args...) _debug_printf("WARNING: " args)40#define INFO(args...) _debug_printf(args)4142#define INFO_DBG(m, f, args...) \43do { \44if (m & NV50_IR_DEBUG_##f) \45_debug_printf(args); \46} while(0)4748#define FATAL(args...) \49do { \50fprintf(stderr, args); \51abort(); \52} while(0)535455#define NV50_IR_FUNC_ALLOC_OBJ_DEF(obj, f, args...) \56new ((f)->getProgram()->mem_##obj.allocate()) obj(f, args)5758#define new_Instruction(f, args...) \59NV50_IR_FUNC_ALLOC_OBJ_DEF(Instruction, f, args)60#define new_CmpInstruction(f, args...) \61NV50_IR_FUNC_ALLOC_OBJ_DEF(CmpInstruction, f, args)62#define new_TexInstruction(f, args...) \63NV50_IR_FUNC_ALLOC_OBJ_DEF(TexInstruction, f, args)64#define new_FlowInstruction(f, args...) \65NV50_IR_FUNC_ALLOC_OBJ_DEF(FlowInstruction, f, args)6667#define new_LValue(f, args...) \68NV50_IR_FUNC_ALLOC_OBJ_DEF(LValue, f, args)697071#define NV50_IR_PROG_ALLOC_OBJ_DEF(obj, p, args...) \72new ((p)->mem_##obj.allocate()) obj(p, args)7374#define new_Symbol(p, args...) \75NV50_IR_PROG_ALLOC_OBJ_DEF(Symbol, p, args)76#define new_ImmediateValue(p, args...) \77NV50_IR_PROG_ALLOC_OBJ_DEF(ImmediateValue, p, args)787980#define delete_Instruction(p, insn) (p)->releaseInstruction(insn)81#define delete_Value(p, val) (p)->releaseValue(val)828384namespace nv50_ir {8586class Iterator87{88public:89virtual ~Iterator() { };90virtual void next() = 0;91virtual void *get() const = 0;92virtual bool end() const = 0; // if true, get will return 093virtual void reset() { assert(0); } // only for graph iterators94};9596#if __cplusplus >= 201103L97typedef std::unique_ptr<Iterator> IteratorRef;98#else99typedef std::auto_ptr<Iterator> IteratorRef;100#endif101102class ManipIterator : public Iterator103{104public:105virtual bool insert(void *) = 0; // insert after current position106virtual void erase() = 0;107};108109// WARNING: do not use a->prev/next for __item or __list110111#define DLLIST_DEL(__item) \112do { \113(__item)->prev->next = (__item)->next; \114(__item)->next->prev = (__item)->prev; \115(__item)->next = (__item); \116(__item)->prev = (__item); \117} while(0)118119#define DLLIST_ADDTAIL(__list, __item) \120do { \121(__item)->next = (__list); \122(__item)->prev = (__list)->prev; \123(__list)->prev->next = (__item); \124(__list)->prev = (__item); \125} while(0)126127#define DLLIST_ADDHEAD(__list, __item) \128do { \129(__item)->prev = (__list); \130(__item)->next = (__list)->next; \131(__list)->next->prev = (__item); \132(__list)->next = (__item); \133} while(0)134135#define DLLIST_MERGE(__listA, __listB, ty) \136do { \137ty prevB = (__listB)->prev; \138(__listA)->prev->next = (__listB); \139(__listB)->prev->next = (__listA); \140(__listB)->prev = (__listA)->prev; \141(__listA)->prev = prevB; \142} while(0)143144#define DLLIST_EMPTY(__list) ((__list)->next == (__list))145146#define DLLIST_FOR_EACH(list, it) \147for (DLList::Iterator it = (list)->iterator(); !(it).end(); (it).next())148149class DLList150{151public:152class Item153{154public:155Item(void *priv) : next(this), prev(this), data(priv) { }156157public:158Item *next;159Item *prev;160void *data;161};162163DLList() : head(0) { }164~DLList() { clear(); }165166inline void insertHead(void *data)167{168Item *item = new Item(data);169170assert(data);171172item->prev = &head;173item->next = head.next;174head.next->prev = item;175head.next = item;176}177178inline void insertTail(void *data)179{180Item *item = new Item(data);181182assert(data);183184DLLIST_ADDTAIL(&head, item);185}186187inline void insert(void *data) { insertTail(data); }188189void clear();190191class Iterator : public ManipIterator192{193public:194Iterator(Item *head, bool r) : rev(r), pos(r ? head->prev : head->next),195term(head) { }196197virtual void next() { if (!end()) pos = rev ? pos->prev : pos->next; }198virtual void *get() const { return pos->data; }199virtual bool end() const { return pos == term; }200201// caution: if you're at end-2 and erase it, then do next, you're at end202virtual void erase();203virtual bool insert(void *data);204205// move item to another list, no consistency with its iterators though206void moveToList(DLList&);207208private:209const bool rev;210Item *pos;211Item *term;212213friend class DLList;214};215216inline void erase(Iterator& pos)217{218pos.erase();219}220221Iterator iterator()222{223return Iterator(&head, false);224}225226Iterator revIterator()227{228return Iterator(&head, true);229}230231private:232Item head;233};234235class Stack236{237public:238class Item {239public:240union {241void *p;242int i;243unsigned int u;244float f;245double d;246} u;247248Item() { memset(&u, 0, sizeof(u)); }249};250251Stack() : size(0), limit(0), array(0) { }252~Stack() { if (array) FREE(array); }253254inline void push(int i) { Item data; data.u.i = i; push(data); }255inline void push(unsigned int u) { Item data; data.u.u = u; push(data); }256inline void push(void *p) { Item data; data.u.p = p; push(data); }257inline void push(float f) { Item data; data.u.f = f; push(data); }258259inline void push(Item data)260{261if (size == limit)262resize();263array[size++] = data;264}265266inline Item pop()267{268if (!size) {269Item data;270assert(0);271return data;272}273return array[--size];274}275276inline unsigned int getSize() { return size; }277278inline Item& peek() { assert(size); return array[size - 1]; }279280void clear(bool releaseStorage = false)281{282if (releaseStorage && array)283FREE(array);284size = limit = 0;285}286287void moveTo(Stack&); // move all items to target (not like push(pop()))288289private:290void resize()291{292unsigned int sizeOld, sizeNew;293294sizeOld = limit * sizeof(Item);295limit = MAX2(4, limit + limit);296sizeNew = limit * sizeof(Item);297298array = (Item *)REALLOC(array, sizeOld, sizeNew);299}300301unsigned int size;302unsigned int limit;303Item *array;304};305306class DynArray307{308public:309class Item310{311public:312union {313uint32_t u32;314void *p;315};316};317318DynArray() : data(NULL), size(0) { }319320~DynArray() { if (data) FREE(data); }321322inline Item& operator[](unsigned int i)323{324if (i >= size)325resize(i);326return data[i];327}328329inline const Item operator[](unsigned int i) const330{331return data[i];332}333334void resize(unsigned int index)335{336const unsigned int oldSize = size * sizeof(Item);337338if (!size)339size = 8;340while (size <= index)341size <<= 1;342343data = (Item *)REALLOC(data, oldSize, size * sizeof(Item));344}345346void clear()347{348FREE(data);349data = NULL;350size = 0;351}352353private:354Item *data;355unsigned int size;356};357358class ArrayList359{360public:361ArrayList() : size(0) { }362363void insert(void *item, int& id)364{365id = ids.getSize() ? ids.pop().u.i : size++;366data[id].p = item;367}368369void remove(int& id)370{371const unsigned int uid = id;372assert(uid < size && data[id].p);373ids.push(uid);374data[uid].p = NULL;375id = -1;376}377378inline int getSize() const { return size; }379380inline void *get(unsigned int id) { assert(id < size); return data[id].p; }381382class Iterator : public nv50_ir::Iterator383{384public:385Iterator(const ArrayList *array) : pos(0), data(array->data)386{387size = array->getSize();388if (size)389nextValid();390}391392void nextValid() { while ((pos < size) && !data[pos].p) ++pos; }393394void next() { if (pos < size) { ++pos; nextValid(); } }395void *get() const { assert(pos < size); return data[pos].p; }396bool end() const { return pos >= size; }397398private:399unsigned int pos;400unsigned int size;401const DynArray& data;402403friend class ArrayList;404};405406Iterator iterator() const { return Iterator(this); }407408void clear()409{410data.clear();411ids.clear(true);412size = 0;413}414415private:416DynArray data;417Stack ids;418unsigned int size;419};420421class Interval422{423public:424Interval() : head(0), tail(0) { }425Interval(const Interval&);426~Interval();427428bool extend(int, int);429void insert(const Interval&);430void unify(Interval&); // clears source interval431void clear();432433inline int begin() const { return head ? head->bgn : -1; }434inline int end() const { checkTail(); return tail ? tail->end : -1; }435inline bool isEmpty() const { return !head; }436bool overlaps(const Interval&) const;437bool contains(int pos) const;438439inline int extent() const { return end() - begin(); }440int length() const;441442void print() const;443444inline void checkTail() const;445446private:447class Range448{449public:450Range(int a, int b) : next(0), bgn(a), end(b) { }451452Range *next;453int bgn;454int end;455456void coalesce(Range **ptail)457{458Range *rnn;459460while (next && end >= next->bgn) {461assert(bgn <= next->bgn);462rnn = next->next;463end = MAX2(end, next->end);464delete next;465next = rnn;466}467if (!next)468*ptail = this;469}470};471472Range *head;473Range *tail;474};475476class BitSet477{478public:479BitSet() : marker(false), data(0), size(0) { }480BitSet(unsigned int nBits, bool zero) : marker(false), data(0), size(0)481{482allocate(nBits, zero);483}484~BitSet()485{486if (data)487FREE(data);488}489490// allocate will keep old data iff size is unchanged491bool allocate(unsigned int nBits, bool zero);492bool resize(unsigned int nBits); // keep old data, zero additional bits493494inline unsigned int getSize() const { return size; }495496void fill(uint32_t val);497498void setOr(BitSet *, BitSet *); // second BitSet may be NULL499500inline void set(unsigned int i)501{502assert(i < size);503data[i / 32] |= 1 << (i % 32);504}505// NOTE: range may not cross 32 bit boundary (implies n <= 32)506inline void setRange(unsigned int i, unsigned int n)507{508assert((i + n) <= size && (((i % 32) + n) <= 32));509data[i / 32] |= ((1 << n) - 1) << (i % 32);510}511inline void setMask(unsigned int i, uint32_t m)512{513assert(i < size);514data[i / 32] |= m;515}516517inline void clr(unsigned int i)518{519assert(i < size);520data[i / 32] &= ~(1 << (i % 32));521}522// NOTE: range may not cross 32 bit boundary (implies n <= 32)523inline void clrRange(unsigned int i, unsigned int n)524{525assert((i + n) <= size && (((i % 32) + n) <= 32));526data[i / 32] &= ~(((1 << n) - 1) << (i % 32));527}528529inline bool test(unsigned int i) const530{531assert(i < size);532return data[i / 32] & (1 << (i % 32));533}534// NOTE: range may not cross 32 bit boundary (implies n <= 32)535inline bool testRange(unsigned int i, unsigned int n) const536{537assert((i + n) <= size && (((i % 32) + n) <= 32));538return data[i / 32] & (((1 << n) - 1) << (i % 32));539}540541// Find a range of count (<= 32) clear bits aligned to roundup_pow2(count).542int findFreeRange(unsigned int count, unsigned int max) const;543inline int findFreeRange(unsigned int count) const {544return findFreeRange(count, size);545}546547BitSet& operator|=(const BitSet&);548549BitSet& operator=(const BitSet& set)550{551assert(data && set.data);552assert(size == set.size);553memcpy(data, set.data, (set.size + 7) / 8);554return *this;555}556557void andNot(const BitSet&);558559// bits = (bits | setMask) & ~clrMask560inline void periodicMask32(uint32_t setMask, uint32_t clrMask)561{562for (unsigned int i = 0; i < (size + 31) / 32; ++i)563data[i] = (data[i] | setMask) & ~clrMask;564}565566unsigned int popCount() const;567568void print() const;569570public:571bool marker; // for user572573private:574uint32_t *data;575unsigned int size;576};577578void Interval::checkTail() const579{580#if NV50_DEBUG & NV50_DEBUG_PROG_RA581Range *r = head;582while (r->next)583r = r->next;584assert(tail == r);585#endif586}587588class MemoryPool589{590private:591inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)592{593const unsigned int size = sizeof(uint8_t *) * id;594const unsigned int incr = sizeof(uint8_t *) * nr;595596uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);597if (!alloc)598return false;599allocArray = alloc;600return true;601}602603inline bool enlargeCapacity()604{605const unsigned int id = count >> objStepLog2;606607uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);608if (!mem)609return false;610611if (!(id % 32)) {612if (!enlargeAllocationsArray(id, 32)) {613FREE(mem);614return false;615}616}617allocArray[id] = mem;618return true;619}620621public:622MemoryPool(unsigned int size, unsigned int incr) : objSize(size),623objStepLog2(incr)624{625allocArray = NULL;626released = NULL;627count = 0;628}629630~MemoryPool()631{632unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;633for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)634FREE(allocArray[i]);635if (allocArray)636FREE(allocArray);637}638639void *allocate()640{641void *ret;642const unsigned int mask = (1 << objStepLog2) - 1;643644if (released) {645ret = released;646released = *(void **)released;647return ret;648}649650if (!(count & mask))651if (!enlargeCapacity())652return NULL;653654ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;655++count;656return ret;657}658659void release(void *ptr)660{661*(void **)ptr = released;662released = ptr;663}664665private:666uint8_t **allocArray; // array (list) of MALLOC allocations667668void *released; // list of released objects669670unsigned int count; // highest allocated object671672const unsigned int objSize;673const unsigned int objStepLog2;674};675676/**677* Composite object cloning policy.678*679* Encapsulates how sub-objects are to be handled (if at all) when a680* composite object is being cloned.681*/682template<typename C>683class ClonePolicy684{685protected:686C *c;687688public:689ClonePolicy(C *c) : c(c) {}690691C *context() { return c; }692693template<typename T> T *get(T *obj)694{695void *clone = lookup(obj);696if (!clone)697clone = obj->clone(*this);698return reinterpret_cast<T *>(clone);699}700701template<typename T> void set(const T *obj, T *clone)702{703insert(obj, clone);704}705706protected:707virtual void *lookup(void *obj) = 0;708virtual void insert(const void *obj, void *clone) = 0;709};710711/**712* Shallow non-recursive cloning policy.713*714* Objects cloned with the "shallow" policy don't clone their715* children recursively, instead, the new copy shares its children716* with the original object.717*/718template<typename C>719class ShallowClonePolicy : public ClonePolicy<C>720{721public:722ShallowClonePolicy(C *c) : ClonePolicy<C>(c) {}723724protected:725virtual void *lookup(void *obj)726{727return obj;728}729730virtual void insert(const void *obj, void *clone)731{732}733};734735template<typename C, typename T>736inline T *cloneShallow(C *c, T *obj)737{738ShallowClonePolicy<C> pol(c);739return obj->clone(pol);740}741742/**743* Recursive cloning policy.744*745* Objects cloned with the "deep" policy clone their children746* recursively, keeping track of what has already been cloned to747* avoid making several new copies of the same object.748*/749template<typename C>750class DeepClonePolicy : public ClonePolicy<C>751{752public:753DeepClonePolicy(C *c) : ClonePolicy<C>(c) {}754755private:756std::map<const void *, void *> map;757758protected:759virtual void *lookup(void *obj)760{761return map[obj];762}763764virtual void insert(const void *obj, void *clone)765{766map[obj] = clone;767}768};769770template<typename S, typename T>771struct bimap772{773std::map<S, T> forth;774std::map<T, S> back;775776public:777bimap() : l(back), r(forth) { }778bimap(const bimap<S, T> &m)779: forth(m.forth), back(m.back), l(back), r(forth) { }780781void insert(const S &s, const T &t)782{783forth.insert(std::make_pair(s, t));784back.insert(std::make_pair(t, s));785}786787typedef typename std::map<T, S>::const_iterator l_iterator;788const std::map<T, S> &l;789typedef typename std::map<S, T>::const_iterator r_iterator;790const std::map<S, T> &r;791};792793} // namespace nv50_ir794795#endif // __NV50_IR_UTIL_H__796797798