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