Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h
4574 views
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 count (<= 32) clear bits aligned to roundup_pow2(count).
543
int findFreeRange(unsigned int count, unsigned int max) const;
544
inline int findFreeRange(unsigned int count) const {
545
return findFreeRange(count, size);
546
}
547
548
BitSet& operator|=(const BitSet&);
549
550
BitSet& operator=(const BitSet& set)
551
{
552
assert(data && set.data);
553
assert(size == set.size);
554
memcpy(data, set.data, (set.size + 7) / 8);
555
return *this;
556
}
557
558
void andNot(const BitSet&);
559
560
// bits = (bits | setMask) & ~clrMask
561
inline void periodicMask32(uint32_t setMask, uint32_t clrMask)
562
{
563
for (unsigned int i = 0; i < (size + 31) / 32; ++i)
564
data[i] = (data[i] | setMask) & ~clrMask;
565
}
566
567
unsigned int popCount() const;
568
569
void print() const;
570
571
public:
572
bool marker; // for user
573
574
private:
575
uint32_t *data;
576
unsigned int size;
577
};
578
579
void Interval::checkTail() const
580
{
581
#if NV50_DEBUG & NV50_DEBUG_PROG_RA
582
Range *r = head;
583
while (r->next)
584
r = r->next;
585
assert(tail == r);
586
#endif
587
}
588
589
class MemoryPool
590
{
591
private:
592
inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)
593
{
594
const unsigned int size = sizeof(uint8_t *) * id;
595
const unsigned int incr = sizeof(uint8_t *) * nr;
596
597
uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);
598
if (!alloc)
599
return false;
600
allocArray = alloc;
601
return true;
602
}
603
604
inline bool enlargeCapacity()
605
{
606
const unsigned int id = count >> objStepLog2;
607
608
uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);
609
if (!mem)
610
return false;
611
612
if (!(id % 32)) {
613
if (!enlargeAllocationsArray(id, 32)) {
614
FREE(mem);
615
return false;
616
}
617
}
618
allocArray[id] = mem;
619
return true;
620
}
621
622
public:
623
MemoryPool(unsigned int size, unsigned int incr) : objSize(size),
624
objStepLog2(incr)
625
{
626
allocArray = NULL;
627
released = NULL;
628
count = 0;
629
}
630
631
~MemoryPool()
632
{
633
unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;
634
for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)
635
FREE(allocArray[i]);
636
if (allocArray)
637
FREE(allocArray);
638
}
639
640
void *allocate()
641
{
642
void *ret;
643
const unsigned int mask = (1 << objStepLog2) - 1;
644
645
if (released) {
646
ret = released;
647
released = *(void **)released;
648
return ret;
649
}
650
651
if (!(count & mask))
652
if (!enlargeCapacity())
653
return NULL;
654
655
ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;
656
++count;
657
return ret;
658
}
659
660
void release(void *ptr)
661
{
662
*(void **)ptr = released;
663
released = ptr;
664
}
665
666
private:
667
uint8_t **allocArray; // array (list) of MALLOC allocations
668
669
void *released; // list of released objects
670
671
unsigned int count; // highest allocated object
672
673
const unsigned int objSize;
674
const unsigned int objStepLog2;
675
};
676
677
/**
678
* Composite object cloning policy.
679
*
680
* Encapsulates how sub-objects are to be handled (if at all) when a
681
* composite object is being cloned.
682
*/
683
template<typename C>
684
class ClonePolicy
685
{
686
protected:
687
C *c;
688
689
public:
690
ClonePolicy(C *c) : c(c) {}
691
692
C *context() { return c; }
693
694
template<typename T> T *get(T *obj)
695
{
696
void *clone = lookup(obj);
697
if (!clone)
698
clone = obj->clone(*this);
699
return reinterpret_cast<T *>(clone);
700
}
701
702
template<typename T> void set(const T *obj, T *clone)
703
{
704
insert(obj, clone);
705
}
706
707
protected:
708
virtual void *lookup(void *obj) = 0;
709
virtual void insert(const void *obj, void *clone) = 0;
710
};
711
712
/**
713
* Shallow non-recursive cloning policy.
714
*
715
* Objects cloned with the "shallow" policy don't clone their
716
* children recursively, instead, the new copy shares its children
717
* with the original object.
718
*/
719
template<typename C>
720
class ShallowClonePolicy : public ClonePolicy<C>
721
{
722
public:
723
ShallowClonePolicy(C *c) : ClonePolicy<C>(c) {}
724
725
protected:
726
virtual void *lookup(void *obj)
727
{
728
return obj;
729
}
730
731
virtual void insert(const void *obj, void *clone)
732
{
733
}
734
};
735
736
template<typename C, typename T>
737
inline T *cloneShallow(C *c, T *obj)
738
{
739
ShallowClonePolicy<C> pol(c);
740
return obj->clone(pol);
741
}
742
743
/**
744
* Recursive cloning policy.
745
*
746
* Objects cloned with the "deep" policy clone their children
747
* recursively, keeping track of what has already been cloned to
748
* avoid making several new copies of the same object.
749
*/
750
template<typename C>
751
class DeepClonePolicy : public ClonePolicy<C>
752
{
753
public:
754
DeepClonePolicy(C *c) : ClonePolicy<C>(c) {}
755
756
private:
757
std::map<const void *, void *> map;
758
759
protected:
760
virtual void *lookup(void *obj)
761
{
762
return map[obj];
763
}
764
765
virtual void insert(const void *obj, void *clone)
766
{
767
map[obj] = clone;
768
}
769
};
770
771
template<typename S, typename T>
772
struct bimap
773
{
774
std::map<S, T> forth;
775
std::map<T, S> back;
776
777
public:
778
bimap() : l(back), r(forth) { }
779
bimap(const bimap<S, T> &m)
780
: forth(m.forth), back(m.back), l(back), r(forth) { }
781
782
void insert(const S &s, const T &t)
783
{
784
forth.insert(std::make_pair(s, t));
785
back.insert(std::make_pair(t, s));
786
}
787
788
typedef typename std::map<T, S>::const_iterator l_iterator;
789
const std::map<T, S> &l;
790
typedef typename std::map<S, T>::const_iterator r_iterator;
791
const std::map<S, T> &r;
792
};
793
794
} // namespace nv50_ir
795
796
#endif // __NV50_IR_UTIL_H__
797
798