1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2020 Google, Inc.
3*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker */
5*61046927SAndroid Build Coastguard Worker
6*61046927SAndroid Build Coastguard Worker #include <err.h>
7*61046927SAndroid Build Coastguard Worker #include <stdio.h>
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Worker #include "ir3.h"
10*61046927SAndroid Build Coastguard Worker #include "ir3_assembler.h"
11*61046927SAndroid Build Coastguard Worker #include "ir3_shader.h"
12*61046927SAndroid Build Coastguard Worker
13*61046927SAndroid Build Coastguard Worker /*
14*61046927SAndroid Build Coastguard Worker * A test for delay-slot calculation. Each test specifies ir3 assembly
15*61046927SAndroid Build Coastguard Worker * for one or more instructions and the last instruction that consumes
16*61046927SAndroid Build Coastguard Worker * the previously produced values. And the expected number of delay
17*61046927SAndroid Build Coastguard Worker * slots that would be needed before that last instruction. Any source
18*61046927SAndroid Build Coastguard Worker * registers in the last instruction which are not written in a previous
19*61046927SAndroid Build Coastguard Worker * instruction are not counted.
20*61046927SAndroid Build Coastguard Worker */
21*61046927SAndroid Build Coastguard Worker
22*61046927SAndroid Build Coastguard Worker /* clang-format off */
23*61046927SAndroid Build Coastguard Worker #define TEST(n, ...) { # __VA_ARGS__, n }
24*61046927SAndroid Build Coastguard Worker /* clang-format on */
25*61046927SAndroid Build Coastguard Worker
26*61046927SAndroid Build Coastguard Worker static const struct test {
27*61046927SAndroid Build Coastguard Worker const char *asmstr;
28*61046927SAndroid Build Coastguard Worker unsigned expected_delay;
29*61046927SAndroid Build Coastguard Worker } tests[] = {
30*61046927SAndroid Build Coastguard Worker /* clang-format off */
31*61046927SAndroid Build Coastguard Worker TEST(6,
32*61046927SAndroid Build Coastguard Worker add.f r0.x, r2.x, r2.y
33*61046927SAndroid Build Coastguard Worker rsq r0.x, r0.x
34*61046927SAndroid Build Coastguard Worker ),
35*61046927SAndroid Build Coastguard Worker TEST(3,
36*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.x, c0.x
37*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.y, c0.y
38*61046927SAndroid Build Coastguard Worker add.f r0.x, r0.x, r0.y
39*61046927SAndroid Build Coastguard Worker ),
40*61046927SAndroid Build Coastguard Worker TEST(2,
41*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.x, c0.x
42*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.y, c0.y
43*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.z, c0.z
44*61046927SAndroid Build Coastguard Worker mad.f32 r0.x, r0.x, r0.y, r0.z
45*61046927SAndroid Build Coastguard Worker ),
46*61046927SAndroid Build Coastguard Worker TEST(0,
47*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.x, c0.x
48*61046927SAndroid Build Coastguard Worker rcp r0.x, r0.y
49*61046927SAndroid Build Coastguard Worker add.f r0.x, r0.x, c0.x
50*61046927SAndroid Build Coastguard Worker ),
51*61046927SAndroid Build Coastguard Worker TEST(2,
52*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.x, c0.x
53*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.y, c0.y
54*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
55*61046927SAndroid Build Coastguard Worker ),
56*61046927SAndroid Build Coastguard Worker TEST(2,
57*61046927SAndroid Build Coastguard Worker (rpt1)mov.f32f32 r0.x, c0.x
58*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
59*61046927SAndroid Build Coastguard Worker ),
60*61046927SAndroid Build Coastguard Worker TEST(3,
61*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.y, c0.y
62*61046927SAndroid Build Coastguard Worker mov.f32f32 r0.x, c0.x
63*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
64*61046927SAndroid Build Coastguard Worker ),
65*61046927SAndroid Build Coastguard Worker TEST(1,
66*61046927SAndroid Build Coastguard Worker (rpt2)mov.f32f32 r0.x, (r)c0.x
67*61046927SAndroid Build Coastguard Worker add.f r0.x, r0.x, c0.x
68*61046927SAndroid Build Coastguard Worker ),
69*61046927SAndroid Build Coastguard Worker TEST(2,
70*61046927SAndroid Build Coastguard Worker (rpt2)mov.f32f32 r0.x, (r)c0.x
71*61046927SAndroid Build Coastguard Worker add.f r0.x, r0.x, r0.y
72*61046927SAndroid Build Coastguard Worker ),
73*61046927SAndroid Build Coastguard Worker TEST(2,
74*61046927SAndroid Build Coastguard Worker (rpt1)mov.f32f32 r0.x, (r)c0.x
75*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.x, c0.x
76*61046927SAndroid Build Coastguard Worker ),
77*61046927SAndroid Build Coastguard Worker TEST(1,
78*61046927SAndroid Build Coastguard Worker (rpt1)mov.f32f32 r0.y, (r)c0.x
79*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.x, c0.x
80*61046927SAndroid Build Coastguard Worker ),
81*61046927SAndroid Build Coastguard Worker TEST(3,
82*61046927SAndroid Build Coastguard Worker (rpt1)mov.f32f32 r0.x, (r)c0.x
83*61046927SAndroid Build Coastguard Worker (rpt1)add.f r0.x, (r)r0.y, c0.x
84*61046927SAndroid Build Coastguard Worker ),
85*61046927SAndroid Build Coastguard Worker /* clang-format on */
86*61046927SAndroid Build Coastguard Worker };
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Worker static struct ir3_shader *
parse_asm(struct ir3_compiler * c,const char * asmstr)89*61046927SAndroid Build Coastguard Worker parse_asm(struct ir3_compiler *c, const char *asmstr)
90*61046927SAndroid Build Coastguard Worker {
91*61046927SAndroid Build Coastguard Worker struct ir3_kernel_info info = {};
92*61046927SAndroid Build Coastguard Worker FILE *in = fmemopen((void *)asmstr, strlen(asmstr), "r");
93*61046927SAndroid Build Coastguard Worker struct ir3_shader *shader = ir3_parse_asm(c, &info, in);
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker fclose(in);
96*61046927SAndroid Build Coastguard Worker
97*61046927SAndroid Build Coastguard Worker if (!shader)
98*61046927SAndroid Build Coastguard Worker errx(-1, "assembler failed");
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker return shader;
101*61046927SAndroid Build Coastguard Worker }
102*61046927SAndroid Build Coastguard Worker
103*61046927SAndroid Build Coastguard Worker /**
104*61046927SAndroid Build Coastguard Worker * ir3_delay_calc_* relies on the src/dst wrmask being correct even for ALU
105*61046927SAndroid Build Coastguard Worker * instructions, so this sets it here.
106*61046927SAndroid Build Coastguard Worker *
107*61046927SAndroid Build Coastguard Worker * Note that this is not clever enough to know how many src/dst there are
108*61046927SAndroid Build Coastguard Worker * for various tex/mem instructions. But the rules for tex consuming alu
109*61046927SAndroid Build Coastguard Worker * are the same as sfu consuming alu.
110*61046927SAndroid Build Coastguard Worker */
111*61046927SAndroid Build Coastguard Worker static void
fixup_wrmask(struct ir3 * ir)112*61046927SAndroid Build Coastguard Worker fixup_wrmask(struct ir3 *ir)
113*61046927SAndroid Build Coastguard Worker {
114*61046927SAndroid Build Coastguard Worker struct ir3_block *block = ir3_start_block(ir);
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker foreach_instr_safe (instr, &block->instr_list) {
117*61046927SAndroid Build Coastguard Worker instr->dsts[0]->wrmask = MASK(instr->repeat + 1);
118*61046927SAndroid Build Coastguard Worker foreach_src (reg, instr) {
119*61046927SAndroid Build Coastguard Worker if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED))
120*61046927SAndroid Build Coastguard Worker continue;
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker if (reg->flags & IR3_REG_R)
123*61046927SAndroid Build Coastguard Worker reg->wrmask = MASK(instr->repeat + 1);
124*61046927SAndroid Build Coastguard Worker else
125*61046927SAndroid Build Coastguard Worker reg->wrmask = 1;
126*61046927SAndroid Build Coastguard Worker }
127*61046927SAndroid Build Coastguard Worker }
128*61046927SAndroid Build Coastguard Worker }
129*61046927SAndroid Build Coastguard Worker
130*61046927SAndroid Build Coastguard Worker /* Calculate the number of nops added before the last instruction by
131*61046927SAndroid Build Coastguard Worker * ir3_legalize.
132*61046927SAndroid Build Coastguard Worker */
133*61046927SAndroid Build Coastguard Worker static unsigned
calc_nops(struct ir3_block * block,struct ir3_instruction * last)134*61046927SAndroid Build Coastguard Worker calc_nops(struct ir3_block *block, struct ir3_instruction *last)
135*61046927SAndroid Build Coastguard Worker {
136*61046927SAndroid Build Coastguard Worker unsigned nops = 0;
137*61046927SAndroid Build Coastguard Worker
138*61046927SAndroid Build Coastguard Worker foreach_instr_rev (instr, &block->instr_list) {
139*61046927SAndroid Build Coastguard Worker if (instr == last)
140*61046927SAndroid Build Coastguard Worker continue;
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker if (instr->opc == OPC_NOP) {
143*61046927SAndroid Build Coastguard Worker nops += 1 + instr->repeat;
144*61046927SAndroid Build Coastguard Worker } else {
145*61046927SAndroid Build Coastguard Worker if (is_alu(instr))
146*61046927SAndroid Build Coastguard Worker nops += instr->nop;
147*61046927SAndroid Build Coastguard Worker break;
148*61046927SAndroid Build Coastguard Worker }
149*61046927SAndroid Build Coastguard Worker }
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker return nops;
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker int
main(int argc,char ** argv)155*61046927SAndroid Build Coastguard Worker main(int argc, char **argv)
156*61046927SAndroid Build Coastguard Worker {
157*61046927SAndroid Build Coastguard Worker struct ir3_compiler *c;
158*61046927SAndroid Build Coastguard Worker int result = 0;
159*61046927SAndroid Build Coastguard Worker
160*61046927SAndroid Build Coastguard Worker struct fd_dev_id dev_id = {
161*61046927SAndroid Build Coastguard Worker .gpu_id = 630,
162*61046927SAndroid Build Coastguard Worker };
163*61046927SAndroid Build Coastguard Worker
164*61046927SAndroid Build Coastguard Worker c = ir3_compiler_create(NULL, &dev_id, fd_dev_info_raw(&dev_id), &(struct ir3_compiler_options){});
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker for (int i = 0; i < ARRAY_SIZE(tests); i++) {
167*61046927SAndroid Build Coastguard Worker const struct test *test = &tests[i];
168*61046927SAndroid Build Coastguard Worker struct ir3_shader *shader = parse_asm(c, test->asmstr);
169*61046927SAndroid Build Coastguard Worker struct ir3 *ir = shader->variants->ir;
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker fixup_wrmask(ir);
172*61046927SAndroid Build Coastguard Worker
173*61046927SAndroid Build Coastguard Worker ir3_debug_print(ir, "AFTER fixup_wrmask");
174*61046927SAndroid Build Coastguard Worker
175*61046927SAndroid Build Coastguard Worker struct ir3_block *block =
176*61046927SAndroid Build Coastguard Worker list_first_entry(&ir->block_list, struct ir3_block, node);
177*61046927SAndroid Build Coastguard Worker struct ir3_instruction *last = NULL;
178*61046927SAndroid Build Coastguard Worker
179*61046927SAndroid Build Coastguard Worker foreach_instr_rev (instr, &block->instr_list) {
180*61046927SAndroid Build Coastguard Worker if (is_meta(instr))
181*61046927SAndroid Build Coastguard Worker continue;
182*61046927SAndroid Build Coastguard Worker last = instr;
183*61046927SAndroid Build Coastguard Worker break;
184*61046927SAndroid Build Coastguard Worker }
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker int max_bary;
187*61046927SAndroid Build Coastguard Worker ir3_legalize(ir, shader->variants, &max_bary);
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker unsigned n = calc_nops(block, last);
190*61046927SAndroid Build Coastguard Worker
191*61046927SAndroid Build Coastguard Worker if (n != test->expected_delay) {
192*61046927SAndroid Build Coastguard Worker printf("%d: FAIL: Expected delay %u, but got %u, for:\n%s\n", i,
193*61046927SAndroid Build Coastguard Worker test->expected_delay, n, test->asmstr);
194*61046927SAndroid Build Coastguard Worker result = -1;
195*61046927SAndroid Build Coastguard Worker } else {
196*61046927SAndroid Build Coastguard Worker printf("%d: PASS\n", i);
197*61046927SAndroid Build Coastguard Worker }
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker ir3_shader_destroy(shader);
200*61046927SAndroid Build Coastguard Worker }
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker ir3_compiler_destroy(c);
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Worker return result;
205*61046927SAndroid Build Coastguard Worker }
206