1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2019 Intel Corporation
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
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #ifndef MI_BUILDER_H
25*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_H
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "dev/intel_device_info.h"
28*61046927SAndroid Build Coastguard Worker #include "genxml/genX_bits.h"
29*61046927SAndroid Build Coastguard Worker #include "util/bitscan.h"
30*61046927SAndroid Build Coastguard Worker #include "util/fast_idiv_by_const.h"
31*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker #ifndef MI_BUILDER_NUM_ALLOC_GPRS
34*61046927SAndroid Build Coastguard Worker /** The number of GPRs the MI builder is allowed to allocate
35*61046927SAndroid Build Coastguard Worker *
36*61046927SAndroid Build Coastguard Worker * This may be set by a user of this API so that it can reserve some GPRs at
37*61046927SAndroid Build Coastguard Worker * the top end for its own use.
38*61046927SAndroid Build Coastguard Worker */
39*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_NUM_ALLOC_GPRS 16
40*61046927SAndroid Build Coastguard Worker #endif
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Worker #ifndef MI_BUILDER_DEFAULT_WRITE_CHECK
43*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_DEFAULT_WRITE_CHECK true
44*61046927SAndroid Build Coastguard Worker #endif
45*61046927SAndroid Build Coastguard Worker
46*61046927SAndroid Build Coastguard Worker #ifndef MI_BUILDER_RAW_MEM_FENCING
47*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_RAW_MEM_FENCING GFX_VER >= 20
48*61046927SAndroid Build Coastguard Worker #endif
49*61046927SAndroid Build Coastguard Worker
50*61046927SAndroid Build Coastguard Worker /** These must be defined by the user of the builder
51*61046927SAndroid Build Coastguard Worker *
52*61046927SAndroid Build Coastguard Worker * void *__gen_get_batch_dwords(__gen_user_data *user_data,
53*61046927SAndroid Build Coastguard Worker * unsigned num_dwords);
54*61046927SAndroid Build Coastguard Worker *
55*61046927SAndroid Build Coastguard Worker * __gen_address_type
56*61046927SAndroid Build Coastguard Worker * __gen_address_offset(__gen_address_type addr, uint64_t offset);
57*61046927SAndroid Build Coastguard Worker *
58*61046927SAndroid Build Coastguard Worker *
59*61046927SAndroid Build Coastguard Worker * If self-modifying batches are supported, we must be able to pass batch
60*61046927SAndroid Build Coastguard Worker * addresses around as void*s so pinning as well as batch chaining or some
61*61046927SAndroid Build Coastguard Worker * other mechanism for ensuring batch pointers remain valid during building is
62*61046927SAndroid Build Coastguard Worker * required. The following function must also be defined, it returns an
63*61046927SAndroid Build Coastguard Worker * address in canonical form:
64*61046927SAndroid Build Coastguard Worker *
65*61046927SAndroid Build Coastguard Worker * __gen_address_type
66*61046927SAndroid Build Coastguard Worker * __gen_get_batch_address(__gen_user_data *user_data, void *location);
67*61046927SAndroid Build Coastguard Worker *
68*61046927SAndroid Build Coastguard Worker * Also, __gen_combine_address must accept a location value of NULL and return
69*61046927SAndroid Build Coastguard Worker * a fully valid 64-bit address.
70*61046927SAndroid Build Coastguard Worker */
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker /**
73*61046927SAndroid Build Coastguard Worker * On Gfx20+ this must also be defined by the user of the builder
74*61046927SAndroid Build Coastguard Worker *
75*61046927SAndroid Build Coastguard Worker * bool *
76*61046927SAndroid Build Coastguard Worker * __gen_get_write_fencing_status(__gen_user_data *user_data);
77*61046927SAndroid Build Coastguard Worker *
78*61046927SAndroid Build Coastguard Worker * Returns a pointer to a boolean tracking the status of fencing for MI
79*61046927SAndroid Build Coastguard Worker * commands writing to memory.
80*61046927SAndroid Build Coastguard Worker */
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker /*
83*61046927SAndroid Build Coastguard Worker * Start of the actual MI builder
84*61046927SAndroid Build Coastguard Worker */
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker #define __genxml_cmd_length(cmd) cmd ## _length
87*61046927SAndroid Build Coastguard Worker #define __genxml_cmd_header(cmd) cmd ## _header
88*61046927SAndroid Build Coastguard Worker #define __genxml_cmd_pack(cmd) cmd ## _pack
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker #define mi_builder_pack(b, cmd, dst, name) \
91*61046927SAndroid Build Coastguard Worker for (struct cmd name = { __genxml_cmd_header(cmd) }, \
92*61046927SAndroid Build Coastguard Worker *_dst = (struct cmd *)(dst); __builtin_expect(_dst != NULL, 1); \
93*61046927SAndroid Build Coastguard Worker __genxml_cmd_pack(cmd)((b)->user_data, (void *)_dst, &name), \
94*61046927SAndroid Build Coastguard Worker _dst = NULL)
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker /* Get the instruction pointer inside a mi_builder_pack() block */
97*61046927SAndroid Build Coastguard Worker #define mi_builder_get_inst_ptr(b) \
98*61046927SAndroid Build Coastguard Worker ((uint8_t *)_dst)
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker #define mi_builder_emit(b, cmd, name) \
101*61046927SAndroid Build Coastguard Worker mi_builder_pack((b), cmd, __gen_get_batch_dwords((b)->user_data, __genxml_cmd_length(cmd)), name)
102*61046927SAndroid Build Coastguard Worker
103*61046927SAndroid Build Coastguard Worker enum mi_value_type {
104*61046927SAndroid Build Coastguard Worker MI_VALUE_TYPE_IMM,
105*61046927SAndroid Build Coastguard Worker MI_VALUE_TYPE_MEM32,
106*61046927SAndroid Build Coastguard Worker MI_VALUE_TYPE_MEM64,
107*61046927SAndroid Build Coastguard Worker MI_VALUE_TYPE_REG32,
108*61046927SAndroid Build Coastguard Worker MI_VALUE_TYPE_REG64,
109*61046927SAndroid Build Coastguard Worker };
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker struct mi_value {
112*61046927SAndroid Build Coastguard Worker enum mi_value_type type;
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker union {
115*61046927SAndroid Build Coastguard Worker uint64_t imm;
116*61046927SAndroid Build Coastguard Worker __gen_address_type addr;
117*61046927SAndroid Build Coastguard Worker uint32_t reg;
118*61046927SAndroid Build Coastguard Worker };
119*61046927SAndroid Build Coastguard Worker
120*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
121*61046927SAndroid Build Coastguard Worker bool invert;
122*61046927SAndroid Build Coastguard Worker #endif
123*61046927SAndroid Build Coastguard Worker };
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker struct mi_reg_num {
126*61046927SAndroid Build Coastguard Worker uint32_t num;
127*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
128*61046927SAndroid Build Coastguard Worker bool cs;
129*61046927SAndroid Build Coastguard Worker #endif
130*61046927SAndroid Build Coastguard Worker };
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker static inline struct mi_reg_num
mi_adjust_reg_num(uint32_t reg)133*61046927SAndroid Build Coastguard Worker mi_adjust_reg_num(uint32_t reg)
134*61046927SAndroid Build Coastguard Worker {
135*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
136*61046927SAndroid Build Coastguard Worker bool cs = reg >= 0x2000 && reg < 0x4000;
137*61046927SAndroid Build Coastguard Worker return (struct mi_reg_num) {
138*61046927SAndroid Build Coastguard Worker .num = reg - (cs ? 0x2000 : 0),
139*61046927SAndroid Build Coastguard Worker .cs = cs,
140*61046927SAndroid Build Coastguard Worker };
141*61046927SAndroid Build Coastguard Worker #else
142*61046927SAndroid Build Coastguard Worker return (struct mi_reg_num) { .num = reg, };
143*61046927SAndroid Build Coastguard Worker #endif
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 9
147*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_MAX_MATH_DWORDS 256
148*61046927SAndroid Build Coastguard Worker #else
149*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_MAX_MATH_DWORDS 64
150*61046927SAndroid Build Coastguard Worker #endif
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker struct mi_builder {
153*61046927SAndroid Build Coastguard Worker const struct intel_device_info *devinfo;
154*61046927SAndroid Build Coastguard Worker __gen_user_data *user_data;
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker bool no_read_write_fencing;
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
159*61046927SAndroid Build Coastguard Worker uint32_t gprs;
160*61046927SAndroid Build Coastguard Worker uint8_t gpr_refs[MI_BUILDER_NUM_ALLOC_GPRS];
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker unsigned num_math_dwords;
163*61046927SAndroid Build Coastguard Worker uint32_t math_dwords[MI_BUILDER_MAX_MATH_DWORDS];
164*61046927SAndroid Build Coastguard Worker #endif
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
167*61046927SAndroid Build Coastguard Worker uint32_t mocs;
168*61046927SAndroid Build Coastguard Worker #endif
169*61046927SAndroid Build Coastguard Worker
170*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
171*61046927SAndroid Build Coastguard Worker bool write_check;
172*61046927SAndroid Build Coastguard Worker #endif
173*61046927SAndroid Build Coastguard Worker };
174*61046927SAndroid Build Coastguard Worker
175*61046927SAndroid Build Coastguard Worker static inline void
mi_builder_init(struct mi_builder * b,const struct intel_device_info * devinfo,__gen_user_data * user_data)176*61046927SAndroid Build Coastguard Worker mi_builder_init(struct mi_builder *b,
177*61046927SAndroid Build Coastguard Worker const struct intel_device_info *devinfo,
178*61046927SAndroid Build Coastguard Worker __gen_user_data *user_data)
179*61046927SAndroid Build Coastguard Worker {
180*61046927SAndroid Build Coastguard Worker memset(b, 0, sizeof(*b));
181*61046927SAndroid Build Coastguard Worker b->devinfo = devinfo;
182*61046927SAndroid Build Coastguard Worker b->user_data = user_data;
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
185*61046927SAndroid Build Coastguard Worker b->write_check = MI_BUILDER_DEFAULT_WRITE_CHECK;
186*61046927SAndroid Build Coastguard Worker #endif
187*61046927SAndroid Build Coastguard Worker b->no_read_write_fencing = false;
188*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
189*61046927SAndroid Build Coastguard Worker b->gprs = 0;
190*61046927SAndroid Build Coastguard Worker b->num_math_dwords = 0;
191*61046927SAndroid Build Coastguard Worker #endif
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker static inline void
mi_builder_flush_math(struct mi_builder * b)195*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(struct mi_builder *b)
196*61046927SAndroid Build Coastguard Worker {
197*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
198*61046927SAndroid Build Coastguard Worker if (b->num_math_dwords == 0)
199*61046927SAndroid Build Coastguard Worker return;
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker uint32_t *dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
202*61046927SAndroid Build Coastguard Worker 1 + b->num_math_dwords);
203*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_MATH), dw, math) {
204*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
205*61046927SAndroid Build Coastguard Worker math.MOCS = b->mocs;
206*61046927SAndroid Build Coastguard Worker #endif
207*61046927SAndroid Build Coastguard Worker math.DWordLength = 1 + b->num_math_dwords - GENX(MI_MATH_length_bias);
208*61046927SAndroid Build Coastguard Worker }
209*61046927SAndroid Build Coastguard Worker memcpy(dw + 1, b->math_dwords, b->num_math_dwords * sizeof(uint32_t));
210*61046927SAndroid Build Coastguard Worker b->num_math_dwords = 0;
211*61046927SAndroid Build Coastguard Worker #endif
212*61046927SAndroid Build Coastguard Worker }
213*61046927SAndroid Build Coastguard Worker
214*61046927SAndroid Build Coastguard Worker /**
215*61046927SAndroid Build Coastguard Worker * Set mocs index to mi_build
216*61046927SAndroid Build Coastguard Worker *
217*61046927SAndroid Build Coastguard Worker * This is required when a MI_MATH instruction will be emitted and
218*61046927SAndroid Build Coastguard Worker * the code is used in GFX 12.5 or newer.
219*61046927SAndroid Build Coastguard Worker */
220*61046927SAndroid Build Coastguard Worker static inline void
mi_builder_set_mocs(UNUSED struct mi_builder * b,UNUSED uint32_t mocs)221*61046927SAndroid Build Coastguard Worker mi_builder_set_mocs(UNUSED struct mi_builder *b, UNUSED uint32_t mocs)
222*61046927SAndroid Build Coastguard Worker {
223*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
224*61046927SAndroid Build Coastguard Worker if (b->mocs != 0 && b->mocs != mocs)
225*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
226*61046927SAndroid Build Coastguard Worker b->mocs = mocs;
227*61046927SAndroid Build Coastguard Worker #endif
228*61046927SAndroid Build Coastguard Worker }
229*61046927SAndroid Build Coastguard Worker
230*61046927SAndroid Build Coastguard Worker /**
231*61046927SAndroid Build Coastguard Worker * Set write checks on immediate writes
232*61046927SAndroid Build Coastguard Worker *
233*61046927SAndroid Build Coastguard Worker * This ensures that the next memory write will complete only when all emitted
234*61046927SAndroid Build Coastguard Worker * previously emitted memory write are .
235*61046927SAndroid Build Coastguard Worker */
236*61046927SAndroid Build Coastguard Worker static inline void
mi_builder_set_write_check(UNUSED struct mi_builder * b,UNUSED bool check)237*61046927SAndroid Build Coastguard Worker mi_builder_set_write_check(UNUSED struct mi_builder *b, UNUSED bool check)
238*61046927SAndroid Build Coastguard Worker {
239*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
240*61046927SAndroid Build Coastguard Worker b->write_check = check;
241*61046927SAndroid Build Coastguard Worker #endif
242*61046927SAndroid Build Coastguard Worker }
243*61046927SAndroid Build Coastguard Worker
244*61046927SAndroid Build Coastguard Worker static inline bool
mi_builder_write_checked(UNUSED struct mi_builder * b)245*61046927SAndroid Build Coastguard Worker mi_builder_write_checked(UNUSED struct mi_builder *b)
246*61046927SAndroid Build Coastguard Worker {
247*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
248*61046927SAndroid Build Coastguard Worker return b->write_check;
249*61046927SAndroid Build Coastguard Worker #else
250*61046927SAndroid Build Coastguard Worker return false;
251*61046927SAndroid Build Coastguard Worker #endif
252*61046927SAndroid Build Coastguard Worker }
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker #define _MI_BUILDER_GPR_BASE 0x2600
255*61046927SAndroid Build Coastguard Worker /* The actual hardware limit on GPRs */
256*61046927SAndroid Build Coastguard Worker #define _MI_BUILDER_NUM_HW_GPRS 16
257*61046927SAndroid Build Coastguard Worker
258*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Worker static inline bool
mi_value_is_reg(struct mi_value val)261*61046927SAndroid Build Coastguard Worker mi_value_is_reg(struct mi_value val)
262*61046927SAndroid Build Coastguard Worker {
263*61046927SAndroid Build Coastguard Worker return val.type == MI_VALUE_TYPE_REG32 ||
264*61046927SAndroid Build Coastguard Worker val.type == MI_VALUE_TYPE_REG64;
265*61046927SAndroid Build Coastguard Worker }
266*61046927SAndroid Build Coastguard Worker
267*61046927SAndroid Build Coastguard Worker static inline bool
mi_value_is_gpr(struct mi_value val)268*61046927SAndroid Build Coastguard Worker mi_value_is_gpr(struct mi_value val)
269*61046927SAndroid Build Coastguard Worker {
270*61046927SAndroid Build Coastguard Worker return mi_value_is_reg(val) &&
271*61046927SAndroid Build Coastguard Worker val.reg >= _MI_BUILDER_GPR_BASE &&
272*61046927SAndroid Build Coastguard Worker val.reg < _MI_BUILDER_GPR_BASE +
273*61046927SAndroid Build Coastguard Worker _MI_BUILDER_NUM_HW_GPRS * 8;
274*61046927SAndroid Build Coastguard Worker }
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker static inline bool
_mi_value_is_allocated_gpr(struct mi_value val)277*61046927SAndroid Build Coastguard Worker _mi_value_is_allocated_gpr(struct mi_value val)
278*61046927SAndroid Build Coastguard Worker {
279*61046927SAndroid Build Coastguard Worker return mi_value_is_reg(val) &&
280*61046927SAndroid Build Coastguard Worker val.reg >= _MI_BUILDER_GPR_BASE &&
281*61046927SAndroid Build Coastguard Worker val.reg < _MI_BUILDER_GPR_BASE +
282*61046927SAndroid Build Coastguard Worker MI_BUILDER_NUM_ALLOC_GPRS * 8;
283*61046927SAndroid Build Coastguard Worker }
284*61046927SAndroid Build Coastguard Worker
285*61046927SAndroid Build Coastguard Worker static inline uint32_t
_mi_value_as_gpr(struct mi_value val)286*61046927SAndroid Build Coastguard Worker _mi_value_as_gpr(struct mi_value val)
287*61046927SAndroid Build Coastguard Worker {
288*61046927SAndroid Build Coastguard Worker assert(mi_value_is_gpr(val));
289*61046927SAndroid Build Coastguard Worker /* Some of the GRL metakernels will generate 64bit value in a GP register,
290*61046927SAndroid Build Coastguard Worker * then use only half of that as the last operation on that value. So allow
291*61046927SAndroid Build Coastguard Worker * unref on part of a GP register.
292*61046927SAndroid Build Coastguard Worker */
293*61046927SAndroid Build Coastguard Worker assert(val.reg % 4 == 0);
294*61046927SAndroid Build Coastguard Worker return (val.reg - _MI_BUILDER_GPR_BASE) / 8;
295*61046927SAndroid Build Coastguard Worker }
296*61046927SAndroid Build Coastguard Worker
297*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_new_gpr(struct mi_builder * b)298*61046927SAndroid Build Coastguard Worker mi_new_gpr(struct mi_builder *b)
299*61046927SAndroid Build Coastguard Worker {
300*61046927SAndroid Build Coastguard Worker unsigned gpr = ffs(~b->gprs) - 1;
301*61046927SAndroid Build Coastguard Worker assert(gpr < MI_BUILDER_NUM_ALLOC_GPRS);
302*61046927SAndroid Build Coastguard Worker assert(b->gpr_refs[gpr] == 0);
303*61046927SAndroid Build Coastguard Worker b->gprs |= (1u << gpr);
304*61046927SAndroid Build Coastguard Worker b->gpr_refs[gpr] = 1;
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker return (struct mi_value) {
307*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_REG64,
308*61046927SAndroid Build Coastguard Worker .reg = _MI_BUILDER_GPR_BASE + gpr * 8,
309*61046927SAndroid Build Coastguard Worker };
310*61046927SAndroid Build Coastguard Worker }
311*61046927SAndroid Build Coastguard Worker
312*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_reserve_gpr(struct mi_builder * b,unsigned gpr)313*61046927SAndroid Build Coastguard Worker mi_reserve_gpr(struct mi_builder *b, unsigned gpr)
314*61046927SAndroid Build Coastguard Worker {
315*61046927SAndroid Build Coastguard Worker assert(gpr < MI_BUILDER_NUM_ALLOC_GPRS);
316*61046927SAndroid Build Coastguard Worker assert(!(b->gprs & (1 << gpr)));
317*61046927SAndroid Build Coastguard Worker assert(b->gpr_refs[gpr] == 0);
318*61046927SAndroid Build Coastguard Worker b->gprs |= (1u << gpr);
319*61046927SAndroid Build Coastguard Worker b->gpr_refs[gpr] = 128; /* Enough that we won't unref it */
320*61046927SAndroid Build Coastguard Worker
321*61046927SAndroid Build Coastguard Worker return (struct mi_value) {
322*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_REG64,
323*61046927SAndroid Build Coastguard Worker .reg = _MI_BUILDER_GPR_BASE + gpr * 8,
324*61046927SAndroid Build Coastguard Worker };
325*61046927SAndroid Build Coastguard Worker }
326*61046927SAndroid Build Coastguard Worker #endif /* GFX_VERx10 >= 75 */
327*61046927SAndroid Build Coastguard Worker
328*61046927SAndroid Build Coastguard Worker /** Take a reference to a mi_value
329*61046927SAndroid Build Coastguard Worker *
330*61046927SAndroid Build Coastguard Worker * The MI builder uses reference counting to automatically free ALU GPRs for
331*61046927SAndroid Build Coastguard Worker * re-use in calculations. All mi_* math functions consume the reference
332*61046927SAndroid Build Coastguard Worker * they are handed for each source and return a reference to a value which the
333*61046927SAndroid Build Coastguard Worker * caller must consume. In particular, if you pas the same value into a
334*61046927SAndroid Build Coastguard Worker * single mi_* math function twice (say to add a number to itself), you
335*61046927SAndroid Build Coastguard Worker * are responsible for calling mi_value_ref() to get a second reference
336*61046927SAndroid Build Coastguard Worker * because the mi_* math function will consume it twice.
337*61046927SAndroid Build Coastguard Worker */
338*61046927SAndroid Build Coastguard Worker static inline void
mi_value_add_refs(struct mi_builder * b,struct mi_value val,unsigned num_refs)339*61046927SAndroid Build Coastguard Worker mi_value_add_refs(struct mi_builder *b, struct mi_value val, unsigned num_refs)
340*61046927SAndroid Build Coastguard Worker {
341*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
342*61046927SAndroid Build Coastguard Worker if (_mi_value_is_allocated_gpr(val)) {
343*61046927SAndroid Build Coastguard Worker unsigned gpr = _mi_value_as_gpr(val);
344*61046927SAndroid Build Coastguard Worker assert(gpr < MI_BUILDER_NUM_ALLOC_GPRS);
345*61046927SAndroid Build Coastguard Worker assert(b->gprs & (1u << gpr));
346*61046927SAndroid Build Coastguard Worker assert(b->gpr_refs[gpr] < UINT8_MAX);
347*61046927SAndroid Build Coastguard Worker b->gpr_refs[gpr] += num_refs;
348*61046927SAndroid Build Coastguard Worker }
349*61046927SAndroid Build Coastguard Worker #endif /* GFX_VERx10 >= 75 */
350*61046927SAndroid Build Coastguard Worker }
351*61046927SAndroid Build Coastguard Worker
352*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_value_ref(struct mi_builder * b,struct mi_value val)353*61046927SAndroid Build Coastguard Worker mi_value_ref(struct mi_builder *b, struct mi_value val)
354*61046927SAndroid Build Coastguard Worker {
355*61046927SAndroid Build Coastguard Worker mi_value_add_refs(b, val, 1);
356*61046927SAndroid Build Coastguard Worker return val;
357*61046927SAndroid Build Coastguard Worker }
358*61046927SAndroid Build Coastguard Worker
359*61046927SAndroid Build Coastguard Worker
360*61046927SAndroid Build Coastguard Worker /** Drop a reference to a mi_value
361*61046927SAndroid Build Coastguard Worker *
362*61046927SAndroid Build Coastguard Worker * See also mi_value_ref.
363*61046927SAndroid Build Coastguard Worker */
364*61046927SAndroid Build Coastguard Worker static inline void
mi_value_unref(struct mi_builder * b,struct mi_value val)365*61046927SAndroid Build Coastguard Worker mi_value_unref(struct mi_builder *b, struct mi_value val)
366*61046927SAndroid Build Coastguard Worker {
367*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
368*61046927SAndroid Build Coastguard Worker if (_mi_value_is_allocated_gpr(val)) {
369*61046927SAndroid Build Coastguard Worker unsigned gpr = _mi_value_as_gpr(val);
370*61046927SAndroid Build Coastguard Worker assert(gpr < MI_BUILDER_NUM_ALLOC_GPRS);
371*61046927SAndroid Build Coastguard Worker assert(b->gprs & (1u << gpr));
372*61046927SAndroid Build Coastguard Worker assert(b->gpr_refs[gpr] > 0);
373*61046927SAndroid Build Coastguard Worker if (--b->gpr_refs[gpr] == 0)
374*61046927SAndroid Build Coastguard Worker b->gprs &= ~(1u << gpr);
375*61046927SAndroid Build Coastguard Worker }
376*61046927SAndroid Build Coastguard Worker #endif /* GFX_VERx10 >= 75 */
377*61046927SAndroid Build Coastguard Worker }
378*61046927SAndroid Build Coastguard Worker
379*61046927SAndroid Build Coastguard Worker /* On Gfx20+ memory read/write can be process unordered, so we need to track
380*61046927SAndroid Build Coastguard Worker * the writes to memory to make sure any memory read will see the effect of a
381*61046927SAndroid Build Coastguard Worker * previous write.
382*61046927SAndroid Build Coastguard Worker */
383*61046927SAndroid Build Coastguard Worker static inline void
mi_builder_set_write(struct mi_builder * b)384*61046927SAndroid Build Coastguard Worker mi_builder_set_write(struct mi_builder *b)
385*61046927SAndroid Build Coastguard Worker {
386*61046927SAndroid Build Coastguard Worker #if MI_BUILDER_RAW_MEM_FENCING
387*61046927SAndroid Build Coastguard Worker *__gen_get_write_fencing_status(b->user_data) = true;
388*61046927SAndroid Build Coastguard Worker #endif
389*61046927SAndroid Build Coastguard Worker }
390*61046927SAndroid Build Coastguard Worker
391*61046927SAndroid Build Coastguard Worker static inline void
mi_ensure_write_fence(struct mi_builder * b)392*61046927SAndroid Build Coastguard Worker mi_ensure_write_fence(struct mi_builder *b)
393*61046927SAndroid Build Coastguard Worker {
394*61046927SAndroid Build Coastguard Worker #if MI_BUILDER_RAW_MEM_FENCING
395*61046927SAndroid Build Coastguard Worker if (!b->no_read_write_fencing &&
396*61046927SAndroid Build Coastguard Worker *__gen_get_write_fencing_status(b->user_data)) {
397*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_MEM_FENCE), fence)
398*61046927SAndroid Build Coastguard Worker fence.FenceType = FENCE_TYPE_MI_WRITE;
399*61046927SAndroid Build Coastguard Worker *__gen_get_write_fencing_status(b->user_data) = false;
400*61046927SAndroid Build Coastguard Worker }
401*61046927SAndroid Build Coastguard Worker #endif
402*61046927SAndroid Build Coastguard Worker }
403*61046927SAndroid Build Coastguard Worker
404*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_imm(uint64_t imm)405*61046927SAndroid Build Coastguard Worker mi_imm(uint64_t imm)
406*61046927SAndroid Build Coastguard Worker {
407*61046927SAndroid Build Coastguard Worker return (struct mi_value) {
408*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_IMM,
409*61046927SAndroid Build Coastguard Worker .imm = imm,
410*61046927SAndroid Build Coastguard Worker };
411*61046927SAndroid Build Coastguard Worker }
412*61046927SAndroid Build Coastguard Worker
413*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_reg32(uint32_t reg)414*61046927SAndroid Build Coastguard Worker mi_reg32(uint32_t reg)
415*61046927SAndroid Build Coastguard Worker {
416*61046927SAndroid Build Coastguard Worker struct mi_value val = {
417*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_REG32,
418*61046927SAndroid Build Coastguard Worker .reg = reg,
419*61046927SAndroid Build Coastguard Worker };
420*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
421*61046927SAndroid Build Coastguard Worker assert(!_mi_value_is_allocated_gpr(val));
422*61046927SAndroid Build Coastguard Worker #endif
423*61046927SAndroid Build Coastguard Worker return val;
424*61046927SAndroid Build Coastguard Worker }
425*61046927SAndroid Build Coastguard Worker
426*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_reg64(uint32_t reg)427*61046927SAndroid Build Coastguard Worker mi_reg64(uint32_t reg)
428*61046927SAndroid Build Coastguard Worker {
429*61046927SAndroid Build Coastguard Worker struct mi_value val = {
430*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_REG64,
431*61046927SAndroid Build Coastguard Worker .reg = reg,
432*61046927SAndroid Build Coastguard Worker };
433*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
434*61046927SAndroid Build Coastguard Worker assert(!_mi_value_is_allocated_gpr(val));
435*61046927SAndroid Build Coastguard Worker #endif
436*61046927SAndroid Build Coastguard Worker return val;
437*61046927SAndroid Build Coastguard Worker }
438*61046927SAndroid Build Coastguard Worker
439*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_mem32(__gen_address_type addr)440*61046927SAndroid Build Coastguard Worker mi_mem32(__gen_address_type addr)
441*61046927SAndroid Build Coastguard Worker {
442*61046927SAndroid Build Coastguard Worker return (struct mi_value) {
443*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_MEM32,
444*61046927SAndroid Build Coastguard Worker .addr = addr,
445*61046927SAndroid Build Coastguard Worker };
446*61046927SAndroid Build Coastguard Worker }
447*61046927SAndroid Build Coastguard Worker
448*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_mem64(__gen_address_type addr)449*61046927SAndroid Build Coastguard Worker mi_mem64(__gen_address_type addr)
450*61046927SAndroid Build Coastguard Worker {
451*61046927SAndroid Build Coastguard Worker return (struct mi_value) {
452*61046927SAndroid Build Coastguard Worker .type = MI_VALUE_TYPE_MEM64,
453*61046927SAndroid Build Coastguard Worker .addr = addr,
454*61046927SAndroid Build Coastguard Worker };
455*61046927SAndroid Build Coastguard Worker }
456*61046927SAndroid Build Coastguard Worker
457*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_value_half(struct mi_value value,bool top_32_bits)458*61046927SAndroid Build Coastguard Worker mi_value_half(struct mi_value value, bool top_32_bits)
459*61046927SAndroid Build Coastguard Worker {
460*61046927SAndroid Build Coastguard Worker switch (value.type) {
461*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_IMM:
462*61046927SAndroid Build Coastguard Worker if (top_32_bits)
463*61046927SAndroid Build Coastguard Worker value.imm >>= 32;
464*61046927SAndroid Build Coastguard Worker else
465*61046927SAndroid Build Coastguard Worker value.imm &= 0xffffffffu;
466*61046927SAndroid Build Coastguard Worker return value;
467*61046927SAndroid Build Coastguard Worker
468*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
469*61046927SAndroid Build Coastguard Worker assert(!top_32_bits);
470*61046927SAndroid Build Coastguard Worker return value;
471*61046927SAndroid Build Coastguard Worker
472*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
473*61046927SAndroid Build Coastguard Worker if (top_32_bits)
474*61046927SAndroid Build Coastguard Worker value.addr = __gen_address_offset(value.addr, 4);
475*61046927SAndroid Build Coastguard Worker value.type = MI_VALUE_TYPE_MEM32;
476*61046927SAndroid Build Coastguard Worker return value;
477*61046927SAndroid Build Coastguard Worker
478*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
479*61046927SAndroid Build Coastguard Worker assert(!top_32_bits);
480*61046927SAndroid Build Coastguard Worker return value;
481*61046927SAndroid Build Coastguard Worker
482*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
483*61046927SAndroid Build Coastguard Worker if (top_32_bits)
484*61046927SAndroid Build Coastguard Worker value.reg += 4;
485*61046927SAndroid Build Coastguard Worker value.type = MI_VALUE_TYPE_REG32;
486*61046927SAndroid Build Coastguard Worker return value;
487*61046927SAndroid Build Coastguard Worker }
488*61046927SAndroid Build Coastguard Worker
489*61046927SAndroid Build Coastguard Worker unreachable("Invalid mi_value type");
490*61046927SAndroid Build Coastguard Worker }
491*61046927SAndroid Build Coastguard Worker
492*61046927SAndroid Build Coastguard Worker static inline void
_mi_copy_no_unref(struct mi_builder * b,struct mi_value dst,struct mi_value src)493*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(struct mi_builder *b,
494*61046927SAndroid Build Coastguard Worker struct mi_value dst, struct mi_value src)
495*61046927SAndroid Build Coastguard Worker {
496*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
497*61046927SAndroid Build Coastguard Worker /* TODO: We could handle src.invert by emitting a bit of math if we really
498*61046927SAndroid Build Coastguard Worker * wanted to.
499*61046927SAndroid Build Coastguard Worker */
500*61046927SAndroid Build Coastguard Worker assert(!dst.invert && !src.invert);
501*61046927SAndroid Build Coastguard Worker #endif
502*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
503*61046927SAndroid Build Coastguard Worker
504*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_MEM64 ||
505*61046927SAndroid Build Coastguard Worker src.type == MI_VALUE_TYPE_MEM32)
506*61046927SAndroid Build Coastguard Worker mi_ensure_write_fence(b);
507*61046927SAndroid Build Coastguard Worker
508*61046927SAndroid Build Coastguard Worker switch (dst.type) {
509*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_IMM:
510*61046927SAndroid Build Coastguard Worker unreachable("Cannot copy to an immediate");
511*61046927SAndroid Build Coastguard Worker
512*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
513*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
514*61046927SAndroid Build Coastguard Worker switch (src.type) {
515*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_IMM:
516*61046927SAndroid Build Coastguard Worker if (dst.type == MI_VALUE_TYPE_REG64) {
517*61046927SAndroid Build Coastguard Worker uint32_t *dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
518*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length) + 2);
519*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
520*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_LOAD_REGISTER_IMM), dw, lri) {
521*61046927SAndroid Build Coastguard Worker lri.DWordLength = GENX(MI_LOAD_REGISTER_IMM_length) + 2 -
522*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length_bias);
523*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
524*61046927SAndroid Build Coastguard Worker lri.AddCSMMIOStartOffset = reg.cs;
525*61046927SAndroid Build Coastguard Worker #endif
526*61046927SAndroid Build Coastguard Worker }
527*61046927SAndroid Build Coastguard Worker dw[1] = reg.num;
528*61046927SAndroid Build Coastguard Worker dw[2] = src.imm;
529*61046927SAndroid Build Coastguard Worker dw[3] = reg.num + 4;
530*61046927SAndroid Build Coastguard Worker dw[4] = src.imm >> 32;
531*61046927SAndroid Build Coastguard Worker } else {
532*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 8
533*61046927SAndroid Build Coastguard Worker assert(dst.type == MI_VALUE_TYPE_MEM64);
534*61046927SAndroid Build Coastguard Worker uint32_t *dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
535*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length) + 1);
536*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_STORE_DATA_IMM), dw, sdi) {
537*61046927SAndroid Build Coastguard Worker sdi.DWordLength = GENX(MI_STORE_DATA_IMM_length) + 1 -
538*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length_bias);
539*61046927SAndroid Build Coastguard Worker sdi.StoreQword = true;
540*61046927SAndroid Build Coastguard Worker sdi.Address = dst.addr;
541*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
542*61046927SAndroid Build Coastguard Worker sdi.ForceWriteCompletionCheck = b->write_check;
543*61046927SAndroid Build Coastguard Worker #endif
544*61046927SAndroid Build Coastguard Worker }
545*61046927SAndroid Build Coastguard Worker dw[3] = src.imm;
546*61046927SAndroid Build Coastguard Worker dw[4] = src.imm >> 32;
547*61046927SAndroid Build Coastguard Worker #else
548*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, false),
549*61046927SAndroid Build Coastguard Worker mi_value_half(src, false));
550*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, true),
551*61046927SAndroid Build Coastguard Worker mi_value_half(src, true));
552*61046927SAndroid Build Coastguard Worker #endif
553*61046927SAndroid Build Coastguard Worker }
554*61046927SAndroid Build Coastguard Worker break;
555*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
556*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
557*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, false),
558*61046927SAndroid Build Coastguard Worker mi_value_half(src, false));
559*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, true),
560*61046927SAndroid Build Coastguard Worker mi_imm(0));
561*61046927SAndroid Build Coastguard Worker break;
562*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
563*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
564*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, false),
565*61046927SAndroid Build Coastguard Worker mi_value_half(src, false));
566*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, true),
567*61046927SAndroid Build Coastguard Worker mi_value_half(src, true));
568*61046927SAndroid Build Coastguard Worker break;
569*61046927SAndroid Build Coastguard Worker default:
570*61046927SAndroid Build Coastguard Worker unreachable("Invalid mi_value type");
571*61046927SAndroid Build Coastguard Worker }
572*61046927SAndroid Build Coastguard Worker break;
573*61046927SAndroid Build Coastguard Worker
574*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
575*61046927SAndroid Build Coastguard Worker switch (src.type) {
576*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_IMM:
577*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_DATA_IMM), sdi) {
578*61046927SAndroid Build Coastguard Worker sdi.Address = dst.addr;
579*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 12
580*61046927SAndroid Build Coastguard Worker sdi.ForceWriteCompletionCheck = b->write_check;
581*61046927SAndroid Build Coastguard Worker #endif
582*61046927SAndroid Build Coastguard Worker sdi.ImmediateData = src.imm;
583*61046927SAndroid Build Coastguard Worker }
584*61046927SAndroid Build Coastguard Worker break;
585*61046927SAndroid Build Coastguard Worker
586*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
587*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
588*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 8
589*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_COPY_MEM_MEM), cmm) {
590*61046927SAndroid Build Coastguard Worker cmm.DestinationMemoryAddress = dst.addr;
591*61046927SAndroid Build Coastguard Worker cmm.SourceMemoryAddress = src.addr;
592*61046927SAndroid Build Coastguard Worker }
593*61046927SAndroid Build Coastguard Worker #elif GFX_VERx10 == 75
594*61046927SAndroid Build Coastguard Worker {
595*61046927SAndroid Build Coastguard Worker struct mi_value tmp = mi_new_gpr(b);
596*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, tmp, src);
597*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, dst, tmp);
598*61046927SAndroid Build Coastguard Worker mi_value_unref(b, tmp);
599*61046927SAndroid Build Coastguard Worker }
600*61046927SAndroid Build Coastguard Worker #else
601*61046927SAndroid Build Coastguard Worker unreachable("Cannot do mem <-> mem copy on IVB and earlier");
602*61046927SAndroid Build Coastguard Worker #endif
603*61046927SAndroid Build Coastguard Worker break;
604*61046927SAndroid Build Coastguard Worker
605*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
606*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
607*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
608*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(src.reg);
609*61046927SAndroid Build Coastguard Worker srm.RegisterAddress = reg.num;
610*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
611*61046927SAndroid Build Coastguard Worker srm.AddCSMMIOStartOffset = reg.cs;
612*61046927SAndroid Build Coastguard Worker #endif
613*61046927SAndroid Build Coastguard Worker srm.MemoryAddress = dst.addr;
614*61046927SAndroid Build Coastguard Worker }
615*61046927SAndroid Build Coastguard Worker break;
616*61046927SAndroid Build Coastguard Worker
617*61046927SAndroid Build Coastguard Worker default:
618*61046927SAndroid Build Coastguard Worker unreachable("Invalid mi_value type");
619*61046927SAndroid Build Coastguard Worker }
620*61046927SAndroid Build Coastguard Worker break;
621*61046927SAndroid Build Coastguard Worker
622*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
623*61046927SAndroid Build Coastguard Worker switch (src.type) {
624*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_IMM:
625*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_LOAD_REGISTER_IMM), lri) {
626*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
627*61046927SAndroid Build Coastguard Worker lri.RegisterOffset = reg.num;
628*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
629*61046927SAndroid Build Coastguard Worker lri.AddCSMMIOStartOffset = reg.cs;
630*61046927SAndroid Build Coastguard Worker #endif
631*61046927SAndroid Build Coastguard Worker lri.DataDWord = src.imm;
632*61046927SAndroid Build Coastguard Worker }
633*61046927SAndroid Build Coastguard Worker break;
634*61046927SAndroid Build Coastguard Worker
635*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
636*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
637*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 7
638*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_LOAD_REGISTER_MEM), lrm) {
639*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
640*61046927SAndroid Build Coastguard Worker lrm.RegisterAddress = reg.num;
641*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
642*61046927SAndroid Build Coastguard Worker lrm.AddCSMMIOStartOffset = reg.cs;
643*61046927SAndroid Build Coastguard Worker #endif
644*61046927SAndroid Build Coastguard Worker lrm.MemoryAddress = src.addr;
645*61046927SAndroid Build Coastguard Worker }
646*61046927SAndroid Build Coastguard Worker #else
647*61046927SAndroid Build Coastguard Worker unreachable("Cannot load do mem -> reg copy on SNB and earlier");
648*61046927SAndroid Build Coastguard Worker #endif
649*61046927SAndroid Build Coastguard Worker break;
650*61046927SAndroid Build Coastguard Worker
651*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
652*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
653*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
654*61046927SAndroid Build Coastguard Worker if (src.reg != dst.reg) {
655*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_LOAD_REGISTER_REG), lrr) {
656*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(src.reg);
657*61046927SAndroid Build Coastguard Worker lrr.SourceRegisterAddress = reg.num;
658*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
659*61046927SAndroid Build Coastguard Worker lrr.AddCSMMIOStartOffsetSource = reg.cs;
660*61046927SAndroid Build Coastguard Worker #endif
661*61046927SAndroid Build Coastguard Worker reg = mi_adjust_reg_num(dst.reg);
662*61046927SAndroid Build Coastguard Worker lrr.DestinationRegisterAddress = reg.num;
663*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
664*61046927SAndroid Build Coastguard Worker lrr.AddCSMMIOStartOffsetDestination = reg.cs;
665*61046927SAndroid Build Coastguard Worker #endif
666*61046927SAndroid Build Coastguard Worker }
667*61046927SAndroid Build Coastguard Worker }
668*61046927SAndroid Build Coastguard Worker #else
669*61046927SAndroid Build Coastguard Worker unreachable("Cannot do reg <-> reg copy on IVB and earlier");
670*61046927SAndroid Build Coastguard Worker #endif
671*61046927SAndroid Build Coastguard Worker break;
672*61046927SAndroid Build Coastguard Worker
673*61046927SAndroid Build Coastguard Worker default:
674*61046927SAndroid Build Coastguard Worker unreachable("Invalid mi_value type");
675*61046927SAndroid Build Coastguard Worker }
676*61046927SAndroid Build Coastguard Worker break;
677*61046927SAndroid Build Coastguard Worker
678*61046927SAndroid Build Coastguard Worker default:
679*61046927SAndroid Build Coastguard Worker unreachable("Invalid mi_value type");
680*61046927SAndroid Build Coastguard Worker }
681*61046927SAndroid Build Coastguard Worker
682*61046927SAndroid Build Coastguard Worker
683*61046927SAndroid Build Coastguard Worker if (dst.type == MI_VALUE_TYPE_MEM64 ||
684*61046927SAndroid Build Coastguard Worker dst.type == MI_VALUE_TYPE_MEM32) {
685*61046927SAndroid Build Coastguard Worker /* Immediate writes can already wait for writes, so no need to do
686*61046927SAndroid Build Coastguard Worker * additional fencing later.
687*61046927SAndroid Build Coastguard Worker */
688*61046927SAndroid Build Coastguard Worker if (src.type != MI_VALUE_TYPE_IMM || !mi_builder_write_checked(b))
689*61046927SAndroid Build Coastguard Worker mi_builder_set_write(b);
690*61046927SAndroid Build Coastguard Worker }
691*61046927SAndroid Build Coastguard Worker }
692*61046927SAndroid Build Coastguard Worker
693*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
694*61046927SAndroid Build Coastguard Worker static inline struct mi_value
695*61046927SAndroid Build Coastguard Worker mi_resolve_invert(struct mi_builder *b, struct mi_value src);
696*61046927SAndroid Build Coastguard Worker #endif
697*61046927SAndroid Build Coastguard Worker
698*61046927SAndroid Build Coastguard Worker /** Store the value in src to the value represented by dst
699*61046927SAndroid Build Coastguard Worker *
700*61046927SAndroid Build Coastguard Worker * If the bit size of src and dst mismatch, this function does an unsigned
701*61046927SAndroid Build Coastguard Worker * integer cast. If src has more bits than dst, it takes the bottom bits. If
702*61046927SAndroid Build Coastguard Worker * src has fewer bits then dst, it fills the top bits with zeros.
703*61046927SAndroid Build Coastguard Worker *
704*61046927SAndroid Build Coastguard Worker * This function consumes one reference for each of src and dst.
705*61046927SAndroid Build Coastguard Worker */
706*61046927SAndroid Build Coastguard Worker static inline void
mi_store(struct mi_builder * b,struct mi_value dst,struct mi_value src)707*61046927SAndroid Build Coastguard Worker mi_store(struct mi_builder *b, struct mi_value dst, struct mi_value src)
708*61046927SAndroid Build Coastguard Worker {
709*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
710*61046927SAndroid Build Coastguard Worker src = mi_resolve_invert(b, src);
711*61046927SAndroid Build Coastguard Worker #endif
712*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, dst, src);
713*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src);
714*61046927SAndroid Build Coastguard Worker mi_value_unref(b, dst);
715*61046927SAndroid Build Coastguard Worker }
716*61046927SAndroid Build Coastguard Worker
717*61046927SAndroid Build Coastguard Worker static inline void
mi_memset(struct mi_builder * b,__gen_address_type dst,uint32_t value,uint32_t size)718*61046927SAndroid Build Coastguard Worker mi_memset(struct mi_builder *b, __gen_address_type dst,
719*61046927SAndroid Build Coastguard Worker uint32_t value, uint32_t size)
720*61046927SAndroid Build Coastguard Worker {
721*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
722*61046927SAndroid Build Coastguard Worker assert(b->num_math_dwords == 0);
723*61046927SAndroid Build Coastguard Worker #endif
724*61046927SAndroid Build Coastguard Worker
725*61046927SAndroid Build Coastguard Worker /* This memset operates in units of dwords. */
726*61046927SAndroid Build Coastguard Worker assert(size % 4 == 0);
727*61046927SAndroid Build Coastguard Worker
728*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < size; i += 4) {
729*61046927SAndroid Build Coastguard Worker mi_store(b, mi_mem32(__gen_address_offset(dst, i)),
730*61046927SAndroid Build Coastguard Worker mi_imm(value));
731*61046927SAndroid Build Coastguard Worker }
732*61046927SAndroid Build Coastguard Worker }
733*61046927SAndroid Build Coastguard Worker
734*61046927SAndroid Build Coastguard Worker /* NOTE: On IVB, this function stomps GFX7_3DPRIM_BASE_VERTEX */
735*61046927SAndroid Build Coastguard Worker static inline void
mi_memcpy(struct mi_builder * b,__gen_address_type dst,__gen_address_type src,uint32_t size)736*61046927SAndroid Build Coastguard Worker mi_memcpy(struct mi_builder *b, __gen_address_type dst,
737*61046927SAndroid Build Coastguard Worker __gen_address_type src, uint32_t size)
738*61046927SAndroid Build Coastguard Worker {
739*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
740*61046927SAndroid Build Coastguard Worker assert(b->num_math_dwords == 0);
741*61046927SAndroid Build Coastguard Worker #endif
742*61046927SAndroid Build Coastguard Worker
743*61046927SAndroid Build Coastguard Worker /* Flush once only */
744*61046927SAndroid Build Coastguard Worker mi_ensure_write_fence(b);
745*61046927SAndroid Build Coastguard Worker b->no_read_write_fencing = true;
746*61046927SAndroid Build Coastguard Worker
747*61046927SAndroid Build Coastguard Worker /* Hold off write checks until the last write. */
748*61046927SAndroid Build Coastguard Worker bool write_check = mi_builder_write_checked(b);
749*61046927SAndroid Build Coastguard Worker mi_builder_set_write_check(b, false);
750*61046927SAndroid Build Coastguard Worker
751*61046927SAndroid Build Coastguard Worker /* This memcpy operates in units of dwords. */
752*61046927SAndroid Build Coastguard Worker assert(size % 4 == 0);
753*61046927SAndroid Build Coastguard Worker
754*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < size; i += 4) {
755*61046927SAndroid Build Coastguard Worker if (i == size - 4)
756*61046927SAndroid Build Coastguard Worker mi_builder_set_write_check(b, write_check);
757*61046927SAndroid Build Coastguard Worker
758*61046927SAndroid Build Coastguard Worker struct mi_value dst_val = mi_mem32(__gen_address_offset(dst, i));
759*61046927SAndroid Build Coastguard Worker struct mi_value src_val = mi_mem32(__gen_address_offset(src, i));
760*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
761*61046927SAndroid Build Coastguard Worker mi_store(b, dst_val, src_val);
762*61046927SAndroid Build Coastguard Worker #else
763*61046927SAndroid Build Coastguard Worker /* IVB does not have a general purpose register for command streamer
764*61046927SAndroid Build Coastguard Worker * commands. Therefore, we use an alternate temporary register.
765*61046927SAndroid Build Coastguard Worker */
766*61046927SAndroid Build Coastguard Worker struct mi_value tmp_reg = mi_reg32(0x2440); /* GFX7_3DPRIM_BASE_VERTEX */
767*61046927SAndroid Build Coastguard Worker mi_store(b, tmp_reg, src_val);
768*61046927SAndroid Build Coastguard Worker mi_store(b, dst_val, tmp_reg);
769*61046927SAndroid Build Coastguard Worker #endif
770*61046927SAndroid Build Coastguard Worker }
771*61046927SAndroid Build Coastguard Worker
772*61046927SAndroid Build Coastguard Worker b->no_read_write_fencing = false;
773*61046927SAndroid Build Coastguard Worker }
774*61046927SAndroid Build Coastguard Worker
775*61046927SAndroid Build Coastguard Worker /*
776*61046927SAndroid Build Coastguard Worker * MI_MATH Section. Only available on Haswell+
777*61046927SAndroid Build Coastguard Worker */
778*61046927SAndroid Build Coastguard Worker
779*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 75
780*61046927SAndroid Build Coastguard Worker
781*61046927SAndroid Build Coastguard Worker /**
782*61046927SAndroid Build Coastguard Worker * Perform a predicated store (assuming the condition is already loaded
783*61046927SAndroid Build Coastguard Worker * in the MI_PREDICATE_RESULT register) of the value in src to the memory
784*61046927SAndroid Build Coastguard Worker * location specified by dst. Non-memory destinations are not supported.
785*61046927SAndroid Build Coastguard Worker *
786*61046927SAndroid Build Coastguard Worker * This function consumes one reference for each of src and dst.
787*61046927SAndroid Build Coastguard Worker */
788*61046927SAndroid Build Coastguard Worker static inline void
mi_store_if(struct mi_builder * b,struct mi_value dst,struct mi_value src)789*61046927SAndroid Build Coastguard Worker mi_store_if(struct mi_builder *b, struct mi_value dst, struct mi_value src)
790*61046927SAndroid Build Coastguard Worker {
791*61046927SAndroid Build Coastguard Worker assert(!dst.invert && !src.invert);
792*61046927SAndroid Build Coastguard Worker
793*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
794*61046927SAndroid Build Coastguard Worker
795*61046927SAndroid Build Coastguard Worker /* We can only predicate MI_STORE_REGISTER_MEM, so restrict the
796*61046927SAndroid Build Coastguard Worker * destination to be memory, and resolve the source to a temporary
797*61046927SAndroid Build Coastguard Worker * register if it isn't in one already.
798*61046927SAndroid Build Coastguard Worker */
799*61046927SAndroid Build Coastguard Worker assert(dst.type == MI_VALUE_TYPE_MEM64 ||
800*61046927SAndroid Build Coastguard Worker dst.type == MI_VALUE_TYPE_MEM32);
801*61046927SAndroid Build Coastguard Worker
802*61046927SAndroid Build Coastguard Worker if (src.type != MI_VALUE_TYPE_REG32 &&
803*61046927SAndroid Build Coastguard Worker src.type != MI_VALUE_TYPE_REG64) {
804*61046927SAndroid Build Coastguard Worker struct mi_value tmp = mi_new_gpr(b);
805*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, tmp, src);
806*61046927SAndroid Build Coastguard Worker src = tmp;
807*61046927SAndroid Build Coastguard Worker }
808*61046927SAndroid Build Coastguard Worker
809*61046927SAndroid Build Coastguard Worker if (dst.type == MI_VALUE_TYPE_MEM64) {
810*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
811*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(src.reg);
812*61046927SAndroid Build Coastguard Worker srm.RegisterAddress = reg.num;
813*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
814*61046927SAndroid Build Coastguard Worker srm.AddCSMMIOStartOffset = reg.cs;
815*61046927SAndroid Build Coastguard Worker #endif
816*61046927SAndroid Build Coastguard Worker srm.MemoryAddress = dst.addr;
817*61046927SAndroid Build Coastguard Worker srm.PredicateEnable = true;
818*61046927SAndroid Build Coastguard Worker }
819*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
820*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(src.reg + 4);
821*61046927SAndroid Build Coastguard Worker srm.RegisterAddress = reg.num;
822*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
823*61046927SAndroid Build Coastguard Worker srm.AddCSMMIOStartOffset = reg.cs;
824*61046927SAndroid Build Coastguard Worker #endif
825*61046927SAndroid Build Coastguard Worker srm.MemoryAddress = __gen_address_offset(dst.addr, 4);
826*61046927SAndroid Build Coastguard Worker srm.PredicateEnable = true;
827*61046927SAndroid Build Coastguard Worker }
828*61046927SAndroid Build Coastguard Worker } else {
829*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
830*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(src.reg);
831*61046927SAndroid Build Coastguard Worker srm.RegisterAddress = reg.num;
832*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
833*61046927SAndroid Build Coastguard Worker srm.AddCSMMIOStartOffset = reg.cs;
834*61046927SAndroid Build Coastguard Worker #endif
835*61046927SAndroid Build Coastguard Worker srm.MemoryAddress = dst.addr;
836*61046927SAndroid Build Coastguard Worker srm.PredicateEnable = true;
837*61046927SAndroid Build Coastguard Worker }
838*61046927SAndroid Build Coastguard Worker }
839*61046927SAndroid Build Coastguard Worker
840*61046927SAndroid Build Coastguard Worker mi_builder_set_write(b);
841*61046927SAndroid Build Coastguard Worker
842*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src);
843*61046927SAndroid Build Coastguard Worker mi_value_unref(b, dst);
844*61046927SAndroid Build Coastguard Worker }
845*61046927SAndroid Build Coastguard Worker
846*61046927SAndroid Build Coastguard Worker static inline void
_mi_builder_push_math(struct mi_builder * b,const uint32_t * dwords,unsigned num_dwords)847*61046927SAndroid Build Coastguard Worker _mi_builder_push_math(struct mi_builder *b,
848*61046927SAndroid Build Coastguard Worker const uint32_t *dwords,
849*61046927SAndroid Build Coastguard Worker unsigned num_dwords)
850*61046927SAndroid Build Coastguard Worker {
851*61046927SAndroid Build Coastguard Worker assert(num_dwords < MI_BUILDER_MAX_MATH_DWORDS);
852*61046927SAndroid Build Coastguard Worker if (b->num_math_dwords + num_dwords > MI_BUILDER_MAX_MATH_DWORDS)
853*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
854*61046927SAndroid Build Coastguard Worker
855*61046927SAndroid Build Coastguard Worker memcpy(&b->math_dwords[b->num_math_dwords],
856*61046927SAndroid Build Coastguard Worker dwords, num_dwords * sizeof(*dwords));
857*61046927SAndroid Build Coastguard Worker b->num_math_dwords += num_dwords;
858*61046927SAndroid Build Coastguard Worker }
859*61046927SAndroid Build Coastguard Worker
860*61046927SAndroid Build Coastguard Worker static inline uint32_t
_mi_pack_alu(uint32_t opcode,uint32_t operand1,uint32_t operand2)861*61046927SAndroid Build Coastguard Worker _mi_pack_alu(uint32_t opcode, uint32_t operand1, uint32_t operand2)
862*61046927SAndroid Build Coastguard Worker {
863*61046927SAndroid Build Coastguard Worker struct GENX(MI_MATH_ALU_INSTRUCTION) instr = {
864*61046927SAndroid Build Coastguard Worker .Operand2 = operand2,
865*61046927SAndroid Build Coastguard Worker .Operand1 = operand1,
866*61046927SAndroid Build Coastguard Worker .ALUOpcode = opcode,
867*61046927SAndroid Build Coastguard Worker };
868*61046927SAndroid Build Coastguard Worker
869*61046927SAndroid Build Coastguard Worker uint32_t dw;
870*61046927SAndroid Build Coastguard Worker GENX(MI_MATH_ALU_INSTRUCTION_pack)(NULL, &dw, &instr);
871*61046927SAndroid Build Coastguard Worker
872*61046927SAndroid Build Coastguard Worker return dw;
873*61046927SAndroid Build Coastguard Worker }
874*61046927SAndroid Build Coastguard Worker
875*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_value_to_gpr(struct mi_builder * b,struct mi_value val)876*61046927SAndroid Build Coastguard Worker mi_value_to_gpr(struct mi_builder *b, struct mi_value val)
877*61046927SAndroid Build Coastguard Worker {
878*61046927SAndroid Build Coastguard Worker if (mi_value_is_gpr(val))
879*61046927SAndroid Build Coastguard Worker return val;
880*61046927SAndroid Build Coastguard Worker
881*61046927SAndroid Build Coastguard Worker /* Save off the invert flag because it makes copy() grumpy */
882*61046927SAndroid Build Coastguard Worker bool invert = val.invert;
883*61046927SAndroid Build Coastguard Worker val.invert = false;
884*61046927SAndroid Build Coastguard Worker
885*61046927SAndroid Build Coastguard Worker struct mi_value tmp = mi_new_gpr(b);
886*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, tmp, val);
887*61046927SAndroid Build Coastguard Worker tmp.invert = invert;
888*61046927SAndroid Build Coastguard Worker
889*61046927SAndroid Build Coastguard Worker return tmp;
890*61046927SAndroid Build Coastguard Worker }
891*61046927SAndroid Build Coastguard Worker
892*61046927SAndroid Build Coastguard Worker static inline uint64_t
mi_value_to_u64(struct mi_value val)893*61046927SAndroid Build Coastguard Worker mi_value_to_u64(struct mi_value val)
894*61046927SAndroid Build Coastguard Worker {
895*61046927SAndroid Build Coastguard Worker assert(val.type == MI_VALUE_TYPE_IMM);
896*61046927SAndroid Build Coastguard Worker return val.invert ? ~val.imm : val.imm;
897*61046927SAndroid Build Coastguard Worker }
898*61046927SAndroid Build Coastguard Worker
899*61046927SAndroid Build Coastguard Worker static inline uint32_t
_mi_math_load_src(struct mi_builder * b,unsigned src,struct mi_value * val)900*61046927SAndroid Build Coastguard Worker _mi_math_load_src(struct mi_builder *b, unsigned src, struct mi_value *val)
901*61046927SAndroid Build Coastguard Worker {
902*61046927SAndroid Build Coastguard Worker if (val->type == MI_VALUE_TYPE_IMM &&
903*61046927SAndroid Build Coastguard Worker (val->imm == 0 || val->imm == UINT64_MAX)) {
904*61046927SAndroid Build Coastguard Worker uint64_t imm = val->invert ? ~val->imm : val->imm;
905*61046927SAndroid Build Coastguard Worker return _mi_pack_alu(imm ? MI_ALU_LOAD1 : MI_ALU_LOAD0, src, 0);
906*61046927SAndroid Build Coastguard Worker } else {
907*61046927SAndroid Build Coastguard Worker *val = mi_value_to_gpr(b, *val);
908*61046927SAndroid Build Coastguard Worker return _mi_pack_alu(val->invert ? MI_ALU_LOADINV : MI_ALU_LOAD,
909*61046927SAndroid Build Coastguard Worker src, _mi_value_as_gpr(*val));
910*61046927SAndroid Build Coastguard Worker }
911*61046927SAndroid Build Coastguard Worker }
912*61046927SAndroid Build Coastguard Worker
913*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_math_binop(struct mi_builder * b,uint32_t opcode,struct mi_value src0,struct mi_value src1,uint32_t store_op,uint32_t store_src)914*61046927SAndroid Build Coastguard Worker mi_math_binop(struct mi_builder *b, uint32_t opcode,
915*61046927SAndroid Build Coastguard Worker struct mi_value src0, struct mi_value src1,
916*61046927SAndroid Build Coastguard Worker uint32_t store_op, uint32_t store_src)
917*61046927SAndroid Build Coastguard Worker {
918*61046927SAndroid Build Coastguard Worker struct mi_value dst = mi_new_gpr(b);
919*61046927SAndroid Build Coastguard Worker
920*61046927SAndroid Build Coastguard Worker uint32_t dw[4];
921*61046927SAndroid Build Coastguard Worker dw[0] = _mi_math_load_src(b, MI_ALU_SRCA, &src0);
922*61046927SAndroid Build Coastguard Worker dw[1] = _mi_math_load_src(b, MI_ALU_SRCB, &src1);
923*61046927SAndroid Build Coastguard Worker dw[2] = _mi_pack_alu(opcode, 0, 0);
924*61046927SAndroid Build Coastguard Worker dw[3] = _mi_pack_alu(store_op, _mi_value_as_gpr(dst), store_src);
925*61046927SAndroid Build Coastguard Worker _mi_builder_push_math(b, dw, 4);
926*61046927SAndroid Build Coastguard Worker
927*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src0);
928*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src1);
929*61046927SAndroid Build Coastguard Worker
930*61046927SAndroid Build Coastguard Worker return dst;
931*61046927SAndroid Build Coastguard Worker }
932*61046927SAndroid Build Coastguard Worker
933*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_inot(struct mi_builder * b,struct mi_value val)934*61046927SAndroid Build Coastguard Worker mi_inot(struct mi_builder *b, struct mi_value val)
935*61046927SAndroid Build Coastguard Worker {
936*61046927SAndroid Build Coastguard Worker if (val.type == MI_VALUE_TYPE_IMM)
937*61046927SAndroid Build Coastguard Worker return mi_imm(~mi_value_to_u64(val));
938*61046927SAndroid Build Coastguard Worker
939*61046927SAndroid Build Coastguard Worker val.invert = !val.invert;
940*61046927SAndroid Build Coastguard Worker return val;
941*61046927SAndroid Build Coastguard Worker }
942*61046927SAndroid Build Coastguard Worker
943*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_resolve_invert(struct mi_builder * b,struct mi_value src)944*61046927SAndroid Build Coastguard Worker mi_resolve_invert(struct mi_builder *b, struct mi_value src)
945*61046927SAndroid Build Coastguard Worker {
946*61046927SAndroid Build Coastguard Worker if (!src.invert)
947*61046927SAndroid Build Coastguard Worker return src;
948*61046927SAndroid Build Coastguard Worker
949*61046927SAndroid Build Coastguard Worker assert(src.type != MI_VALUE_TYPE_IMM);
950*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_ADD, src, mi_imm(0),
951*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
952*61046927SAndroid Build Coastguard Worker }
953*61046927SAndroid Build Coastguard Worker
954*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_iadd(struct mi_builder * b,struct mi_value src0,struct mi_value src1)955*61046927SAndroid Build Coastguard Worker mi_iadd(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
956*61046927SAndroid Build Coastguard Worker {
957*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
958*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) + mi_value_to_u64(src1));
959*61046927SAndroid Build Coastguard Worker
960*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_ADD, src0, src1,
961*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
962*61046927SAndroid Build Coastguard Worker }
963*61046927SAndroid Build Coastguard Worker
964*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_iadd_imm(struct mi_builder * b,struct mi_value src,uint64_t N)965*61046927SAndroid Build Coastguard Worker mi_iadd_imm(struct mi_builder *b,
966*61046927SAndroid Build Coastguard Worker struct mi_value src, uint64_t N)
967*61046927SAndroid Build Coastguard Worker {
968*61046927SAndroid Build Coastguard Worker if (N == 0)
969*61046927SAndroid Build Coastguard Worker return src;
970*61046927SAndroid Build Coastguard Worker
971*61046927SAndroid Build Coastguard Worker return mi_iadd(b, src, mi_imm(N));
972*61046927SAndroid Build Coastguard Worker }
973*61046927SAndroid Build Coastguard Worker
974*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_isub(struct mi_builder * b,struct mi_value src0,struct mi_value src1)975*61046927SAndroid Build Coastguard Worker mi_isub(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
976*61046927SAndroid Build Coastguard Worker {
977*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
978*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) - mi_value_to_u64(src1));
979*61046927SAndroid Build Coastguard Worker
980*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SUB, src0, src1,
981*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
982*61046927SAndroid Build Coastguard Worker }
983*61046927SAndroid Build Coastguard Worker
984*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ieq(struct mi_builder * b,struct mi_value src0,struct mi_value src1)985*61046927SAndroid Build Coastguard Worker mi_ieq(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
986*61046927SAndroid Build Coastguard Worker {
987*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
988*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) == mi_value_to_u64(src1) ? ~0ull : 0);
989*61046927SAndroid Build Coastguard Worker
990*61046927SAndroid Build Coastguard Worker /* Compute "equal" by subtracting and storing the zero bit */
991*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SUB, src0, src1,
992*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ZF);
993*61046927SAndroid Build Coastguard Worker }
994*61046927SAndroid Build Coastguard Worker
995*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ine(struct mi_builder * b,struct mi_value src0,struct mi_value src1)996*61046927SAndroid Build Coastguard Worker mi_ine(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
997*61046927SAndroid Build Coastguard Worker {
998*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
999*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) != mi_value_to_u64(src1) ? ~0ull : 0);
1000*61046927SAndroid Build Coastguard Worker
1001*61046927SAndroid Build Coastguard Worker /* Compute "not equal" by subtracting and storing the inverse zero bit */
1002*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SUB, src0, src1,
1003*61046927SAndroid Build Coastguard Worker MI_ALU_STOREINV, MI_ALU_ZF);
1004*61046927SAndroid Build Coastguard Worker }
1005*61046927SAndroid Build Coastguard Worker
1006*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ult(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1007*61046927SAndroid Build Coastguard Worker mi_ult(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1008*61046927SAndroid Build Coastguard Worker {
1009*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1010*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) < mi_value_to_u64(src1) ? ~0ull : 0);
1011*61046927SAndroid Build Coastguard Worker
1012*61046927SAndroid Build Coastguard Worker /* Compute "less than" by subtracting and storing the carry bit */
1013*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SUB, src0, src1,
1014*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_CF);
1015*61046927SAndroid Build Coastguard Worker }
1016*61046927SAndroid Build Coastguard Worker
1017*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_uge(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1018*61046927SAndroid Build Coastguard Worker mi_uge(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1019*61046927SAndroid Build Coastguard Worker {
1020*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1021*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) >= mi_value_to_u64(src1) ? ~0ull : 0);
1022*61046927SAndroid Build Coastguard Worker
1023*61046927SAndroid Build Coastguard Worker /* Compute "less than" by subtracting and storing the carry bit */
1024*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SUB, src0, src1,
1025*61046927SAndroid Build Coastguard Worker MI_ALU_STOREINV, MI_ALU_CF);
1026*61046927SAndroid Build Coastguard Worker }
1027*61046927SAndroid Build Coastguard Worker
1028*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_iand(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1029*61046927SAndroid Build Coastguard Worker mi_iand(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1030*61046927SAndroid Build Coastguard Worker {
1031*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1032*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) & mi_value_to_u64(src1));
1033*61046927SAndroid Build Coastguard Worker
1034*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_AND, src0, src1,
1035*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
1036*61046927SAndroid Build Coastguard Worker }
1037*61046927SAndroid Build Coastguard Worker
1038*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_nz(struct mi_builder * b,struct mi_value src)1039*61046927SAndroid Build Coastguard Worker mi_nz(struct mi_builder *b, struct mi_value src)
1040*61046927SAndroid Build Coastguard Worker {
1041*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1042*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src) != 0 ? ~0ull : 0);
1043*61046927SAndroid Build Coastguard Worker
1044*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_ADD, src, mi_imm(0),
1045*61046927SAndroid Build Coastguard Worker MI_ALU_STOREINV, MI_ALU_ZF);
1046*61046927SAndroid Build Coastguard Worker }
1047*61046927SAndroid Build Coastguard Worker
1048*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_z(struct mi_builder * b,struct mi_value src)1049*61046927SAndroid Build Coastguard Worker mi_z(struct mi_builder *b, struct mi_value src)
1050*61046927SAndroid Build Coastguard Worker {
1051*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1052*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src) == 0 ? ~0ull : 0);
1053*61046927SAndroid Build Coastguard Worker
1054*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_ADD, src, mi_imm(0),
1055*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ZF);
1056*61046927SAndroid Build Coastguard Worker }
1057*61046927SAndroid Build Coastguard Worker
1058*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ior(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1059*61046927SAndroid Build Coastguard Worker mi_ior(struct mi_builder *b,
1060*61046927SAndroid Build Coastguard Worker struct mi_value src0, struct mi_value src1)
1061*61046927SAndroid Build Coastguard Worker {
1062*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1063*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) | mi_value_to_u64(src1));
1064*61046927SAndroid Build Coastguard Worker
1065*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_OR, src0, src1,
1066*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
1067*61046927SAndroid Build Coastguard Worker }
1068*61046927SAndroid Build Coastguard Worker
1069*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1070*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ishl(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1071*61046927SAndroid Build Coastguard Worker mi_ishl(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1072*61046927SAndroid Build Coastguard Worker {
1073*61046927SAndroid Build Coastguard Worker if (src1.type == MI_VALUE_TYPE_IMM) {
1074*61046927SAndroid Build Coastguard Worker assert(util_is_power_of_two_or_zero(mi_value_to_u64(src1)));
1075*61046927SAndroid Build Coastguard Worker assert(mi_value_to_u64(src1) <= 32);
1076*61046927SAndroid Build Coastguard Worker }
1077*61046927SAndroid Build Coastguard Worker
1078*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1079*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) << mi_value_to_u64(src1));
1080*61046927SAndroid Build Coastguard Worker
1081*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SHL, src0, src1,
1082*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
1083*61046927SAndroid Build Coastguard Worker }
1084*61046927SAndroid Build Coastguard Worker
1085*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ushr(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1086*61046927SAndroid Build Coastguard Worker mi_ushr(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1087*61046927SAndroid Build Coastguard Worker {
1088*61046927SAndroid Build Coastguard Worker if (src1.type == MI_VALUE_TYPE_IMM) {
1089*61046927SAndroid Build Coastguard Worker assert(util_is_power_of_two_or_zero(mi_value_to_u64(src1)));
1090*61046927SAndroid Build Coastguard Worker assert(mi_value_to_u64(src1) <= 32);
1091*61046927SAndroid Build Coastguard Worker }
1092*61046927SAndroid Build Coastguard Worker
1093*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1094*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src0) >> mi_value_to_u64(src1));
1095*61046927SAndroid Build Coastguard Worker
1096*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SHR, src0, src1,
1097*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
1098*61046927SAndroid Build Coastguard Worker }
1099*61046927SAndroid Build Coastguard Worker
1100*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ushr_imm(struct mi_builder * b,struct mi_value src,uint32_t shift)1101*61046927SAndroid Build Coastguard Worker mi_ushr_imm(struct mi_builder *b, struct mi_value src, uint32_t shift)
1102*61046927SAndroid Build Coastguard Worker {
1103*61046927SAndroid Build Coastguard Worker if (shift == 0)
1104*61046927SAndroid Build Coastguard Worker return src;
1105*61046927SAndroid Build Coastguard Worker
1106*61046927SAndroid Build Coastguard Worker if (shift >= 64)
1107*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1108*61046927SAndroid Build Coastguard Worker
1109*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1110*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src) >> shift);
1111*61046927SAndroid Build Coastguard Worker
1112*61046927SAndroid Build Coastguard Worker struct mi_value res = mi_value_to_gpr(b, src);
1113*61046927SAndroid Build Coastguard Worker
1114*61046927SAndroid Build Coastguard Worker /* Annoyingly, we only have power-of-two shifts */
1115*61046927SAndroid Build Coastguard Worker while (shift) {
1116*61046927SAndroid Build Coastguard Worker int bit = u_bit_scan(&shift);
1117*61046927SAndroid Build Coastguard Worker assert(bit <= 5);
1118*61046927SAndroid Build Coastguard Worker res = mi_ushr(b, res, mi_imm(1ULL << bit));
1119*61046927SAndroid Build Coastguard Worker }
1120*61046927SAndroid Build Coastguard Worker
1121*61046927SAndroid Build Coastguard Worker return res;
1122*61046927SAndroid Build Coastguard Worker }
1123*61046927SAndroid Build Coastguard Worker
1124*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ishr(struct mi_builder * b,struct mi_value src0,struct mi_value src1)1125*61046927SAndroid Build Coastguard Worker mi_ishr(struct mi_builder *b, struct mi_value src0, struct mi_value src1)
1126*61046927SAndroid Build Coastguard Worker {
1127*61046927SAndroid Build Coastguard Worker if (src1.type == MI_VALUE_TYPE_IMM) {
1128*61046927SAndroid Build Coastguard Worker assert(util_is_power_of_two_or_zero(mi_value_to_u64(src1)));
1129*61046927SAndroid Build Coastguard Worker assert(mi_value_to_u64(src1) <= 32);
1130*61046927SAndroid Build Coastguard Worker }
1131*61046927SAndroid Build Coastguard Worker
1132*61046927SAndroid Build Coastguard Worker if (src0.type == MI_VALUE_TYPE_IMM && src1.type == MI_VALUE_TYPE_IMM)
1133*61046927SAndroid Build Coastguard Worker return mi_imm((int64_t)mi_value_to_u64(src0) >> mi_value_to_u64(src1));
1134*61046927SAndroid Build Coastguard Worker
1135*61046927SAndroid Build Coastguard Worker return mi_math_binop(b, MI_ALU_SAR, src0, src1,
1136*61046927SAndroid Build Coastguard Worker MI_ALU_STORE, MI_ALU_ACCU);
1137*61046927SAndroid Build Coastguard Worker }
1138*61046927SAndroid Build Coastguard Worker
1139*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ishr_imm(struct mi_builder * b,struct mi_value src,uint32_t shift)1140*61046927SAndroid Build Coastguard Worker mi_ishr_imm(struct mi_builder *b, struct mi_value src, uint32_t shift)
1141*61046927SAndroid Build Coastguard Worker {
1142*61046927SAndroid Build Coastguard Worker if (shift == 0)
1143*61046927SAndroid Build Coastguard Worker return src;
1144*61046927SAndroid Build Coastguard Worker
1145*61046927SAndroid Build Coastguard Worker if (shift >= 64)
1146*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1147*61046927SAndroid Build Coastguard Worker
1148*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1149*61046927SAndroid Build Coastguard Worker return mi_imm((int64_t)mi_value_to_u64(src) >> shift);
1150*61046927SAndroid Build Coastguard Worker
1151*61046927SAndroid Build Coastguard Worker struct mi_value res = mi_value_to_gpr(b, src);
1152*61046927SAndroid Build Coastguard Worker
1153*61046927SAndroid Build Coastguard Worker /* Annoyingly, we only have power-of-two shifts */
1154*61046927SAndroid Build Coastguard Worker while (shift) {
1155*61046927SAndroid Build Coastguard Worker int bit = u_bit_scan(&shift);
1156*61046927SAndroid Build Coastguard Worker assert(bit <= 5);
1157*61046927SAndroid Build Coastguard Worker res = mi_ishr(b, res, mi_imm(1 << bit));
1158*61046927SAndroid Build Coastguard Worker }
1159*61046927SAndroid Build Coastguard Worker
1160*61046927SAndroid Build Coastguard Worker return res;
1161*61046927SAndroid Build Coastguard Worker }
1162*61046927SAndroid Build Coastguard Worker #endif /* if GFX_VERx10 >= 125 */
1163*61046927SAndroid Build Coastguard Worker
1164*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_imul_imm(struct mi_builder * b,struct mi_value src,uint32_t N)1165*61046927SAndroid Build Coastguard Worker mi_imul_imm(struct mi_builder *b, struct mi_value src, uint32_t N)
1166*61046927SAndroid Build Coastguard Worker {
1167*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1168*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src) * N);
1169*61046927SAndroid Build Coastguard Worker
1170*61046927SAndroid Build Coastguard Worker if (N == 0) {
1171*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src);
1172*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1173*61046927SAndroid Build Coastguard Worker }
1174*61046927SAndroid Build Coastguard Worker
1175*61046927SAndroid Build Coastguard Worker if (N == 1)
1176*61046927SAndroid Build Coastguard Worker return src;
1177*61046927SAndroid Build Coastguard Worker
1178*61046927SAndroid Build Coastguard Worker src = mi_value_to_gpr(b, src);
1179*61046927SAndroid Build Coastguard Worker
1180*61046927SAndroid Build Coastguard Worker struct mi_value res = mi_value_ref(b, src);
1181*61046927SAndroid Build Coastguard Worker
1182*61046927SAndroid Build Coastguard Worker unsigned top_bit = 31 - __builtin_clz(N);
1183*61046927SAndroid Build Coastguard Worker for (int i = top_bit - 1; i >= 0; i--) {
1184*61046927SAndroid Build Coastguard Worker res = mi_iadd(b, res, mi_value_ref(b, res));
1185*61046927SAndroid Build Coastguard Worker if (N & (1 << i))
1186*61046927SAndroid Build Coastguard Worker res = mi_iadd(b, res, mi_value_ref(b, src));
1187*61046927SAndroid Build Coastguard Worker }
1188*61046927SAndroid Build Coastguard Worker
1189*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src);
1190*61046927SAndroid Build Coastguard Worker
1191*61046927SAndroid Build Coastguard Worker return res;
1192*61046927SAndroid Build Coastguard Worker }
1193*61046927SAndroid Build Coastguard Worker
1194*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ishl_imm(struct mi_builder * b,struct mi_value src,uint32_t shift)1195*61046927SAndroid Build Coastguard Worker mi_ishl_imm(struct mi_builder *b, struct mi_value src, uint32_t shift)
1196*61046927SAndroid Build Coastguard Worker {
1197*61046927SAndroid Build Coastguard Worker if (shift == 0)
1198*61046927SAndroid Build Coastguard Worker return src;
1199*61046927SAndroid Build Coastguard Worker
1200*61046927SAndroid Build Coastguard Worker if (shift >= 64)
1201*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1202*61046927SAndroid Build Coastguard Worker
1203*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1204*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(src) << shift);
1205*61046927SAndroid Build Coastguard Worker
1206*61046927SAndroid Build Coastguard Worker struct mi_value res = mi_value_to_gpr(b, src);
1207*61046927SAndroid Build Coastguard Worker
1208*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1209*61046927SAndroid Build Coastguard Worker /* Annoyingly, we only have power-of-two shifts */
1210*61046927SAndroid Build Coastguard Worker while (shift) {
1211*61046927SAndroid Build Coastguard Worker int bit = u_bit_scan(&shift);
1212*61046927SAndroid Build Coastguard Worker assert(bit <= 5);
1213*61046927SAndroid Build Coastguard Worker res = mi_ishl(b, res, mi_imm(1 << bit));
1214*61046927SAndroid Build Coastguard Worker }
1215*61046927SAndroid Build Coastguard Worker #else
1216*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < shift; i++)
1217*61046927SAndroid Build Coastguard Worker res = mi_iadd(b, res, mi_value_ref(b, res));
1218*61046927SAndroid Build Coastguard Worker #endif
1219*61046927SAndroid Build Coastguard Worker
1220*61046927SAndroid Build Coastguard Worker return res;
1221*61046927SAndroid Build Coastguard Worker }
1222*61046927SAndroid Build Coastguard Worker
1223*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_ushr32_imm(struct mi_builder * b,struct mi_value src,uint32_t shift)1224*61046927SAndroid Build Coastguard Worker mi_ushr32_imm(struct mi_builder *b, struct mi_value src, uint32_t shift)
1225*61046927SAndroid Build Coastguard Worker {
1226*61046927SAndroid Build Coastguard Worker if (shift == 0)
1227*61046927SAndroid Build Coastguard Worker return src;
1228*61046927SAndroid Build Coastguard Worker
1229*61046927SAndroid Build Coastguard Worker if (shift >= 64)
1230*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1231*61046927SAndroid Build Coastguard Worker
1232*61046927SAndroid Build Coastguard Worker /* We right-shift by left-shifting by 32 - shift and taking the top 32 bits
1233*61046927SAndroid Build Coastguard Worker * of the result.
1234*61046927SAndroid Build Coastguard Worker */
1235*61046927SAndroid Build Coastguard Worker if (src.type == MI_VALUE_TYPE_IMM)
1236*61046927SAndroid Build Coastguard Worker return mi_imm((mi_value_to_u64(src) >> shift) & UINT32_MAX);
1237*61046927SAndroid Build Coastguard Worker
1238*61046927SAndroid Build Coastguard Worker if (shift > 32) {
1239*61046927SAndroid Build Coastguard Worker struct mi_value tmp = mi_new_gpr(b);
1240*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(tmp, false),
1241*61046927SAndroid Build Coastguard Worker mi_value_half(src, true));
1242*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(tmp, true), mi_imm(0));
1243*61046927SAndroid Build Coastguard Worker mi_value_unref(b, src);
1244*61046927SAndroid Build Coastguard Worker src = tmp;
1245*61046927SAndroid Build Coastguard Worker shift -= 32;
1246*61046927SAndroid Build Coastguard Worker }
1247*61046927SAndroid Build Coastguard Worker assert(shift <= 32);
1248*61046927SAndroid Build Coastguard Worker struct mi_value tmp = mi_ishl_imm(b, src, 32 - shift);
1249*61046927SAndroid Build Coastguard Worker struct mi_value dst = mi_new_gpr(b);
1250*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, false),
1251*61046927SAndroid Build Coastguard Worker mi_value_half(tmp, true));
1252*61046927SAndroid Build Coastguard Worker _mi_copy_no_unref(b, mi_value_half(dst, true), mi_imm(0));
1253*61046927SAndroid Build Coastguard Worker mi_value_unref(b, tmp);
1254*61046927SAndroid Build Coastguard Worker return dst;
1255*61046927SAndroid Build Coastguard Worker }
1256*61046927SAndroid Build Coastguard Worker
1257*61046927SAndroid Build Coastguard Worker static inline struct mi_value
mi_udiv32_imm(struct mi_builder * b,struct mi_value N,uint32_t D)1258*61046927SAndroid Build Coastguard Worker mi_udiv32_imm(struct mi_builder *b, struct mi_value N, uint32_t D)
1259*61046927SAndroid Build Coastguard Worker {
1260*61046927SAndroid Build Coastguard Worker if (N.type == MI_VALUE_TYPE_IMM) {
1261*61046927SAndroid Build Coastguard Worker assert(mi_value_to_u64(N) <= UINT32_MAX);
1262*61046927SAndroid Build Coastguard Worker return mi_imm(mi_value_to_u64(N) / D);
1263*61046927SAndroid Build Coastguard Worker }
1264*61046927SAndroid Build Coastguard Worker
1265*61046927SAndroid Build Coastguard Worker /* We implicitly assume that N is only a 32-bit value */
1266*61046927SAndroid Build Coastguard Worker if (D == 0) {
1267*61046927SAndroid Build Coastguard Worker /* This is invalid but we should do something */
1268*61046927SAndroid Build Coastguard Worker return mi_imm(0);
1269*61046927SAndroid Build Coastguard Worker } else if (util_is_power_of_two_or_zero(D)) {
1270*61046927SAndroid Build Coastguard Worker return mi_ushr32_imm(b, N, util_logbase2(D));
1271*61046927SAndroid Build Coastguard Worker } else {
1272*61046927SAndroid Build Coastguard Worker struct util_fast_udiv_info m = util_compute_fast_udiv_info(D, 32, 32);
1273*61046927SAndroid Build Coastguard Worker assert(m.multiplier <= UINT32_MAX);
1274*61046927SAndroid Build Coastguard Worker
1275*61046927SAndroid Build Coastguard Worker if (m.pre_shift)
1276*61046927SAndroid Build Coastguard Worker N = mi_ushr32_imm(b, N, m.pre_shift);
1277*61046927SAndroid Build Coastguard Worker
1278*61046927SAndroid Build Coastguard Worker /* Do the 32x32 multiply into gpr0 */
1279*61046927SAndroid Build Coastguard Worker N = mi_imul_imm(b, N, m.multiplier);
1280*61046927SAndroid Build Coastguard Worker
1281*61046927SAndroid Build Coastguard Worker if (m.increment)
1282*61046927SAndroid Build Coastguard Worker N = mi_iadd(b, N, mi_imm(m.multiplier));
1283*61046927SAndroid Build Coastguard Worker
1284*61046927SAndroid Build Coastguard Worker N = mi_ushr32_imm(b, N, 32);
1285*61046927SAndroid Build Coastguard Worker
1286*61046927SAndroid Build Coastguard Worker if (m.post_shift)
1287*61046927SAndroid Build Coastguard Worker N = mi_ushr32_imm(b, N, m.post_shift);
1288*61046927SAndroid Build Coastguard Worker
1289*61046927SAndroid Build Coastguard Worker return N;
1290*61046927SAndroid Build Coastguard Worker }
1291*61046927SAndroid Build Coastguard Worker }
1292*61046927SAndroid Build Coastguard Worker
1293*61046927SAndroid Build Coastguard Worker #endif /* MI_MATH section */
1294*61046927SAndroid Build Coastguard Worker
1295*61046927SAndroid Build Coastguard Worker /* This assumes addresses of strictly more than 32bits (aka. Gfx8+). */
1296*61046927SAndroid Build Coastguard Worker #if MI_BUILDER_CAN_WRITE_BATCH
1297*61046927SAndroid Build Coastguard Worker
1298*61046927SAndroid Build Coastguard Worker struct mi_reloc_imm_token {
1299*61046927SAndroid Build Coastguard Worker enum mi_value_type dst_type;
1300*61046927SAndroid Build Coastguard Worker uint32_t *ptr[2];
1301*61046927SAndroid Build Coastguard Worker };
1302*61046927SAndroid Build Coastguard Worker
1303*61046927SAndroid Build Coastguard Worker /* Emits a immediate write to an address/register where the immediate value
1304*61046927SAndroid Build Coastguard Worker * can be updated later.
1305*61046927SAndroid Build Coastguard Worker */
1306*61046927SAndroid Build Coastguard Worker static inline struct mi_reloc_imm_token
mi_store_relocated_imm(struct mi_builder * b,struct mi_value dst)1307*61046927SAndroid Build Coastguard Worker mi_store_relocated_imm(struct mi_builder *b, struct mi_value dst)
1308*61046927SAndroid Build Coastguard Worker {
1309*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
1310*61046927SAndroid Build Coastguard Worker
1311*61046927SAndroid Build Coastguard Worker struct mi_reloc_imm_token token = {
1312*61046927SAndroid Build Coastguard Worker .dst_type = dst.type,
1313*61046927SAndroid Build Coastguard Worker };
1314*61046927SAndroid Build Coastguard Worker
1315*61046927SAndroid Build Coastguard Worker uint32_t *dw;
1316*61046927SAndroid Build Coastguard Worker switch (dst.type) {
1317*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
1318*61046927SAndroid Build Coastguard Worker dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
1319*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length));
1320*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_STORE_DATA_IMM), dw, sdm) {
1321*61046927SAndroid Build Coastguard Worker sdm.DWordLength = GENX(MI_STORE_DATA_IMM_length) -
1322*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length_bias);
1323*61046927SAndroid Build Coastguard Worker sdm.Address = dst.addr;
1324*61046927SAndroid Build Coastguard Worker }
1325*61046927SAndroid Build Coastguard Worker token.ptr[0] = dw + GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32;
1326*61046927SAndroid Build Coastguard Worker mi_builder_set_write(b);
1327*61046927SAndroid Build Coastguard Worker break;
1328*61046927SAndroid Build Coastguard Worker
1329*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
1330*61046927SAndroid Build Coastguard Worker dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
1331*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length) + 1);
1332*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_STORE_DATA_IMM), dw, sdm) {
1333*61046927SAndroid Build Coastguard Worker sdm.DWordLength = GENX(MI_STORE_DATA_IMM_length) + 1 -
1334*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_DATA_IMM_length_bias);
1335*61046927SAndroid Build Coastguard Worker sdm.Address = dst.addr;
1336*61046927SAndroid Build Coastguard Worker }
1337*61046927SAndroid Build Coastguard Worker token.ptr[0] = &dw[GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32];
1338*61046927SAndroid Build Coastguard Worker token.ptr[1] = &dw[GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32 + 1];
1339*61046927SAndroid Build Coastguard Worker mi_builder_set_write(b);
1340*61046927SAndroid Build Coastguard Worker break;
1341*61046927SAndroid Build Coastguard Worker
1342*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
1343*61046927SAndroid Build Coastguard Worker dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
1344*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length));
1345*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_LOAD_REGISTER_IMM), dw, lri) {
1346*61046927SAndroid Build Coastguard Worker lri.DWordLength = GENX(MI_LOAD_REGISTER_IMM_length) -
1347*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length_bias);
1348*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
1349*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
1350*61046927SAndroid Build Coastguard Worker lri.AddCSMMIOStartOffset = reg.cs;
1351*61046927SAndroid Build Coastguard Worker #endif
1352*61046927SAndroid Build Coastguard Worker lri.RegisterOffset = reg.num;
1353*61046927SAndroid Build Coastguard Worker }
1354*61046927SAndroid Build Coastguard Worker token.ptr[0] = &dw[2];
1355*61046927SAndroid Build Coastguard Worker break;
1356*61046927SAndroid Build Coastguard Worker
1357*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64: {
1358*61046927SAndroid Build Coastguard Worker dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
1359*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length) + 2);
1360*61046927SAndroid Build Coastguard Worker struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
1361*61046927SAndroid Build Coastguard Worker mi_builder_pack(b, GENX(MI_LOAD_REGISTER_IMM), dw, lri) {
1362*61046927SAndroid Build Coastguard Worker lri.DWordLength = GENX(MI_LOAD_REGISTER_IMM_length) + 2 -
1363*61046927SAndroid Build Coastguard Worker GENX(MI_LOAD_REGISTER_IMM_length_bias);
1364*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 11
1365*61046927SAndroid Build Coastguard Worker lri.AddCSMMIOStartOffset = reg.cs;
1366*61046927SAndroid Build Coastguard Worker #endif
1367*61046927SAndroid Build Coastguard Worker }
1368*61046927SAndroid Build Coastguard Worker dw[1] = reg.num;
1369*61046927SAndroid Build Coastguard Worker dw[3] = reg.num + 4;
1370*61046927SAndroid Build Coastguard Worker token.ptr[0] = &dw[2];
1371*61046927SAndroid Build Coastguard Worker token.ptr[1] = &dw[4];
1372*61046927SAndroid Build Coastguard Worker break;
1373*61046927SAndroid Build Coastguard Worker }
1374*61046927SAndroid Build Coastguard Worker
1375*61046927SAndroid Build Coastguard Worker default:
1376*61046927SAndroid Build Coastguard Worker unreachable("Invalid value type");
1377*61046927SAndroid Build Coastguard Worker }
1378*61046927SAndroid Build Coastguard Worker
1379*61046927SAndroid Build Coastguard Worker mi_value_unref(b, dst);
1380*61046927SAndroid Build Coastguard Worker return token;
1381*61046927SAndroid Build Coastguard Worker }
1382*61046927SAndroid Build Coastguard Worker
1383*61046927SAndroid Build Coastguard Worker static inline void
mi_relocate_store_imm(struct mi_reloc_imm_token token,uint64_t value)1384*61046927SAndroid Build Coastguard Worker mi_relocate_store_imm(struct mi_reloc_imm_token token, uint64_t value)
1385*61046927SAndroid Build Coastguard Worker {
1386*61046927SAndroid Build Coastguard Worker switch (token.dst_type) {
1387*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM64:
1388*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG64:
1389*61046927SAndroid Build Coastguard Worker *token.ptr[1] = value >> 32;
1390*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
1391*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_MEM32:
1392*61046927SAndroid Build Coastguard Worker case MI_VALUE_TYPE_REG32:
1393*61046927SAndroid Build Coastguard Worker *token.ptr[0] = value & 0xffffffff;
1394*61046927SAndroid Build Coastguard Worker break;
1395*61046927SAndroid Build Coastguard Worker default:
1396*61046927SAndroid Build Coastguard Worker unreachable("Invalid value type");
1397*61046927SAndroid Build Coastguard Worker }
1398*61046927SAndroid Build Coastguard Worker }
1399*61046927SAndroid Build Coastguard Worker
1400*61046927SAndroid Build Coastguard Worker struct mi_address_token {
1401*61046927SAndroid Build Coastguard Worker /* Pointers to address memory fields in the batch. */
1402*61046927SAndroid Build Coastguard Worker uint64_t *ptrs[2];
1403*61046927SAndroid Build Coastguard Worker };
1404*61046927SAndroid Build Coastguard Worker
1405*61046927SAndroid Build Coastguard Worker /* Emits a 64bit memory write to a yet unknown address using a value from a
1406*61046927SAndroid Build Coastguard Worker * register
1407*61046927SAndroid Build Coastguard Worker */
1408*61046927SAndroid Build Coastguard Worker static inline struct mi_address_token
mi_store_relocated_address_reg64(struct mi_builder * b,struct mi_value addr_reg)1409*61046927SAndroid Build Coastguard Worker mi_store_relocated_address_reg64(struct mi_builder *b, struct mi_value addr_reg)
1410*61046927SAndroid Build Coastguard Worker {
1411*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
1412*61046927SAndroid Build Coastguard Worker
1413*61046927SAndroid Build Coastguard Worker assert(addr_reg.type == MI_VALUE_TYPE_REG64);
1414*61046927SAndroid Build Coastguard Worker
1415*61046927SAndroid Build Coastguard Worker struct mi_address_token token = {};
1416*61046927SAndroid Build Coastguard Worker
1417*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 2; i++) {
1418*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
1419*61046927SAndroid Build Coastguard Worker srm.RegisterAddress = addr_reg.reg + (i * 4);
1420*61046927SAndroid Build Coastguard Worker
1421*61046927SAndroid Build Coastguard Worker const unsigned addr_dw =
1422*61046927SAndroid Build Coastguard Worker GENX(MI_STORE_REGISTER_MEM_MemoryAddress_start) / 8;
1423*61046927SAndroid Build Coastguard Worker token.ptrs[i] = (uint64_t *)(mi_builder_get_inst_ptr(_dst) + addr_dw);
1424*61046927SAndroid Build Coastguard Worker }
1425*61046927SAndroid Build Coastguard Worker }
1426*61046927SAndroid Build Coastguard Worker
1427*61046927SAndroid Build Coastguard Worker mi_builder_set_write(b);
1428*61046927SAndroid Build Coastguard Worker mi_value_unref(b, addr_reg);
1429*61046927SAndroid Build Coastguard Worker return token;
1430*61046927SAndroid Build Coastguard Worker }
1431*61046927SAndroid Build Coastguard Worker
1432*61046927SAndroid Build Coastguard Worker static inline void
mi_self_mod_barrier(struct mi_builder * b,unsigned cs_prefetch_size)1433*61046927SAndroid Build Coastguard Worker mi_self_mod_barrier(struct mi_builder *b, unsigned cs_prefetch_size)
1434*61046927SAndroid Build Coastguard Worker {
1435*61046927SAndroid Build Coastguard Worker /* First make sure all the memory writes from previous modifying commands
1436*61046927SAndroid Build Coastguard Worker * have landed. We want to do this before going through the CS cache,
1437*61046927SAndroid Build Coastguard Worker * otherwise we could be fetching memory that hasn't been written to yet.
1438*61046927SAndroid Build Coastguard Worker */
1439*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(PIPE_CONTROL), pc) {
1440*61046927SAndroid Build Coastguard Worker pc.CommandStreamerStallEnable = true;
1441*61046927SAndroid Build Coastguard Worker }
1442*61046927SAndroid Build Coastguard Worker /* Documentation says Gfx11+ should be able to invalidate the command cache
1443*61046927SAndroid Build Coastguard Worker * but experiment show it doesn't work properly, so for now just get over
1444*61046927SAndroid Build Coastguard Worker * the CS prefetch.
1445*61046927SAndroid Build Coastguard Worker */
1446*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < (cs_prefetch_size / 4); i++)
1447*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_NOOP), noop);
1448*61046927SAndroid Build Coastguard Worker }
1449*61046927SAndroid Build Coastguard Worker
1450*61046927SAndroid Build Coastguard Worker static inline void
mi_resolve_relocated_address_token(struct mi_builder * b,struct mi_address_token token,void * batch_location)1451*61046927SAndroid Build Coastguard Worker mi_resolve_relocated_address_token(struct mi_builder *b,
1452*61046927SAndroid Build Coastguard Worker struct mi_address_token token,
1453*61046927SAndroid Build Coastguard Worker void *batch_location)
1454*61046927SAndroid Build Coastguard Worker {
1455*61046927SAndroid Build Coastguard Worker __gen_address_type addr = __gen_get_batch_address(b->user_data,
1456*61046927SAndroid Build Coastguard Worker batch_location);
1457*61046927SAndroid Build Coastguard Worker uint64_t addr_addr_u64 = __gen_combine_address(b->user_data, batch_location,
1458*61046927SAndroid Build Coastguard Worker addr, 0);
1459*61046927SAndroid Build Coastguard Worker *(token.ptrs[0]) = addr_addr_u64;
1460*61046927SAndroid Build Coastguard Worker *(token.ptrs[1]) = addr_addr_u64 + 4;
1461*61046927SAndroid Build Coastguard Worker }
1462*61046927SAndroid Build Coastguard Worker
1463*61046927SAndroid Build Coastguard Worker #endif /* MI_BUILDER_CAN_WRITE_BATCH */
1464*61046927SAndroid Build Coastguard Worker
1465*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1466*61046927SAndroid Build Coastguard Worker
1467*61046927SAndroid Build Coastguard Worker /*
1468*61046927SAndroid Build Coastguard Worker * Indirect load/store. Only available on XE_HP+
1469*61046927SAndroid Build Coastguard Worker */
1470*61046927SAndroid Build Coastguard Worker
1471*61046927SAndroid Build Coastguard Worker MUST_CHECK static inline struct mi_value
mi_load_mem64_offset(struct mi_builder * b,__gen_address_type addr,struct mi_value offset)1472*61046927SAndroid Build Coastguard Worker mi_load_mem64_offset(struct mi_builder *b,
1473*61046927SAndroid Build Coastguard Worker __gen_address_type addr, struct mi_value offset)
1474*61046927SAndroid Build Coastguard Worker {
1475*61046927SAndroid Build Coastguard Worker mi_ensure_write_fence(b);
1476*61046927SAndroid Build Coastguard Worker
1477*61046927SAndroid Build Coastguard Worker uint64_t addr_u64 = __gen_combine_address(b->user_data, NULL, addr, 0);
1478*61046927SAndroid Build Coastguard Worker struct mi_value addr_val = mi_imm(addr_u64);
1479*61046927SAndroid Build Coastguard Worker
1480*61046927SAndroid Build Coastguard Worker struct mi_value dst = mi_new_gpr(b);
1481*61046927SAndroid Build Coastguard Worker
1482*61046927SAndroid Build Coastguard Worker uint32_t dw[5];
1483*61046927SAndroid Build Coastguard Worker dw[0] = _mi_math_load_src(b, MI_ALU_SRCA, &addr_val);
1484*61046927SAndroid Build Coastguard Worker dw[1] = _mi_math_load_src(b, MI_ALU_SRCB, &offset);
1485*61046927SAndroid Build Coastguard Worker dw[2] = _mi_pack_alu(MI_ALU_ADD, 0, 0);
1486*61046927SAndroid Build Coastguard Worker dw[3] = _mi_pack_alu(MI_ALU_LOADIND, _mi_value_as_gpr(dst), MI_ALU_ACCU);
1487*61046927SAndroid Build Coastguard Worker dw[4] = _mi_pack_alu(MI_ALU_FENCE_RD, 0, 0);
1488*61046927SAndroid Build Coastguard Worker _mi_builder_push_math(b, dw, 5);
1489*61046927SAndroid Build Coastguard Worker
1490*61046927SAndroid Build Coastguard Worker mi_value_unref(b, addr_val);
1491*61046927SAndroid Build Coastguard Worker mi_value_unref(b, offset);
1492*61046927SAndroid Build Coastguard Worker
1493*61046927SAndroid Build Coastguard Worker return dst;
1494*61046927SAndroid Build Coastguard Worker }
1495*61046927SAndroid Build Coastguard Worker
1496*61046927SAndroid Build Coastguard Worker static inline void
mi_store_mem64_offset(struct mi_builder * b,__gen_address_type addr,struct mi_value offset,struct mi_value data)1497*61046927SAndroid Build Coastguard Worker mi_store_mem64_offset(struct mi_builder *b,
1498*61046927SAndroid Build Coastguard Worker __gen_address_type addr, struct mi_value offset,
1499*61046927SAndroid Build Coastguard Worker struct mi_value data)
1500*61046927SAndroid Build Coastguard Worker {
1501*61046927SAndroid Build Coastguard Worker uint64_t addr_u64 = __gen_combine_address(b->user_data, NULL, addr, 0);
1502*61046927SAndroid Build Coastguard Worker struct mi_value addr_val = mi_imm(addr_u64);
1503*61046927SAndroid Build Coastguard Worker
1504*61046927SAndroid Build Coastguard Worker data = mi_value_to_gpr(b, mi_resolve_invert(b, data));
1505*61046927SAndroid Build Coastguard Worker
1506*61046927SAndroid Build Coastguard Worker uint32_t dw[5];
1507*61046927SAndroid Build Coastguard Worker dw[0] = _mi_math_load_src(b, MI_ALU_SRCA, &addr_val);
1508*61046927SAndroid Build Coastguard Worker dw[1] = _mi_math_load_src(b, MI_ALU_SRCB, &offset);
1509*61046927SAndroid Build Coastguard Worker dw[2] = _mi_pack_alu(MI_ALU_ADD, 0, 0);
1510*61046927SAndroid Build Coastguard Worker dw[3] = _mi_pack_alu(MI_ALU_STOREIND, MI_ALU_ACCU, _mi_value_as_gpr(data));
1511*61046927SAndroid Build Coastguard Worker dw[4] = _mi_pack_alu(MI_ALU_FENCE_WR, 0, 0);
1512*61046927SAndroid Build Coastguard Worker _mi_builder_push_math(b, dw, 5);
1513*61046927SAndroid Build Coastguard Worker
1514*61046927SAndroid Build Coastguard Worker mi_value_unref(b, addr_val);
1515*61046927SAndroid Build Coastguard Worker mi_value_unref(b, offset);
1516*61046927SAndroid Build Coastguard Worker mi_value_unref(b, data);
1517*61046927SAndroid Build Coastguard Worker
1518*61046927SAndroid Build Coastguard Worker /* This is the only math case which has side-effects outside of regular
1519*61046927SAndroid Build Coastguard Worker * registers to flush math afterwards so we don't confuse anyone.
1520*61046927SAndroid Build Coastguard Worker */
1521*61046927SAndroid Build Coastguard Worker mi_builder_flush_math(b);
1522*61046927SAndroid Build Coastguard Worker /* mi_builder_set_write() is not required here because we have a FENCE_WR
1523*61046927SAndroid Build Coastguard Worker * in the ALU instruction.
1524*61046927SAndroid Build Coastguard Worker */
1525*61046927SAndroid Build Coastguard Worker }
1526*61046927SAndroid Build Coastguard Worker
1527*61046927SAndroid Build Coastguard Worker #endif /* GFX_VERx10 >= 125 */
1528*61046927SAndroid Build Coastguard Worker
1529*61046927SAndroid Build Coastguard Worker #if GFX_VER >= 9
1530*61046927SAndroid Build Coastguard Worker
1531*61046927SAndroid Build Coastguard Worker /*
1532*61046927SAndroid Build Coastguard Worker * Control-flow Section. Only available on Gfx9+
1533*61046927SAndroid Build Coastguard Worker */
1534*61046927SAndroid Build Coastguard Worker
1535*61046927SAndroid Build Coastguard Worker struct _mi_goto {
1536*61046927SAndroid Build Coastguard Worker bool predicated;
1537*61046927SAndroid Build Coastguard Worker void *mi_bbs;
1538*61046927SAndroid Build Coastguard Worker };
1539*61046927SAndroid Build Coastguard Worker
1540*61046927SAndroid Build Coastguard Worker struct mi_goto_target {
1541*61046927SAndroid Build Coastguard Worker bool placed;
1542*61046927SAndroid Build Coastguard Worker unsigned num_gotos;
1543*61046927SAndroid Build Coastguard Worker struct _mi_goto gotos[8];
1544*61046927SAndroid Build Coastguard Worker __gen_address_type addr;
1545*61046927SAndroid Build Coastguard Worker };
1546*61046927SAndroid Build Coastguard Worker
1547*61046927SAndroid Build Coastguard Worker #define MI_GOTO_TARGET_INIT ((struct mi_goto_target) {})
1548*61046927SAndroid Build Coastguard Worker
1549*61046927SAndroid Build Coastguard Worker /* On >= Gfx12.5, the predication of MI_BATCH_BUFFER_START is driven by the
1550*61046927SAndroid Build Coastguard Worker * bit0 of the MI_SET_PREDICATE_RESULT register.
1551*61046927SAndroid Build Coastguard Worker *
1552*61046927SAndroid Build Coastguard Worker * ACM PRMs, Vol 2a: Command Reference: Instructions, MI_BATCH_BUFFER_START,
1553*61046927SAndroid Build Coastguard Worker * Predication Enable:
1554*61046927SAndroid Build Coastguard Worker *
1555*61046927SAndroid Build Coastguard Worker * "This bit is used to enable predication of this command. If this bit is
1556*61046927SAndroid Build Coastguard Worker * set and Bit 0 of the MI_SET_PREDICATE_RESULT register is set, this
1557*61046927SAndroid Build Coastguard Worker * command is ignored. Otherwise the command is performed normally."
1558*61046927SAndroid Build Coastguard Worker *
1559*61046927SAndroid Build Coastguard Worker * The register offset is not listed in the PRMs, but BSpec places it a
1560*61046927SAndroid Build Coastguard Worker * 0x2418.
1561*61046927SAndroid Build Coastguard Worker *
1562*61046927SAndroid Build Coastguard Worker * On < Gfx12.5, the predication of MI_BATCH_BUFFER_START is driven by the
1563*61046927SAndroid Build Coastguard Worker * bit0 of MI_PREDICATE_RESULT_1.
1564*61046927SAndroid Build Coastguard Worker *
1565*61046927SAndroid Build Coastguard Worker * SKL PRMs, Vol 2a: Command Reference: Instructions, MI_BATCH_BUFFER_START,
1566*61046927SAndroid Build Coastguard Worker * Predication Enable:
1567*61046927SAndroid Build Coastguard Worker *
1568*61046927SAndroid Build Coastguard Worker * "This bit is used to enable predication of this command. If this bit is
1569*61046927SAndroid Build Coastguard Worker * set and Bit 0 of the MI_PREDICATE_RESULT_1 register is clear, this
1570*61046927SAndroid Build Coastguard Worker * command is ignored. Otherwise the command is performed normally.
1571*61046927SAndroid Build Coastguard Worker * Specific to the Render command stream only."
1572*61046927SAndroid Build Coastguard Worker *
1573*61046927SAndroid Build Coastguard Worker * The register offset is listed in the SKL PRMs, Vol 2c: Command Reference:
1574*61046927SAndroid Build Coastguard Worker * Registers, MI_PREDICATE_RESULT_1, at 0x241C.
1575*61046927SAndroid Build Coastguard Worker */
1576*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1577*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_MI_PREDICATE_RESULT_num 0x2418
1578*61046927SAndroid Build Coastguard Worker #else
1579*61046927SAndroid Build Coastguard Worker #define MI_BUILDER_MI_PREDICATE_RESULT_num 0x241C
1580*61046927SAndroid Build Coastguard Worker #endif
1581*61046927SAndroid Build Coastguard Worker
1582*61046927SAndroid Build Coastguard Worker static inline void
mi_goto_if(struct mi_builder * b,struct mi_value cond,struct mi_goto_target * t)1583*61046927SAndroid Build Coastguard Worker mi_goto_if(struct mi_builder *b, struct mi_value cond,
1584*61046927SAndroid Build Coastguard Worker struct mi_goto_target *t)
1585*61046927SAndroid Build Coastguard Worker {
1586*61046927SAndroid Build Coastguard Worker /* First, set up the predicate, if any */
1587*61046927SAndroid Build Coastguard Worker bool predicated;
1588*61046927SAndroid Build Coastguard Worker if (cond.type == MI_VALUE_TYPE_IMM) {
1589*61046927SAndroid Build Coastguard Worker /* If it's an immediate, the goto either doesn't happen or happens
1590*61046927SAndroid Build Coastguard Worker * unconditionally.
1591*61046927SAndroid Build Coastguard Worker */
1592*61046927SAndroid Build Coastguard Worker if (mi_value_to_u64(cond) == 0)
1593*61046927SAndroid Build Coastguard Worker return;
1594*61046927SAndroid Build Coastguard Worker
1595*61046927SAndroid Build Coastguard Worker assert(mi_value_to_u64(cond) == ~0ull);
1596*61046927SAndroid Build Coastguard Worker predicated = false;
1597*61046927SAndroid Build Coastguard Worker } else if (mi_value_is_reg(cond) &&
1598*61046927SAndroid Build Coastguard Worker cond.reg == MI_BUILDER_MI_PREDICATE_RESULT_num) {
1599*61046927SAndroid Build Coastguard Worker /* If it's MI_PREDICATE_RESULT, we use whatever predicate the client
1600*61046927SAndroid Build Coastguard Worker * provided us with
1601*61046927SAndroid Build Coastguard Worker */
1602*61046927SAndroid Build Coastguard Worker assert(cond.type == MI_VALUE_TYPE_REG32);
1603*61046927SAndroid Build Coastguard Worker predicated = true;
1604*61046927SAndroid Build Coastguard Worker } else {
1605*61046927SAndroid Build Coastguard Worker mi_store(b, mi_reg32(MI_BUILDER_MI_PREDICATE_RESULT_num), cond);
1606*61046927SAndroid Build Coastguard Worker predicated = true;
1607*61046927SAndroid Build Coastguard Worker }
1608*61046927SAndroid Build Coastguard Worker
1609*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1610*61046927SAndroid Build Coastguard Worker if (predicated) {
1611*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_SET_PREDICATE), sp) {
1612*61046927SAndroid Build Coastguard Worker sp.PredicateEnable = NOOPOnResultClear;
1613*61046927SAndroid Build Coastguard Worker }
1614*61046927SAndroid Build Coastguard Worker }
1615*61046927SAndroid Build Coastguard Worker #endif
1616*61046927SAndroid Build Coastguard Worker if (t->placed) {
1617*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_BATCH_BUFFER_START), bbs) {
1618*61046927SAndroid Build Coastguard Worker bbs.PredicationEnable = predicated;
1619*61046927SAndroid Build Coastguard Worker bbs.AddressSpaceIndicator = ASI_PPGTT;
1620*61046927SAndroid Build Coastguard Worker bbs.BatchBufferStartAddress = t->addr;
1621*61046927SAndroid Build Coastguard Worker }
1622*61046927SAndroid Build Coastguard Worker } else {
1623*61046927SAndroid Build Coastguard Worker assert(t->num_gotos < ARRAY_SIZE(t->gotos));
1624*61046927SAndroid Build Coastguard Worker struct _mi_goto g = {
1625*61046927SAndroid Build Coastguard Worker .predicated = predicated,
1626*61046927SAndroid Build Coastguard Worker .mi_bbs = __gen_get_batch_dwords(b->user_data,
1627*61046927SAndroid Build Coastguard Worker GENX(MI_BATCH_BUFFER_START_length)),
1628*61046927SAndroid Build Coastguard Worker };
1629*61046927SAndroid Build Coastguard Worker memset(g.mi_bbs, 0, 4 * GENX(MI_BATCH_BUFFER_START_length));
1630*61046927SAndroid Build Coastguard Worker t->gotos[t->num_gotos++] = g;
1631*61046927SAndroid Build Coastguard Worker }
1632*61046927SAndroid Build Coastguard Worker if (predicated) {
1633*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1634*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_SET_PREDICATE), sp) {
1635*61046927SAndroid Build Coastguard Worker sp.PredicateEnable = NOOPNever;
1636*61046927SAndroid Build Coastguard Worker }
1637*61046927SAndroid Build Coastguard Worker #else
1638*61046927SAndroid Build Coastguard Worker mi_store(b, mi_reg32(MI_BUILDER_MI_PREDICATE_RESULT_num), mi_imm(0));
1639*61046927SAndroid Build Coastguard Worker #endif
1640*61046927SAndroid Build Coastguard Worker }
1641*61046927SAndroid Build Coastguard Worker }
1642*61046927SAndroid Build Coastguard Worker
1643*61046927SAndroid Build Coastguard Worker static inline void
mi_goto(struct mi_builder * b,struct mi_goto_target * t)1644*61046927SAndroid Build Coastguard Worker mi_goto(struct mi_builder *b, struct mi_goto_target *t)
1645*61046927SAndroid Build Coastguard Worker {
1646*61046927SAndroid Build Coastguard Worker mi_goto_if(b, mi_imm(-1), t);
1647*61046927SAndroid Build Coastguard Worker }
1648*61046927SAndroid Build Coastguard Worker
1649*61046927SAndroid Build Coastguard Worker static inline void
mi_goto_target(struct mi_builder * b,struct mi_goto_target * t)1650*61046927SAndroid Build Coastguard Worker mi_goto_target(struct mi_builder *b, struct mi_goto_target *t)
1651*61046927SAndroid Build Coastguard Worker {
1652*61046927SAndroid Build Coastguard Worker #if GFX_VERx10 >= 125
1653*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_SET_PREDICATE), sp) {
1654*61046927SAndroid Build Coastguard Worker sp.PredicateEnable = NOOPNever;
1655*61046927SAndroid Build Coastguard Worker t->addr = __gen_get_batch_address(b->user_data,
1656*61046927SAndroid Build Coastguard Worker mi_builder_get_inst_ptr(b));
1657*61046927SAndroid Build Coastguard Worker }
1658*61046927SAndroid Build Coastguard Worker #else
1659*61046927SAndroid Build Coastguard Worker mi_builder_emit(b, GENX(MI_NOOP), sp) {
1660*61046927SAndroid Build Coastguard Worker t->addr = __gen_get_batch_address(b->user_data,
1661*61046927SAndroid Build Coastguard Worker mi_builder_get_inst_ptr(b));
1662*61046927SAndroid Build Coastguard Worker }
1663*61046927SAndroid Build Coastguard Worker mi_store(b, mi_reg32(MI_BUILDER_MI_PREDICATE_RESULT_num), mi_imm(0));
1664*61046927SAndroid Build Coastguard Worker #endif
1665*61046927SAndroid Build Coastguard Worker t->placed = true;
1666*61046927SAndroid Build Coastguard Worker
1667*61046927SAndroid Build Coastguard Worker struct GENX(MI_BATCH_BUFFER_START) bbs = { GENX(MI_BATCH_BUFFER_START_header) };
1668*61046927SAndroid Build Coastguard Worker bbs.AddressSpaceIndicator = ASI_PPGTT;
1669*61046927SAndroid Build Coastguard Worker bbs.BatchBufferStartAddress = t->addr;
1670*61046927SAndroid Build Coastguard Worker
1671*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < t->num_gotos; i++) {
1672*61046927SAndroid Build Coastguard Worker bbs.PredicationEnable = t->gotos[i].predicated;
1673*61046927SAndroid Build Coastguard Worker GENX(MI_BATCH_BUFFER_START_pack)(b->user_data, t->gotos[i].mi_bbs, &bbs);
1674*61046927SAndroid Build Coastguard Worker }
1675*61046927SAndroid Build Coastguard Worker }
1676*61046927SAndroid Build Coastguard Worker
1677*61046927SAndroid Build Coastguard Worker static inline struct mi_goto_target
mi_goto_target_init_and_place(struct mi_builder * b)1678*61046927SAndroid Build Coastguard Worker mi_goto_target_init_and_place(struct mi_builder *b)
1679*61046927SAndroid Build Coastguard Worker {
1680*61046927SAndroid Build Coastguard Worker struct mi_goto_target t = MI_GOTO_TARGET_INIT;
1681*61046927SAndroid Build Coastguard Worker mi_goto_target(b, &t);
1682*61046927SAndroid Build Coastguard Worker return t;
1683*61046927SAndroid Build Coastguard Worker }
1684*61046927SAndroid Build Coastguard Worker
1685*61046927SAndroid Build Coastguard Worker #define mi_loop(b) \
1686*61046927SAndroid Build Coastguard Worker for (struct mi_goto_target __break = MI_GOTO_TARGET_INIT, \
1687*61046927SAndroid Build Coastguard Worker __continue = mi_goto_target_init_and_place(b); !__break.placed; \
1688*61046927SAndroid Build Coastguard Worker mi_goto(b, &__continue), mi_goto_target(b, &__break))
1689*61046927SAndroid Build Coastguard Worker
1690*61046927SAndroid Build Coastguard Worker #define mi_break(b) mi_goto(b, &__break)
1691*61046927SAndroid Build Coastguard Worker #define mi_break_if(b, cond) mi_goto_if(b, cond, &__break)
1692*61046927SAndroid Build Coastguard Worker #define mi_continue(b) mi_goto(b, &__continue)
1693*61046927SAndroid Build Coastguard Worker #define mi_continue_if(b, cond) mi_goto_if(b, cond, &__continue)
1694*61046927SAndroid Build Coastguard Worker
1695*61046927SAndroid Build Coastguard Worker #endif /* GFX_VER >= 9 */
1696*61046927SAndroid Build Coastguard Worker
1697*61046927SAndroid Build Coastguard Worker #endif /* MI_BUILDER_H */
1698