Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright 2011 Christoph Bumiller
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  */
     22 
     23 #ifndef __NV50_IR_UTIL_H__
     24 #define __NV50_IR_UTIL_H__
     25 
     26 #include <new>
     27 #include <assert.h>
     28 #include <stdio.h>
     29 #include <memory>
     30 #include <map>
     31 
     32 #ifndef NDEBUG
     33 # include <typeinfo>
     34 #endif
     35 
     36 #include "util/u_inlines.h"
     37 #include "util/u_memory.h"
     38 
     39 #define ERROR(args...) debug_printf("ERROR: " args)
     40 #define WARN(args...) debug_printf("WARNING: " args)
     41 #define INFO(args...) debug_printf(args)
     42 
     43 #define INFO_DBG(m, f, args...)          \
     44    do {                                  \
     45       if (m & NV50_IR_DEBUG_##f)         \
     46          debug_printf(args);             \
     47    } while(0)
     48 
     49 #define FATAL(args...)          \
     50    do {                         \
     51       fprintf(stderr, args);    \
     52       abort();                  \
     53    } while(0)
     54 
     55 
     56 #define NV50_IR_FUNC_ALLOC_OBJ_DEF(obj, f, args...)               \
     57    new ((f)->getProgram()->mem_##obj.allocate()) obj(f, args)
     58 
     59 #define new_Instruction(f, args...)                      \
     60    NV50_IR_FUNC_ALLOC_OBJ_DEF(Instruction, f, args)
     61 #define new_CmpInstruction(f, args...)                   \
     62    NV50_IR_FUNC_ALLOC_OBJ_DEF(CmpInstruction, f, args)
     63 #define new_TexInstruction(f, args...)                   \
     64    NV50_IR_FUNC_ALLOC_OBJ_DEF(TexInstruction, f, args)
     65 #define new_FlowInstruction(f, args...)                  \
     66    NV50_IR_FUNC_ALLOC_OBJ_DEF(FlowInstruction, f, args)
     67 
     68 #define new_LValue(f, args...)                  \
     69    NV50_IR_FUNC_ALLOC_OBJ_DEF(LValue, f, args)
     70 
     71 
     72 #define NV50_IR_PROG_ALLOC_OBJ_DEF(obj, p, args...)   \
     73    new ((p)->mem_##obj.allocate()) obj(p, args)
     74 
     75 #define new_Symbol(p, args...)                           \
     76    NV50_IR_PROG_ALLOC_OBJ_DEF(Symbol, p, args)
     77 #define new_ImmediateValue(p, args...)                   \
     78    NV50_IR_PROG_ALLOC_OBJ_DEF(ImmediateValue, p, args)
     79 
     80 
     81 #define delete_Instruction(p, insn) (p)->releaseInstruction(insn)
     82 #define delete_Value(p, val) (p)->releaseValue(val)
     83 
     84 
     85 namespace nv50_ir {
     86 
     87 class Iterator
     88 {
     89 public:
     90    virtual ~Iterator() { };
     91    virtual void next() = 0;
     92    virtual void *get() const = 0;
     93    virtual bool end() const = 0; // if true, get will return 0
     94    virtual void reset() { assert(0); } // only for graph iterators
     95 };
     96 
     97 typedef std::auto_ptr<Iterator> IteratorRef;
     98 
     99 class ManipIterator : public Iterator
    100 {
    101 public:
    102    virtual bool insert(void *) = 0; // insert after current position
    103    virtual void erase() = 0;
    104 };
    105 
    106 // WARNING: do not use a->prev/next for __item or __list
    107 
    108 #define DLLIST_DEL(__item)                      \
    109    do {                                         \
    110       (__item)->prev->next = (__item)->next;    \
    111       (__item)->next->prev = (__item)->prev;    \
    112       (__item)->next = (__item);                \
    113       (__item)->prev = (__item);                \
    114    } while(0)
    115 
    116 #define DLLIST_ADDTAIL(__list, __item)          \
    117    do {                                         \
    118       (__item)->next = (__list);                \
    119       (__item)->prev = (__list)->prev;          \
    120       (__list)->prev->next = (__item);          \
    121       (__list)->prev = (__item);                \
    122    } while(0)
    123 
    124 #define DLLIST_ADDHEAD(__list, __item)          \
    125    do {                                         \
    126       (__item)->prev = (__list);                \
    127       (__item)->next = (__list)->next;          \
    128       (__list)->next->prev = (__item);          \
    129       (__list)->next = (__item);                \
    130    } while(0)
    131 
    132 #define DLLIST_MERGE(__listA, __listB, ty)      \
    133    do {                                         \
    134       ty prevB = (__listB)->prev;               \
    135       (__listA)->prev->next = (__listB);        \
    136       (__listB)->prev->next = (__listA);        \
    137       (__listB)->prev = (__listA)->prev;        \
    138       (__listA)->prev = prevB;                  \
    139    } while(0)
    140 
    141 #define DLLIST_EMPTY(__list) ((__list)->next == (__list))
    142 
    143 #define DLLIST_FOR_EACH(list, it) \
    144    for (DLList::Iterator (it) = (list)->iterator(); !(it).end(); (it).next())
    145 
    146 class DLList
    147 {
    148 public:
    149    class Item
    150    {
    151    public:
    152       Item(void *priv) : next(this), prev(this), data(priv) { }
    153 
    154    public:
    155       Item *next;
    156       Item *prev;
    157       void *data;
    158    };
    159 
    160    DLList() : head(0) { }
    161    ~DLList() { clear(); }
    162 
    163    inline void insertHead(void *data)
    164    {
    165       Item *item = new Item(data);
    166 
    167       assert(data);
    168 
    169       item->prev = &head;
    170       item->next = head.next;
    171       head.next->prev = item;
    172       head.next = item;
    173    }
    174 
    175    inline void insertTail(void *data)
    176    {
    177       Item *item = new Item(data);
    178 
    179       assert(data);
    180 
    181       DLLIST_ADDTAIL(&head, item);
    182    }
    183 
    184    inline void insert(void *data) { insertTail(data); }
    185 
    186    void clear();
    187 
    188    class Iterator : public ManipIterator
    189    {
    190    public:
    191       Iterator(Item *head, bool r) : rev(r), pos(r ? head->prev : head->next),
    192                                      term(head) { }
    193 
    194       virtual void next() { if (!end()) pos = rev ? pos->prev : pos->next; }
    195       virtual void *get() const { return pos->data; }
    196       virtual bool end() const { return pos == term; }
    197 
    198       // caution: if you're at end-2 and erase it, then do next, you're at end
    199       virtual void erase();
    200       virtual bool insert(void *data);
    201 
    202       // move item to a another list, no consistency with its iterators though
    203       void moveToList(DLList&);
    204 
    205    private:
    206       const bool rev;
    207       Item *pos;
    208       Item *term;
    209 
    210       friend class DLList;
    211    };
    212 
    213    inline void erase(Iterator& pos)
    214    {
    215       pos.erase();
    216    }
    217 
    218    Iterator iterator()
    219    {
    220       return Iterator(&head, false);
    221    }
    222 
    223    Iterator revIterator()
    224    {
    225       return Iterator(&head, true);
    226    }
    227 
    228 private:
    229    Item head;
    230 };
    231 
    232 class Stack
    233 {
    234 public:
    235    class Item {
    236    public:
    237       union {
    238          void *p;
    239          int i;
    240          unsigned int u;
    241          float f;
    242          double d;
    243       } u;
    244 
    245       Item() { memset(&u, 0, sizeof(u)); }
    246    };
    247 
    248    Stack() : size(0), limit(0), array(0) { }
    249    ~Stack() { if (array) FREE(array); }
    250 
    251    inline void push(int i)          { Item data; data.u.i = i; push(data); }
    252    inline void push(unsigned int u) { Item data; data.u.u = u; push(data); }
    253    inline void push(void *p)        { Item data; data.u.p = p; push(data); }
    254    inline void push(float f)        { Item data; data.u.f = f; push(data); }
    255 
    256    inline void push(Item data)
    257    {
    258       if (size == limit)
    259          resize();
    260       array[size++] = data;
    261    }
    262 
    263    inline Item pop()
    264    {
    265       if (!size) {
    266          Item data;
    267          assert(0);
    268          return data;
    269       }
    270       return array[--size];
    271    }
    272 
    273    inline unsigned int getSize() { return size; }
    274 
    275    inline Item& peek() { assert(size); return array[size - 1]; }
    276 
    277    void clear(bool releaseStorage = false)
    278    {
    279       if (releaseStorage && array)
    280          FREE(array);
    281       size = limit = 0;
    282    }
    283 
    284    void moveTo(Stack&); // move all items to target (not like push(pop()))
    285 
    286 private:
    287    void resize()
    288    {
    289          unsigned int sizeOld, sizeNew;
    290 
    291          sizeOld = limit * sizeof(Item);
    292          limit = MAX2(4, limit + limit);
    293          sizeNew = limit * sizeof(Item);
    294 
    295          array = (Item *)REALLOC(array, sizeOld, sizeNew);
    296    }
    297 
    298    unsigned int size;
    299    unsigned int limit;
    300    Item *array;
    301 };
    302 
    303 class DynArray
    304 {
    305 public:
    306    class Item
    307    {
    308    public:
    309       union {
    310          uint32_t u32;
    311          void *p;
    312       };
    313    };
    314 
    315    DynArray() : data(NULL), size(0) { }
    316 
    317    ~DynArray() { if (data) FREE(data); }
    318 
    319    inline Item& operator[](unsigned int i)
    320    {
    321       if (i >= size)
    322          resize(i);
    323       return data[i];
    324    }
    325 
    326    inline const Item operator[](unsigned int i) const
    327    {
    328       return data[i];
    329    }
    330 
    331    void resize(unsigned int index)
    332    {
    333       const unsigned int oldSize = size * sizeof(Item);
    334 
    335       if (!size)
    336          size = 8;
    337       while (size <= index)
    338          size <<= 1;
    339 
    340       data = (Item *)REALLOC(data, oldSize, size * sizeof(Item));
    341    }
    342 
    343    void clear()
    344    {
    345       FREE(data);
    346       data = NULL;
    347       size = 0;
    348    }
    349 
    350 private:
    351    Item *data;
    352    unsigned int size;
    353 };
    354 
    355 class ArrayList
    356 {
    357 public:
    358    ArrayList() : size(0) { }
    359 
    360    void insert(void *item, int& id)
    361    {
    362       id = ids.getSize() ? ids.pop().u.i : size++;
    363       data[id].p = item;
    364    }
    365 
    366    void remove(int& id)
    367    {
    368       const unsigned int uid = id;
    369       assert(uid < size && data[id].p);
    370       ids.push(uid);
    371       data[uid].p = NULL;
    372       id = -1;
    373    }
    374 
    375    inline int getSize() const { return size; }
    376 
    377    inline void *get(unsigned int id) { assert(id < size); return data[id].p; }
    378 
    379    class Iterator : public nv50_ir::Iterator
    380    {
    381    public:
    382       Iterator(const ArrayList *array) : pos(0), data(array->data)
    383       {
    384          size = array->getSize();
    385          if (size)
    386             nextValid();
    387       }
    388 
    389       void nextValid() { while ((pos < size) && !data[pos].p) ++pos; }
    390 
    391       void next() { if (pos < size) { ++pos; nextValid(); } }
    392       void *get() const { assert(pos < size); return data[pos].p; }
    393       bool end() const { return pos >= size; }
    394 
    395    private:
    396       unsigned int pos;
    397       unsigned int size;
    398       const DynArray& data;
    399 
    400       friend class ArrayList;
    401    };
    402 
    403    Iterator iterator() const { return Iterator(this); }
    404 
    405    void clear()
    406    {
    407       data.clear();
    408       ids.clear(true);
    409       size = 0;
    410    }
    411 
    412 private:
    413    DynArray data;
    414    Stack ids;
    415    unsigned int size;
    416 };
    417 
    418 class Interval
    419 {
    420 public:
    421    Interval() : head(0), tail(0) { }
    422    Interval(const Interval&);
    423    ~Interval();
    424 
    425    bool extend(int, int);
    426    void insert(const Interval&);
    427    void unify(Interval&); // clears source interval
    428    void clear();
    429 
    430    inline int begin() const { return head ? head->bgn : -1; }
    431    inline int end() const { checkTail(); return tail ? tail->end : -1; }
    432    inline bool isEmpty() const { return !head; }
    433    bool overlaps(const Interval&) const;
    434    bool contains(int pos) const;
    435 
    436    inline int extent() const { return end() - begin(); }
    437    int length() const;
    438 
    439    void print() const;
    440 
    441    inline void checkTail() const;
    442 
    443 private:
    444    class Range
    445    {
    446    public:
    447       Range(int a, int b) : next(0), bgn(a), end(b) { }
    448 
    449       Range *next;
    450       int bgn;
    451       int end;
    452 
    453       void coalesce(Range **ptail)
    454       {
    455          Range *rnn;
    456 
    457          while (next && end >= next->bgn) {
    458             assert(bgn <= next->bgn);
    459             rnn = next->next;
    460             end = MAX2(end, next->end);
    461             delete next;
    462             next = rnn;
    463          }
    464          if (!next)
    465             *ptail = this;
    466       }
    467    };
    468 
    469    Range *head;
    470    Range *tail;
    471 };
    472 
    473 class BitSet
    474 {
    475 public:
    476    BitSet() : marker(false), data(0), size(0) { }
    477    BitSet(unsigned int nBits, bool zero) : marker(false), data(0), size(0)
    478    {
    479       allocate(nBits, zero);
    480    }
    481    ~BitSet()
    482    {
    483       if (data)
    484          FREE(data);
    485    }
    486 
    487    bool allocate(unsigned int nBits, bool zero);
    488    bool resize(unsigned int nBits); // keep old data, zero additional bits
    489 
    490    inline unsigned int getSize() const { return size; }
    491 
    492    void fill(uint32_t val);
    493 
    494    void setOr(BitSet *, BitSet *); // second BitSet may be NULL
    495 
    496    inline void set(unsigned int i)
    497    {
    498       assert(i < size);
    499       data[i / 32] |= 1 << (i % 32);
    500    }
    501    // NOTE: range may not cross 32 bit boundary (implies n <= 32)
    502    inline void setRange(unsigned int i, unsigned int n)
    503    {
    504       assert((i + n) <= size && (((i % 32) + n) <= 32));
    505       data[i / 32] |= ((1 << n) - 1) << (i % 32);
    506    }
    507    inline void setMask(unsigned int i, uint32_t m)
    508    {
    509       assert(i < size);
    510       data[i / 32] |= m;
    511    }
    512 
    513    inline void clr(unsigned int i)
    514    {
    515       assert(i < size);
    516       data[i / 32] &= ~(1 << (i % 32));
    517    }
    518    // NOTE: range may not cross 32 bit boundary (implies n <= 32)
    519    inline void clrRange(unsigned int i, unsigned int n)
    520    {
    521       assert((i + n) <= size && (((i % 32) + n) <= 32));
    522       data[i / 32] &= ~(((1 << n) - 1) << (i % 32));
    523    }
    524 
    525    inline bool test(unsigned int i) const
    526    {
    527       assert(i < size);
    528       return data[i / 32] & (1 << (i % 32));
    529    }
    530    // NOTE: range may not cross 32 bit boundary (implies n <= 32)
    531    inline bool testRange(unsigned int i, unsigned int n)
    532    {
    533       assert((i + n) <= size && (((i % 32) + n) <= 32));
    534       return data[i / 32] & (((1 << n) - 1) << (i % 32));
    535    }
    536 
    537    // Find a range of size (<= 32) clear bits aligned to roundup_pow2(size).
    538    int findFreeRange(unsigned int size) const;
    539 
    540    BitSet& operator|=(const BitSet&);
    541 
    542    BitSet& operator=(const BitSet& set)
    543    {
    544       assert(data && set.data);
    545       assert(size == set.size);
    546       memcpy(data, set.data, (set.size + 7) / 8);
    547       return *this;
    548    }
    549 
    550    void andNot(const BitSet&);
    551 
    552    // bits = (bits | setMask) & ~clrMask
    553    inline void periodicMask32(uint32_t setMask, uint32_t clrMask)
    554    {
    555       for (unsigned int i = 0; i < (size + 31) / 32; ++i)
    556          data[i] = (data[i] | setMask) & ~clrMask;
    557    }
    558 
    559    unsigned int popCount() const;
    560 
    561    void print() const;
    562 
    563 public:
    564    bool marker; // for user
    565 
    566 private:
    567    uint32_t *data;
    568    unsigned int size;
    569 };
    570 
    571 void Interval::checkTail() const
    572 {
    573 #if NV50_DEBUG & NV50_DEBUG_PROG_RA
    574    Range *r = head;
    575    while (r->next)
    576       r = r->next;
    577    assert(tail == r);
    578 #endif
    579 }
    580 
    581 class MemoryPool
    582 {
    583 private:
    584    inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)
    585    {
    586       const unsigned int size = sizeof(uint8_t *) * id;
    587       const unsigned int incr = sizeof(uint8_t *) * nr;
    588 
    589       uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);
    590       if (!alloc)
    591          return false;
    592       allocArray = alloc;
    593       return true;
    594    }
    595 
    596    inline bool enlargeCapacity()
    597    {
    598       const unsigned int id = count >> objStepLog2;
    599 
    600       uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);
    601       if (!mem)
    602          return false;
    603 
    604       if (!(id % 32)) {
    605          if (!enlargeAllocationsArray(id, 32)) {
    606             FREE(mem);
    607             return false;
    608          }
    609       }
    610       allocArray[id] = mem;
    611       return true;
    612    }
    613 
    614 public:
    615    MemoryPool(unsigned int size, unsigned int incr) : objSize(size),
    616                                                       objStepLog2(incr)
    617    {
    618       allocArray = NULL;
    619       released = NULL;
    620       count = 0;
    621    }
    622 
    623    ~MemoryPool()
    624    {
    625       unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;
    626       for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)
    627          FREE(allocArray[i]);
    628       if (allocArray)
    629          FREE(allocArray);
    630    }
    631 
    632    void *allocate()
    633    {
    634       void *ret;
    635       const unsigned int mask = (1 << objStepLog2) - 1;
    636 
    637       if (released) {
    638          ret = released;
    639          released = *(void **)released;
    640          return ret;
    641       }
    642 
    643       if (!(count & mask))
    644          if (!enlargeCapacity())
    645             return NULL;
    646 
    647       ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;
    648       ++count;
    649       return ret;
    650    }
    651 
    652    void release(void *ptr)
    653    {
    654       *(void **)ptr = released;
    655       released = ptr;
    656    }
    657 
    658 private:
    659    uint8_t **allocArray; // array (list) of MALLOC allocations
    660 
    661    void *released; // list of released objects
    662 
    663    unsigned int count; // highest allocated object
    664 
    665    const unsigned int objSize;
    666    const unsigned int objStepLog2;
    667 };
    668 
    669 /**
    670  *  Composite object cloning policy.
    671  *
    672  *  Encapsulates how sub-objects are to be handled (if at all) when a
    673  *  composite object is being cloned.
    674  */
    675 template<typename C>
    676 class ClonePolicy
    677 {
    678 protected:
    679    C *c;
    680 
    681 public:
    682    ClonePolicy(C *c) : c(c) {}
    683 
    684    C *context() { return c; }
    685 
    686    template<typename T> T *get(T *obj)
    687    {
    688       void *clone = lookup(obj);
    689       if (!clone)
    690          clone = obj->clone(*this);
    691       return reinterpret_cast<T *>(clone);
    692    }
    693 
    694    template<typename T> void set(const T *obj, T *clone)
    695    {
    696       insert(obj, clone);
    697    }
    698 
    699 protected:
    700    virtual void *lookup(void *obj) = 0;
    701    virtual void insert(const void *obj, void *clone) = 0;
    702 };
    703 
    704 /**
    705  *  Shallow non-recursive cloning policy.
    706  *
    707  *  Objects cloned with the "shallow" policy don't clone their
    708  *  children recursively, instead, the new copy shares its children
    709  *  with the original object.
    710  */
    711 template<typename C>
    712 class ShallowClonePolicy : public ClonePolicy<C>
    713 {
    714 public:
    715    ShallowClonePolicy(C *c) : ClonePolicy<C>(c) {}
    716 
    717 protected:
    718    virtual void *lookup(void *obj)
    719    {
    720       return obj;
    721    }
    722 
    723    virtual void insert(const void *obj, void *clone)
    724    {
    725    }
    726 };
    727 
    728 template<typename C, typename T>
    729 inline T *cloneShallow(C *c, T *obj)
    730 {
    731    ShallowClonePolicy<C> pol(c);
    732    return obj->clone(pol);
    733 }
    734 
    735 /**
    736  *  Recursive cloning policy.
    737  *
    738  *  Objects cloned with the "deep" policy clone their children
    739  *  recursively, keeping track of what has already been cloned to
    740  *  avoid making several new copies of the same object.
    741  */
    742 template<typename C>
    743 class DeepClonePolicy : public ClonePolicy<C>
    744 {
    745 public:
    746    DeepClonePolicy(C *c) : ClonePolicy<C>(c) {}
    747 
    748 private:
    749    std::map<const void *, void *> map;
    750 
    751 protected:
    752    virtual void *lookup(void *obj)
    753    {
    754       return map[obj];
    755    }
    756 
    757    virtual void insert(const void *obj, void *clone)
    758    {
    759       map[obj] = clone;
    760    }
    761 };
    762 
    763 template<typename S, typename T>
    764 struct bimap
    765 {
    766    std::map<S, T> forth;
    767    std::map<T, S> back;
    768 
    769 public:
    770    bimap() : l(back), r(forth) { }
    771    bimap(const bimap<S, T> &m)
    772       : forth(m.forth), back(m.back), l(back), r(forth) { }
    773 
    774    void insert(const S &s, const T &t)
    775    {
    776       forth.insert(std::make_pair(s, t));
    777       back.insert(std::make_pair(t, s));
    778    }
    779 
    780    typedef typename std::map<T, S>::const_iterator l_iterator;
    781    const std::map<T, S> &l;
    782    typedef typename std::map<S, T>::const_iterator r_iterator;
    783    const std::map<S, T> &r;
    784 };
    785 
    786 } // namespace nv50_ir
    787 
    788 #endif // __NV50_IR_UTIL_H__
    789