1 /*
2 * Copyright © 2024 Imagination Technologies Ltd.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 /**
8 * \file pco_const_imms.c
9 *
10 * \brief PCO constant immediates lowering pass.
11 */
12
13 #include "pco.h"
14 #include "pco_builder.h"
15 #include "pco_internal.h"
16 #include "util/macros.h"
17
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21
22 /** Mapping of constant register values and their indices. */
23 struct const_reg_def {
24 uint32_t val;
25 uint8_t idx;
26 bool flr : 1;
27 bool neg : 1;
28 };
29
30 /** Constant register values (sorted for bsearch). */
31 static const struct const_reg_def const_reg_defs[] = {
32 { 0x00000000, 0, false, false }, { 0x00000001, 1, false, false },
33 { 0x00000002, 2, false, false }, { 0x00000003, 3, false, false },
34 { 0x00000004, 4, false, false }, { 0x00000005, 5, false, false },
35 { 0x00000006, 6, false, false }, { 0x00000007, 7, false, false },
36 { 0x00000008, 8, false, false }, { 0x00000009, 9, false, false },
37 { 0x0000000a, 10, false, false }, { 0x0000000b, 11, false, false },
38 { 0x0000000c, 12, false, false }, { 0x0000000d, 13, false, false },
39 { 0x0000000e, 14, false, false }, { 0x0000000f, 15, false, false },
40 { 0x00000010, 16, false, false }, { 0x00000011, 17, false, false },
41 { 0x00000012, 18, false, false }, { 0x00000013, 19, false, false },
42 { 0x00000014, 20, false, false }, { 0x00000015, 21, false, false },
43 { 0x00000016, 22, false, false }, { 0x00000017, 23, false, false },
44 { 0x00000018, 24, false, false }, { 0x00000019, 25, false, false },
45 { 0x0000001a, 26, false, false }, { 0x0000001b, 27, false, false },
46 { 0x0000001c, 28, false, false }, { 0x0000001d, 29, false, false },
47 { 0x0000001e, 30, false, false }, { 0x0000001f, 31, false, false },
48 { 0x0000007f, 147, false, false }, { 0x37800000, 134, false, false },
49 { 0x38000000, 135, false, false }, { 0x38800000, 88, false, false },
50 { 0x39000000, 87, false, false }, { 0x39800000, 86, false, false },
51 { 0x3a000000, 85, false, false }, { 0x3a800000, 84, false, false },
52 { 0x3b000000, 83, false, false }, { 0x3b4d2e1c, 136, false, false },
53 { 0x3b800000, 82, false, false }, { 0x3c000000, 81, false, false },
54 { 0x3c800000, 80, false, false }, { 0x3d000000, 79, false, false },
55 { 0x3d25aee6, 156, false, false }, { 0x3d6147ae, 140, false, false },
56 { 0x3d800000, 78, false, false }, { 0x3d9e8391, 157, false, false },
57 { 0x3e000000, 77, false, false }, { 0x3e2aaaab, 153, false, false },
58 { 0x3e800000, 76, false, false }, { 0x3e9a209b, 145, false, false },
59 { 0x3ea2f983, 128, false, false }, { 0x3eaaaaab, 152, false, false },
60 { 0x3ebc5ab2, 90, false, false }, { 0x3ed55555, 138, false, false },
61 { 0x3f000000, 75, false, false }, { 0x3f22f983, 129, false, false },
62 { 0x3f317218, 146, false, false }, { 0x3f3504f3, 92, false, false },
63 { 0x3f490fdb, 93, false, false }, { 0x3f72a76f, 158, false, false },
64 { 0x3f800000, 64, false, false }, { 0x3f860a92, 151, false, false },
65 { 0x3f870a3d, 139, false, false }, { 0x3fa2f983, 130, false, false },
66 { 0x3fb504f3, 91, false, false }, { 0x3fb8aa3b, 155, false, false },
67 { 0x3fc90fdb, 94, false, false }, { 0x40000000, 65, false, false },
68 { 0x4019999a, 159, false, false }, { 0x402df854, 89, false, false },
69 { 0x40400000, 95, true, false }, { 0x40490fdb, 95, false, false },
70 { 0x40549a78, 154, false, false }, { 0x40800000, 66, false, false },
71 { 0x40c00000, 131, true, false }, { 0x40c90fdb, 131, false, false },
72 { 0x41000000, 67, false, false }, { 0x41400000, 132, true, false },
73 { 0x41490fdb, 132, false, false }, { 0x414eb852, 137, false, false },
74 { 0x41800000, 68, false, false }, { 0x41c80000, 133, true, false },
75 { 0x41c90fdb, 133, false, false }, { 0x42000000, 69, false, false },
76 { 0x42800000, 70, false, false }, { 0x43000000, 71, false, false },
77 { 0x43800000, 72, false, false }, { 0x44000000, 73, false, false },
78 { 0x44800000, 74, false, false }, { 0x4b000000, 149, false, false },
79 { 0x4b800000, 150, false, false }, { 0x7f7fffff, 148, false, false },
80 { 0x7f800000, 142, false, false }, { 0x7fff7fff, 144, false, false },
81 { 0x7fffffff, 143, false, true }, { 0x80000000, 141, false, false },
82 { 0x80000001, 1, false, true }, { 0x80000002, 2, false, true },
83 { 0x80000003, 3, false, true }, { 0x80000004, 4, false, true },
84 { 0x80000005, 5, false, true }, { 0x80000006, 6, false, true },
85 { 0x80000007, 7, false, true }, { 0x80000008, 8, false, true },
86 { 0x80000009, 9, false, true }, { 0x8000000a, 10, false, true },
87 { 0x8000000b, 11, false, true }, { 0x8000000c, 12, false, true },
88 { 0x8000000d, 13, false, true }, { 0x8000000e, 14, false, true },
89 { 0x8000000f, 15, false, true }, { 0x80000010, 16, false, true },
90 { 0x80000011, 17, false, true }, { 0x80000012, 18, false, true },
91 { 0x80000013, 19, false, true }, { 0x80000014, 20, false, true },
92 { 0x80000015, 21, false, true }, { 0x80000016, 22, false, true },
93 { 0x80000017, 23, false, true }, { 0x80000018, 24, false, true },
94 { 0x80000019, 25, false, true }, { 0x8000001a, 26, false, true },
95 { 0x8000001b, 27, false, true }, { 0x8000001c, 28, false, true },
96 { 0x8000001d, 29, false, true }, { 0x8000001e, 30, false, true },
97 { 0x8000001f, 31, false, true }, { 0x8000007f, 147, false, true },
98 { 0xb7800000, 134, false, true }, { 0xb8000000, 135, false, true },
99 { 0xb8800000, 88, false, true }, { 0xb9000000, 87, false, true },
100 { 0xb9800000, 86, false, true }, { 0xba000000, 85, false, true },
101 { 0xba800000, 84, false, true }, { 0xbb000000, 83, false, true },
102 { 0xbb4d2e1c, 136, false, true }, { 0xbb800000, 82, false, true },
103 { 0xbc000000, 81, false, true }, { 0xbc800000, 80, false, true },
104 { 0xbd000000, 79, false, true }, { 0xbd25aee6, 156, false, true },
105 { 0xbd6147ae, 140, false, true }, { 0xbd800000, 78, false, true },
106 { 0xbd9e8391, 157, false, true }, { 0xbe000000, 77, false, true },
107 { 0xbe2aaaab, 153, false, true }, { 0xbe800000, 76, false, true },
108 { 0xbe9a209b, 145, false, true }, { 0xbea2f983, 128, false, true },
109 { 0xbeaaaaab, 152, false, true }, { 0xbebc5ab2, 90, false, true },
110 { 0xbed55555, 138, false, true }, { 0xbf000000, 75, false, true },
111 { 0xbf22f983, 129, false, true }, { 0xbf317218, 146, false, true },
112 { 0xbf3504f3, 92, false, true }, { 0xbf490fdb, 93, false, true },
113 { 0xbf72a76f, 158, false, true }, { 0xbf800000, 64, false, true },
114 { 0xbf860a92, 151, false, true }, { 0xbf870a3d, 139, false, true },
115 { 0xbfa2f983, 130, false, true }, { 0xbfb504f3, 91, false, true },
116 { 0xbfb8aa3b, 155, false, true }, { 0xbfc90fdb, 94, false, true },
117 { 0xc0000000, 65, false, true }, { 0xc019999a, 159, false, true },
118 { 0xc02df854, 89, false, true }, { 0xc0400000, 95, true, true },
119 { 0xc0490fdb, 95, false, true }, { 0xc0549a78, 154, false, true },
120 { 0xc0800000, 66, false, true }, { 0xc0c00000, 131, true, true },
121 { 0xc0c90fdb, 131, false, true }, { 0xc1000000, 67, false, true },
122 { 0xc1400000, 132, true, true }, { 0xc1490fdb, 132, false, true },
123 { 0xc14eb852, 137, false, true }, { 0xc1800000, 68, false, true },
124 { 0xc1c80000, 133, true, true }, { 0xc1c90fdb, 133, false, true },
125 { 0xc2000000, 69, false, true }, { 0xc2800000, 70, false, true },
126 { 0xc3000000, 71, false, true }, { 0xc3800000, 72, false, true },
127 { 0xc4000000, 73, false, true }, { 0xc4800000, 74, false, true },
128 { 0xcb000000, 149, false, true }, { 0xcb800000, 150, false, true },
129 { 0xff7fffff, 148, false, true }, { 0xff800000, 142, false, true },
130 { 0xffff7fff, 144, false, true }, { 0xffffffff, 143, false, false },
131 };
132
133 /**
134 * \brief Comparison function for bsearch() to support rogue_const_reg_def.
135 *
136 * \param[in] lhs The left hand side of the comparison.
137 * \param[in] rhs The right hand side of the comparison.
138 * \return 0 if (lhs == rhs), -1 if (lhs < rhs), 1 if (lhs > rhs).
139 */
constreg_cmp(const void * lhs,const void * rhs)140 static int constreg_cmp(const void *lhs, const void *rhs)
141 {
142 const struct const_reg_def *l = lhs;
143 const struct const_reg_def *r = rhs;
144
145 if (l->val < r->val)
146 return -1;
147 else if (l->val > r->val)
148 return 1;
149
150 return 0;
151 }
152
153 /**
154 * \brief Looks up an immediate in constant registers.
155 *
156 * \param[in] imm The immediate to lookup.
157 * \return A pointer to the constant register definition,
158 * or NULL if no constant register was found.
159 */
constreg_lookup(uint32_t imm)160 inline static const struct const_reg_def *constreg_lookup(uint32_t imm)
161 {
162 return bsearch(&(struct const_reg_def){ .val = imm },
163 const_reg_defs,
164 ARRAY_SIZE(const_reg_defs),
165 sizeof(*const_reg_defs),
166 constreg_cmp);
167 }
168
169 /**
170 * \brief Converts immediates into constant register lookups where possible.
171 *
172 * \param[in,out] shader PCO shader.
173 * \return True if the pass made progress.
174 */
pco_const_imms(pco_shader * shader)175 bool pco_const_imms(pco_shader *shader)
176 {
177 bool progress = false;
178
179 pco_foreach_func_in_shader (func, shader) {
180 pco_foreach_instr_in_func_safe (instr, func) {
181 if (instr->op != PCO_OP_MOVI32)
182 continue;
183
184 const struct const_reg_def *const_reg_def =
185 constreg_lookup(pco_ref_get_imm(instr->src[0]));
186
187 if (!const_reg_def)
188 continue;
189
190 pco_builder b =
191 pco_builder_create(func, pco_cursor_before_instr(instr));
192
193 pco_ref dest = instr->dest[0];
194 pco_ref const_reg =
195 pco_ref_hwreg(const_reg_def->idx, PCO_REG_CLASS_CONST);
196
197 if (!const_reg_def->flr && !const_reg_def->neg) {
198 pco_mov(&b, dest, const_reg);
199 } else if (!const_reg_def->flr && const_reg_def->neg) {
200 pco_neg(&b, dest, const_reg);
201 } else if (const_reg_def->flr && !const_reg_def->neg) {
202 pco_flr(&b, dest, const_reg);
203 } else {
204 /* TODO: use floor and neg mods when support for > 1 is added. */
205 const_reg = pco_ref_flr(const_reg);
206 const_reg = pco_ref_neg(const_reg);
207
208 pco_fadd(&b, dest, const_reg, pco_zero);
209 }
210
211 pco_instr_delete(instr);
212 progress = true;
213 }
214 }
215
216 return progress;
217 }
218