1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright (C) 2019 Collabora, Ltd.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*61046927SAndroid Build Coastguard Worker * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*61046927SAndroid Build Coastguard Worker * SOFTWARE.
22*61046927SAndroid Build Coastguard Worker *
23*61046927SAndroid Build Coastguard Worker * Authors (Collabora):
24*61046927SAndroid Build Coastguard Worker * Alyssa Rosenzweig <[email protected]>
25*61046927SAndroid Build Coastguard Worker */
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "compiler.h"
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker /* Midgard's generic load/store instructions, particularly to implement SSBOs
30*61046927SAndroid Build Coastguard Worker * and globals, have support for address arithmetic natively. In particularly,
31*61046927SAndroid Build Coastguard Worker * they take two indirect arguments A, B and two immediates #s, #c, calculating
32*61046927SAndroid Build Coastguard Worker * the address:
33*61046927SAndroid Build Coastguard Worker *
34*61046927SAndroid Build Coastguard Worker * A + (zext?(B) << #s) + #c
35*61046927SAndroid Build Coastguard Worker *
36*61046927SAndroid Build Coastguard Worker * This allows for fast indexing into arrays. This file tries to pattern match
37*61046927SAndroid Build Coastguard Worker * the offset in NIR with this form to reduce pressure on the ALU pipe.
38*61046927SAndroid Build Coastguard Worker */
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker struct mir_address {
41*61046927SAndroid Build Coastguard Worker nir_scalar A;
42*61046927SAndroid Build Coastguard Worker nir_scalar B;
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker midgard_index_address_format type;
45*61046927SAndroid Build Coastguard Worker unsigned shift;
46*61046927SAndroid Build Coastguard Worker unsigned bias;
47*61046927SAndroid Build Coastguard Worker };
48*61046927SAndroid Build Coastguard Worker
49*61046927SAndroid Build Coastguard Worker static bool
mir_args_ssa(nir_scalar s,unsigned count)50*61046927SAndroid Build Coastguard Worker mir_args_ssa(nir_scalar s, unsigned count)
51*61046927SAndroid Build Coastguard Worker {
52*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(s.def->parent_instr);
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Worker if (count > nir_op_infos[alu->op].num_inputs)
55*61046927SAndroid Build Coastguard Worker return false;
56*61046927SAndroid Build Coastguard Worker
57*61046927SAndroid Build Coastguard Worker return true;
58*61046927SAndroid Build Coastguard Worker }
59*61046927SAndroid Build Coastguard Worker
60*61046927SAndroid Build Coastguard Worker /* Matches a constant in either slot and moves it to the bias */
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker static void
mir_match_constant(struct mir_address * address)63*61046927SAndroid Build Coastguard Worker mir_match_constant(struct mir_address *address)
64*61046927SAndroid Build Coastguard Worker {
65*61046927SAndroid Build Coastguard Worker if (address->A.def && nir_scalar_is_const(address->A)) {
66*61046927SAndroid Build Coastguard Worker address->bias += nir_scalar_as_uint(address->A);
67*61046927SAndroid Build Coastguard Worker address->A.def = NULL;
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Worker if (address->B.def && nir_scalar_is_const(address->B)) {
71*61046927SAndroid Build Coastguard Worker address->bias += nir_scalar_as_uint(address->B);
72*61046927SAndroid Build Coastguard Worker address->B.def = NULL;
73*61046927SAndroid Build Coastguard Worker }
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker
76*61046927SAndroid Build Coastguard Worker /* Matches an iadd when there is a free slot or constant */
77*61046927SAndroid Build Coastguard Worker
78*61046927SAndroid Build Coastguard Worker /* The offset field is a 18-bit signed integer */
79*61046927SAndroid Build Coastguard Worker #define MAX_POSITIVE_OFFSET ((1 << 17) - 1)
80*61046927SAndroid Build Coastguard Worker
81*61046927SAndroid Build Coastguard Worker static void
mir_match_iadd(struct mir_address * address,bool first_free)82*61046927SAndroid Build Coastguard Worker mir_match_iadd(struct mir_address *address, bool first_free)
83*61046927SAndroid Build Coastguard Worker {
84*61046927SAndroid Build Coastguard Worker if (!address->B.def || !nir_scalar_is_alu(address->B))
85*61046927SAndroid Build Coastguard Worker return;
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker if (!mir_args_ssa(address->B, 2))
88*61046927SAndroid Build Coastguard Worker return;
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->B);
91*61046927SAndroid Build Coastguard Worker
92*61046927SAndroid Build Coastguard Worker if (op != nir_op_iadd)
93*61046927SAndroid Build Coastguard Worker return;
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker nir_scalar op1 = nir_scalar_chase_alu_src(address->B, 0);
96*61046927SAndroid Build Coastguard Worker nir_scalar op2 = nir_scalar_chase_alu_src(address->B, 1);
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker if (nir_scalar_is_const(op1) &&
99*61046927SAndroid Build Coastguard Worker nir_scalar_as_uint(op1) <= MAX_POSITIVE_OFFSET) {
100*61046927SAndroid Build Coastguard Worker address->bias += nir_scalar_as_uint(op1);
101*61046927SAndroid Build Coastguard Worker address->B = op2;
102*61046927SAndroid Build Coastguard Worker } else if (nir_scalar_is_const(op2) &&
103*61046927SAndroid Build Coastguard Worker nir_scalar_as_uint(op2) <= MAX_POSITIVE_OFFSET) {
104*61046927SAndroid Build Coastguard Worker address->bias += nir_scalar_as_uint(op2);
105*61046927SAndroid Build Coastguard Worker address->B = op1;
106*61046927SAndroid Build Coastguard Worker } else if (!nir_scalar_is_const(op1) && !nir_scalar_is_const(op2) &&
107*61046927SAndroid Build Coastguard Worker first_free && !address->A.def) {
108*61046927SAndroid Build Coastguard Worker address->A = op1;
109*61046927SAndroid Build Coastguard Worker address->B = op2;
110*61046927SAndroid Build Coastguard Worker }
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker /* Matches u2u64 and sets type */
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Worker static void
mir_match_u2u64(struct mir_address * address)116*61046927SAndroid Build Coastguard Worker mir_match_u2u64(struct mir_address *address)
117*61046927SAndroid Build Coastguard Worker {
118*61046927SAndroid Build Coastguard Worker if (!address->B.def || !nir_scalar_is_alu(address->B))
119*61046927SAndroid Build Coastguard Worker return;
120*61046927SAndroid Build Coastguard Worker
121*61046927SAndroid Build Coastguard Worker if (!mir_args_ssa(address->B, 1))
122*61046927SAndroid Build Coastguard Worker return;
123*61046927SAndroid Build Coastguard Worker
124*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->B);
125*61046927SAndroid Build Coastguard Worker if (op != nir_op_u2u64)
126*61046927SAndroid Build Coastguard Worker return;
127*61046927SAndroid Build Coastguard Worker nir_scalar arg = nir_scalar_chase_alu_src(address->B, 0);
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker address->B = arg;
130*61046927SAndroid Build Coastguard Worker address->type = midgard_index_address_u32;
131*61046927SAndroid Build Coastguard Worker }
132*61046927SAndroid Build Coastguard Worker
133*61046927SAndroid Build Coastguard Worker /* Matches i2i64 and sets type */
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker static void
mir_match_i2i64(struct mir_address * address)136*61046927SAndroid Build Coastguard Worker mir_match_i2i64(struct mir_address *address)
137*61046927SAndroid Build Coastguard Worker {
138*61046927SAndroid Build Coastguard Worker if (!address->B.def || !nir_scalar_is_alu(address->B))
139*61046927SAndroid Build Coastguard Worker return;
140*61046927SAndroid Build Coastguard Worker
141*61046927SAndroid Build Coastguard Worker if (!mir_args_ssa(address->B, 1))
142*61046927SAndroid Build Coastguard Worker return;
143*61046927SAndroid Build Coastguard Worker
144*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->B);
145*61046927SAndroid Build Coastguard Worker if (op != nir_op_i2i64)
146*61046927SAndroid Build Coastguard Worker return;
147*61046927SAndroid Build Coastguard Worker nir_scalar arg = nir_scalar_chase_alu_src(address->B, 0);
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker address->B = arg;
150*61046927SAndroid Build Coastguard Worker address->type = midgard_index_address_s32;
151*61046927SAndroid Build Coastguard Worker }
152*61046927SAndroid Build Coastguard Worker
153*61046927SAndroid Build Coastguard Worker /* Matches ishl to shift */
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker static void
mir_match_ishl(struct mir_address * address)156*61046927SAndroid Build Coastguard Worker mir_match_ishl(struct mir_address *address)
157*61046927SAndroid Build Coastguard Worker {
158*61046927SAndroid Build Coastguard Worker if (!address->B.def || !nir_scalar_is_alu(address->B))
159*61046927SAndroid Build Coastguard Worker return;
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker if (!mir_args_ssa(address->B, 2))
162*61046927SAndroid Build Coastguard Worker return;
163*61046927SAndroid Build Coastguard Worker
164*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->B);
165*61046927SAndroid Build Coastguard Worker if (op != nir_op_ishl)
166*61046927SAndroid Build Coastguard Worker return;
167*61046927SAndroid Build Coastguard Worker nir_scalar op1 = nir_scalar_chase_alu_src(address->B, 0);
168*61046927SAndroid Build Coastguard Worker nir_scalar op2 = nir_scalar_chase_alu_src(address->B, 1);
169*61046927SAndroid Build Coastguard Worker
170*61046927SAndroid Build Coastguard Worker if (!nir_scalar_is_const(op2))
171*61046927SAndroid Build Coastguard Worker return;
172*61046927SAndroid Build Coastguard Worker
173*61046927SAndroid Build Coastguard Worker unsigned shift = nir_scalar_as_uint(op2);
174*61046927SAndroid Build Coastguard Worker if (shift > 0x7)
175*61046927SAndroid Build Coastguard Worker return;
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker address->B = op1;
178*61046927SAndroid Build Coastguard Worker address->shift = shift;
179*61046927SAndroid Build Coastguard Worker }
180*61046927SAndroid Build Coastguard Worker
181*61046927SAndroid Build Coastguard Worker /* Strings through mov which can happen from NIR vectorization */
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker static void
mir_match_mov(struct mir_address * address)184*61046927SAndroid Build Coastguard Worker mir_match_mov(struct mir_address *address)
185*61046927SAndroid Build Coastguard Worker {
186*61046927SAndroid Build Coastguard Worker if (address->A.def && nir_scalar_is_alu(address->A)) {
187*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->A);
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker if (op == nir_op_mov && mir_args_ssa(address->A, 1))
190*61046927SAndroid Build Coastguard Worker address->A = nir_scalar_chase_alu_src(address->A, 0);
191*61046927SAndroid Build Coastguard Worker }
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker if (address->B.def && nir_scalar_is_alu(address->B)) {
194*61046927SAndroid Build Coastguard Worker nir_op op = nir_scalar_alu_op(address->B);
195*61046927SAndroid Build Coastguard Worker
196*61046927SAndroid Build Coastguard Worker if (op == nir_op_mov && mir_args_ssa(address->B, 1))
197*61046927SAndroid Build Coastguard Worker address->B = nir_scalar_chase_alu_src(address->B, 0);
198*61046927SAndroid Build Coastguard Worker }
199*61046927SAndroid Build Coastguard Worker }
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker /* Tries to pattern match into mir_address */
202*61046927SAndroid Build Coastguard Worker
203*61046927SAndroid Build Coastguard Worker static struct mir_address
mir_match_offset(nir_def * offset,bool first_free,bool extend)204*61046927SAndroid Build Coastguard Worker mir_match_offset(nir_def *offset, bool first_free, bool extend)
205*61046927SAndroid Build Coastguard Worker {
206*61046927SAndroid Build Coastguard Worker struct mir_address address = {
207*61046927SAndroid Build Coastguard Worker .B = {.def = offset},
208*61046927SAndroid Build Coastguard Worker .type = extend ? midgard_index_address_u64 : midgard_index_address_u32,
209*61046927SAndroid Build Coastguard Worker };
210*61046927SAndroid Build Coastguard Worker
211*61046927SAndroid Build Coastguard Worker mir_match_mov(&address);
212*61046927SAndroid Build Coastguard Worker mir_match_constant(&address);
213*61046927SAndroid Build Coastguard Worker mir_match_mov(&address);
214*61046927SAndroid Build Coastguard Worker mir_match_iadd(&address, first_free);
215*61046927SAndroid Build Coastguard Worker mir_match_mov(&address);
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker if (extend) {
218*61046927SAndroid Build Coastguard Worker mir_match_u2u64(&address);
219*61046927SAndroid Build Coastguard Worker mir_match_i2i64(&address);
220*61046927SAndroid Build Coastguard Worker mir_match_mov(&address);
221*61046927SAndroid Build Coastguard Worker }
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker mir_match_ishl(&address);
224*61046927SAndroid Build Coastguard Worker
225*61046927SAndroid Build Coastguard Worker return address;
226*61046927SAndroid Build Coastguard Worker }
227*61046927SAndroid Build Coastguard Worker
228*61046927SAndroid Build Coastguard Worker void
mir_set_offset(compiler_context * ctx,midgard_instruction * ins,nir_src * offset,unsigned seg)229*61046927SAndroid Build Coastguard Worker mir_set_offset(compiler_context *ctx, midgard_instruction *ins, nir_src *offset,
230*61046927SAndroid Build Coastguard Worker unsigned seg)
231*61046927SAndroid Build Coastguard Worker {
232*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 16; ++i) {
233*61046927SAndroid Build Coastguard Worker ins->swizzle[1][i] = 0;
234*61046927SAndroid Build Coastguard Worker ins->swizzle[2][i] = 0;
235*61046927SAndroid Build Coastguard Worker }
236*61046927SAndroid Build Coastguard Worker
237*61046927SAndroid Build Coastguard Worker /* Sign extend instead of zero extend in case the address is something
238*61046927SAndroid Build Coastguard Worker * like `base + offset + 20`, where offset could be negative. */
239*61046927SAndroid Build Coastguard Worker bool force_sext = (nir_src_bit_size(*offset) < 64);
240*61046927SAndroid Build Coastguard Worker bool first_free = (seg == LDST_GLOBAL);
241*61046927SAndroid Build Coastguard Worker
242*61046927SAndroid Build Coastguard Worker struct mir_address match = mir_match_offset(offset->ssa, first_free, true);
243*61046927SAndroid Build Coastguard Worker
244*61046927SAndroid Build Coastguard Worker if (match.A.def) {
245*61046927SAndroid Build Coastguard Worker unsigned bitsize = match.A.def->bit_size;
246*61046927SAndroid Build Coastguard Worker assert(bitsize == 32 || bitsize == 64);
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker ins->src[1] = nir_ssa_index(match.A.def);
249*61046927SAndroid Build Coastguard Worker ins->swizzle[1][0] = match.A.comp;
250*61046927SAndroid Build Coastguard Worker ins->src_types[1] = nir_type_uint | bitsize;
251*61046927SAndroid Build Coastguard Worker ins->load_store.bitsize_toggle = (bitsize == 64);
252*61046927SAndroid Build Coastguard Worker } else {
253*61046927SAndroid Build Coastguard Worker ins->load_store.bitsize_toggle = true;
254*61046927SAndroid Build Coastguard Worker ins->load_store.arg_comp = seg & 0x3;
255*61046927SAndroid Build Coastguard Worker ins->load_store.arg_reg = (seg >> 2) & 0x7;
256*61046927SAndroid Build Coastguard Worker }
257*61046927SAndroid Build Coastguard Worker
258*61046927SAndroid Build Coastguard Worker if (match.B.def) {
259*61046927SAndroid Build Coastguard Worker ins->src[2] = nir_ssa_index(match.B.def);
260*61046927SAndroid Build Coastguard Worker ins->swizzle[2][0] = match.B.comp;
261*61046927SAndroid Build Coastguard Worker ins->src_types[2] = nir_type_uint | match.B.def->bit_size;
262*61046927SAndroid Build Coastguard Worker } else
263*61046927SAndroid Build Coastguard Worker ins->load_store.index_reg = REGISTER_LDST_ZERO;
264*61046927SAndroid Build Coastguard Worker
265*61046927SAndroid Build Coastguard Worker if (force_sext)
266*61046927SAndroid Build Coastguard Worker match.type = midgard_index_address_s32;
267*61046927SAndroid Build Coastguard Worker
268*61046927SAndroid Build Coastguard Worker ins->load_store.index_format = match.type;
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker assert(match.shift <= 7);
271*61046927SAndroid Build Coastguard Worker ins->load_store.index_shift = match.shift;
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker ins->constants.u32[0] = match.bias;
274*61046927SAndroid Build Coastguard Worker }
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker void
mir_set_ubo_offset(midgard_instruction * ins,nir_src * src,unsigned bias)277*61046927SAndroid Build Coastguard Worker mir_set_ubo_offset(midgard_instruction *ins, nir_src *src, unsigned bias)
278*61046927SAndroid Build Coastguard Worker {
279*61046927SAndroid Build Coastguard Worker struct mir_address match = mir_match_offset(src->ssa, false, false);
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker if (match.B.def) {
282*61046927SAndroid Build Coastguard Worker ins->src[2] = nir_ssa_index(match.B.def);
283*61046927SAndroid Build Coastguard Worker
284*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < ARRAY_SIZE(ins->swizzle[2]); ++i)
285*61046927SAndroid Build Coastguard Worker ins->swizzle[2][i] = match.B.comp;
286*61046927SAndroid Build Coastguard Worker }
287*61046927SAndroid Build Coastguard Worker
288*61046927SAndroid Build Coastguard Worker ins->load_store.index_shift = match.shift;
289*61046927SAndroid Build Coastguard Worker ins->constants.u32[0] = match.bias + bias;
290*61046927SAndroid Build Coastguard Worker }
291