nv50_ir_util.h revision d2d19ea51fa3575a8d014a69a9b835c335728817
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
30#include "util/u_inlines.h"
31#include "util/u_memory.h"
32
33#define ERROR(args...) debug_printf("ERROR: " args)
34#define WARN(args...) debug_printf("WARNING: " args)
35#define INFO(args...) debug_printf(args)
36
37#define INFO_DBG(m, f, args...)          \
38   do {                                  \
39      if (m & NV50_IR_DEBUG_##f)         \
40         debug_printf(args);             \
41   } while(0)
42
43#define FATAL(args...)          \
44   do {                         \
45      fprintf(stderr, args);    \
46      abort();                  \
47   } while(0)
48
49
50#define NV50_IR_FUNC_ALLOC_OBJ_DEF(obj, f, args...)               \
51   new ((f)->getProgram()->mem_##obj.allocate()) obj(f, args)
52
53#define new_Instruction(f, args...)                      \
54   NV50_IR_FUNC_ALLOC_OBJ_DEF(Instruction, f, args)
55#define new_CmpInstruction(f, args...)                   \
56   NV50_IR_FUNC_ALLOC_OBJ_DEF(CmpInstruction, f, args)
57#define new_TexInstruction(f, args...)                   \
58   NV50_IR_FUNC_ALLOC_OBJ_DEF(TexInstruction, f, args)
59#define new_FlowInstruction(f, args...)                  \
60   NV50_IR_FUNC_ALLOC_OBJ_DEF(FlowInstruction, f, args)
61
62#define new_LValue(f, args...)                  \
63   NV50_IR_FUNC_ALLOC_OBJ_DEF(LValue, f, args)
64
65
66#define NV50_IR_PROG_ALLOC_OBJ_DEF(obj, p, args...)   \
67   new ((p)->mem_##obj.allocate()) obj(p, args)
68
69#define new_Symbol(p, args...)                           \
70   NV50_IR_PROG_ALLOC_OBJ_DEF(Symbol, p, args)
71#define new_ImmediateValue(p, args...)                   \
72   NV50_IR_PROG_ALLOC_OBJ_DEF(ImmediateValue, p, args)
73
74
75#define delete_Instruction(p, insn) (p)->releaseInstruction(insn)
76#define delete_Value(p, val) (p)->releaseValue(val)
77
78
79namespace nv50_ir {
80
81class Iterator
82{
83public:
84   virtual void next() = 0;
85   virtual void *get() const = 0;
86   virtual bool end() const = 0; // if true, get will return 0
87};
88
89class ManipIterator : public Iterator
90{
91public:
92   virtual bool insert(void *) = 0; // insert after current position
93   virtual void erase() = 0;
94};
95
96// WARNING: do not use a->prev/next for __item or __list
97
98#define DLLIST_DEL(__item)                      \
99   do {                                         \
100      (__item)->prev->next = (__item)->next;    \
101      (__item)->next->prev = (__item)->prev;    \
102      (__item)->next = (__item);                \
103      (__item)->prev = (__item);                \
104   } while(0)
105
106#define DLLIST_ADDTAIL(__list, __item)          \
107   do {                                         \
108      (__item)->next = (__list);                \
109      (__item)->prev = (__list)->prev;          \
110      (__list)->prev->next = (__item);          \
111      (__list)->prev = (__item);                \
112   } while(0)
113
114#define DLLIST_ADDHEAD(__list, __item)          \
115   do {                                         \
116      (__item)->prev = (__list);                \
117      (__item)->next = (__list)->next;          \
118      (__list)->next->prev = (__item);          \
119      (__list)->next = (__item);                \
120   } while(0)
121
122#define DLLIST_MERGE(__listA, __listB, ty)      \
123   do {                                         \
124      ty prevB = (__listB)->prev;               \
125      (__listA)->prev->next = (__listB);        \
126      (__listB)->prev->next = (__listA);        \
127      (__listB)->prev = (__listA)->prev;        \
128      (__listA)->prev = prevB;                  \
129   } while(0)
130
131#define DLLIST_FOR_EACH(list, it) \
132   for (DLList::Iterator (it) = (list)->iterator(); !(it).end(); (it).next())
133
134class DLList
135{
136public:
137   class Item
138   {
139   public:
140      Item(void *priv) : next(this), prev(this), data(priv) { }
141
142   public:
143      Item *next;
144      Item *prev;
145      void *data;
146   };
147
148   DLList() : head(0) { }
149   ~DLList() { clear(); }
150
151   inline void insertHead(void *data)
152   {
153      Item *item = new Item(data);
154
155      assert(data);
156
157      item->prev = &head;
158      item->next = head.next;
159      head.next->prev = item;
160      head.next = item;
161   }
162
163   inline void insertTail(void *data)
164   {
165      Item *item = new Item(data);
166
167      assert(data);
168
169      DLLIST_ADDTAIL(&head, item);
170   }
171
172   inline void insert(void *data) { insertTail(data); }
173
174   void clear();
175
176   class Iterator : public ManipIterator
177   {
178   public:
179      Iterator(Item *head, bool r) : rev(r), pos(r ? head->prev : head->next),
180                                     term(head) { }
181
182      virtual void next() { if (!end()) pos = rev ? pos->prev : pos->next; }
183      virtual void *get() const { return pos->data; }
184      virtual bool end() const { return pos == term; }
185
186      // caution: if you're at end-2 and erase it, then do next, you're at end
187      virtual void erase();
188      virtual bool insert(void *data);
189
190      // move item to a another list, no consistency with its iterators though
191      void moveToList(DLList&);
192
193   private:
194      const bool rev;
195      Item *pos;
196      Item *term;
197
198      friend class DLList;
199   };
200
201   inline void erase(Iterator& pos)
202   {
203      pos.erase();
204   }
205
206   Iterator iterator()
207   {
208      return Iterator(&head, false);
209   }
210
211   Iterator revIterator()
212   {
213      return Iterator(&head, true);
214   }
215
216private:
217   Item head;
218};
219
220class Stack
221{
222public:
223   class Item {
224   public:
225      union {
226         void *p;
227         int i;
228         unsigned int u;
229         float f;
230         double d;
231      } u;
232
233      Item() { memset(&u, 0, sizeof(u)); }
234   };
235
236   Stack() : size(0), limit(0), array(0) { }
237   ~Stack() { if (array) FREE(array); }
238
239   inline void push(int i)          { Item data; data.u.i = i; push(data); }
240   inline void push(unsigned int u) { Item data; data.u.u = u; push(data); }
241   inline void push(void *p)        { Item data; data.u.p = p; push(data); }
242   inline void push(float f)        { Item data; data.u.f = f; push(data); }
243
244   inline void push(Item data)
245   {
246      if (size == limit)
247         resize();
248      array[size++] = data;
249   }
250
251   inline Item pop()
252   {
253      if (!size) {
254         Item data;
255         assert(0);
256         return data;
257      }
258      return array[--size];
259   }
260
261   inline unsigned int getSize() { return size; }
262
263   inline Item& peek() { assert(size); return array[size - 1]; }
264
265   void clear(bool releaseStorage = false)
266   {
267      if (releaseStorage && array)
268         FREE(array);
269      size = limit = 0;
270   }
271
272   void moveTo(Stack&); // move all items to target (not like push(pop()))
273
274private:
275   void resize()
276   {
277         unsigned int sizeOld, sizeNew;
278
279         sizeOld = limit * sizeof(Item);
280         limit = MAX2(4, limit + limit);
281         sizeNew = limit * sizeof(Item);
282
283         array = (Item *)REALLOC(array, sizeOld, sizeNew);
284   }
285
286   unsigned int size;
287   unsigned int limit;
288   Item *array;
289};
290
291class DynArray
292{
293public:
294   class Item
295   {
296   public:
297      union {
298         uint32_t u32;
299         void *p;
300      };
301   };
302
303   DynArray() : data(NULL), size(0) { }
304
305   ~DynArray() { if (data) FREE(data); }
306
307   inline Item& operator[](unsigned int i)
308   {
309      if (i >= size)
310         resize(i);
311      return data[i];
312   }
313
314   inline const Item operator[](unsigned int i) const
315   {
316      return data[i];
317   }
318
319   void resize(unsigned int index)
320   {
321      const unsigned int oldSize = size * sizeof(Item);
322
323      if (!size)
324         size = 8;
325      while (size <= index)
326         size <<= 1;
327
328      data = (Item *)REALLOC(data, oldSize, size * sizeof(Item));
329   }
330
331private:
332   Item *data;
333   unsigned int size;
334};
335
336class ArrayList
337{
338public:
339   ArrayList() : size(0) { }
340
341   void insert(void *item, int& id)
342   {
343      id = ids.getSize() ? ids.pop().u.i : size++;
344      data[id].p = item;
345   }
346
347   void remove(int& id)
348   {
349      const unsigned int uid = id;
350      assert(uid < size && data[id].p);
351      ids.push(uid);
352      data[uid].p = NULL;
353      id = -1;
354   }
355
356   inline int getSize() const { return size; }
357
358   inline void *get(unsigned int id) { assert(id < size); return data[id].p; }
359
360   class Iterator : public nv50_ir::Iterator
361   {
362   public:
363      Iterator(const ArrayList *array) : pos(0), data(array->data)
364      {
365         size = array->getSize();
366         if (size)
367            nextValid();
368      }
369
370      void nextValid() { while ((pos < size) && !data[pos].p) ++pos; }
371
372      void next() { if (pos < size) { ++pos; nextValid(); } }
373      void *get() const { assert(pos < size); return data[pos].p; }
374      bool end() const { return pos >= size; }
375
376   private:
377      unsigned int pos;
378      unsigned int size;
379      const DynArray& data;
380
381      friend class ArrayList;
382   };
383
384   Iterator iterator() const { return Iterator(this); }
385
386private:
387   DynArray data;
388   Stack ids;
389   unsigned int size;
390};
391
392class Interval
393{
394public:
395   Interval() : head(0), tail(0) { }
396   ~Interval();
397
398   bool extend(int, int);
399   void unify(Interval&); // clears source interval
400   void clear();
401
402   inline int begin() { return head ? head->bgn : -1; }
403   inline int end() { checkTail(); return tail ? tail->end : -1; }
404   inline bool isEmpty() const { return !head; }
405   bool overlaps(const Interval&) const;
406   bool contains(int pos);
407
408   void print() const;
409
410   inline void checkTail() const;
411
412private:
413   class Range
414   {
415   public:
416      Range(int a, int b) : next(0), bgn(a), end(b) { }
417
418      Range *next;
419      int bgn;
420      int end;
421
422      void coalesce(Range **ptail)
423      {
424         Range *rnn;
425
426         while (next && end >= next->bgn) {
427            assert(bgn <= next->bgn);
428            rnn = next->next;
429            end = MAX2(end, next->end);
430            delete next;
431            next = rnn;
432         }
433         if (!next)
434            *ptail = this;
435      }
436   };
437
438   Range *head;
439   Range *tail;
440};
441
442class BitSet
443{
444public:
445   BitSet() : marker(false), data(0), size(0) { }
446   BitSet(unsigned int nBits, bool zero) : marker(false), data(0), size(0)
447   {
448      allocate(nBits, zero);
449   }
450   ~BitSet()
451   {
452      if (data)
453         FREE(data);
454   }
455
456   bool allocate(unsigned int nBits, bool zero);
457
458   inline unsigned int getSize() const { return size; }
459
460   void fill(uint32_t val);
461
462   void setOr(BitSet *, BitSet *); // second BitSet may be NULL
463
464   inline void set(unsigned int i)
465   {
466      assert(i < size);
467      data[i / 32] |= 1 << (i % 32);
468   }
469
470   inline void clr(unsigned int i)
471   {
472      assert(i < size);
473      data[i / 32] &= ~(1 << (i % 32));
474   }
475
476   inline bool test(unsigned int i) const
477   {
478      assert(i < size);
479      return data[i / 32] & (1 << (i % 32));
480   }
481
482   BitSet& operator|=(const BitSet&);
483
484   BitSet& operator=(const BitSet& set)
485   {
486      assert(data && set.data);
487      assert(size == set.size);
488      memcpy(data, set.data, (set.size + 7) / 8);
489      return *this;
490   }
491
492   void andNot(const BitSet&);
493
494   unsigned int popCount() const;
495
496   void print() const;
497
498public:
499   bool marker; // for user
500
501private:
502   uint32_t *data;
503   unsigned int size;
504};
505
506void Interval::checkTail() const
507{
508#if NV50_DEBUG & NV50_DEBUG_PROG_RA
509   Range *r = head;
510   while (r->next)
511      r = r->next;
512   assert(tail == r);
513#endif
514}
515
516class MemoryPool
517{
518private:
519   inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)
520   {
521      const unsigned int size = sizeof(uint8_t *) * id;
522      const unsigned int incr = sizeof(uint8_t *) * nr;
523
524      uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);
525      if (!alloc)
526         return false;
527      allocArray = alloc;
528      return true;
529   }
530
531   inline bool enlargeCapacity()
532   {
533      const unsigned int id = count >> objStepLog2;
534
535      uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);
536      if (!mem)
537         return false;
538
539      if (!(id % 32)) {
540         if (!enlargeAllocationsArray(id, 32)) {
541            FREE(mem);
542            return false;
543         }
544      }
545      allocArray[id] = mem;
546      return true;
547   }
548
549public:
550   MemoryPool(unsigned int size, unsigned int incr) : objSize(size),
551                                                      objStepLog2(incr)
552   {
553      allocArray = NULL;
554      released = NULL;
555      count = 0;
556   }
557
558   ~MemoryPool()
559   {
560      unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;
561      for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)
562         FREE(allocArray[i]);
563      if (allocArray)
564         FREE(allocArray);
565   }
566
567   void *allocate()
568   {
569      void *ret;
570      const unsigned int mask = (1 << objStepLog2) - 1;
571
572      if (released) {
573         ret = released;
574         released = *(void **)released;
575         return ret;
576      }
577
578      if (!(count & mask))
579         if (!enlargeCapacity())
580            return NULL;
581
582      ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;
583      ++count;
584      return ret;
585   }
586
587   void release(void *ptr)
588   {
589      *(void **)ptr = released;
590      released = ptr;
591   }
592
593private:
594   uint8_t **allocArray; // array (list) of MALLOC allocations
595
596   void *released; // list of released objects
597
598   unsigned int count; // highest allocated object
599
600   const unsigned int objSize;
601   const unsigned int objStepLog2;
602};
603
604} // namespace nv50_ir
605
606#endif // __NV50_IR_UTIL_H__
607