1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <err.h>
25bf215546Sopenharmony_ci#include <stdio.h>
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "ir3.h"
28bf215546Sopenharmony_ci#include "ir3_assembler.h"
29bf215546Sopenharmony_ci#include "ir3_shader.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci/*
32bf215546Sopenharmony_ci * A test for delay-slot calculation.  Each test specifies ir3 assembly
33bf215546Sopenharmony_ci * for one or more instructions and the last instruction that consumes
34bf215546Sopenharmony_ci * the previously produced values.  And the expected number of delay
35bf215546Sopenharmony_ci * slots that would be needed before that last instruction.  Any source
36bf215546Sopenharmony_ci * registers in the last instruction which are not written in a previous
37bf215546Sopenharmony_ci * instruction are not counted.
38bf215546Sopenharmony_ci */
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci/* clang-format off */
41bf215546Sopenharmony_ci#define TEST(n, ...) { # __VA_ARGS__, n }
42bf215546Sopenharmony_ci/* clang-format on */
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_cistatic const struct test {
45bf215546Sopenharmony_ci   const char *asmstr;
46bf215546Sopenharmony_ci   unsigned expected_delay;
47bf215546Sopenharmony_ci} tests[] = {
48bf215546Sopenharmony_ci   /* clang-format off */
49bf215546Sopenharmony_ci   TEST(6,
50bf215546Sopenharmony_ci      add.f r0.x, r2.x, r2.y
51bf215546Sopenharmony_ci      rsq r0.x, r0.x
52bf215546Sopenharmony_ci   ),
53bf215546Sopenharmony_ci   TEST(3,
54bf215546Sopenharmony_ci      mov.f32f32 r0.x, c0.x
55bf215546Sopenharmony_ci      mov.f32f32 r0.y, c0.y
56bf215546Sopenharmony_ci      add.f r0.x, r0.x, r0.y
57bf215546Sopenharmony_ci   ),
58bf215546Sopenharmony_ci   TEST(2,
59bf215546Sopenharmony_ci      mov.f32f32 r0.x, c0.x
60bf215546Sopenharmony_ci      mov.f32f32 r0.y, c0.y
61bf215546Sopenharmony_ci      mov.f32f32 r0.z, c0.z
62bf215546Sopenharmony_ci      mad.f32 r0.x, r0.x, r0.y, r0.z
63bf215546Sopenharmony_ci   ),
64bf215546Sopenharmony_ci   TEST(0,
65bf215546Sopenharmony_ci      mov.f32f32 r0.x, c0.x
66bf215546Sopenharmony_ci      rcp r0.x, r0.y
67bf215546Sopenharmony_ci      add.f r0.x, r0.x, c0.x
68bf215546Sopenharmony_ci   ),
69bf215546Sopenharmony_ci   TEST(2,
70bf215546Sopenharmony_ci      mov.f32f32 r0.x, c0.x
71bf215546Sopenharmony_ci      mov.f32f32 r0.y, c0.y
72bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
73bf215546Sopenharmony_ci   ),
74bf215546Sopenharmony_ci   TEST(2,
75bf215546Sopenharmony_ci      (rpt1)mov.f32f32 r0.x, c0.x
76bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
77bf215546Sopenharmony_ci   ),
78bf215546Sopenharmony_ci   TEST(3,
79bf215546Sopenharmony_ci      mov.f32f32 r0.y, c0.y
80bf215546Sopenharmony_ci      mov.f32f32 r0.x, c0.x
81bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.x, (r)c0.x
82bf215546Sopenharmony_ci   ),
83bf215546Sopenharmony_ci   TEST(1,
84bf215546Sopenharmony_ci      (rpt2)mov.f32f32 r0.x, (r)c0.x
85bf215546Sopenharmony_ci      add.f r0.x, r0.x, c0.x
86bf215546Sopenharmony_ci   ),
87bf215546Sopenharmony_ci   TEST(2,
88bf215546Sopenharmony_ci      (rpt2)mov.f32f32 r0.x, (r)c0.x
89bf215546Sopenharmony_ci      add.f r0.x, r0.x, r0.y
90bf215546Sopenharmony_ci   ),
91bf215546Sopenharmony_ci   TEST(2,
92bf215546Sopenharmony_ci      (rpt1)mov.f32f32 r0.x, (r)c0.x
93bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.x, c0.x
94bf215546Sopenharmony_ci   ),
95bf215546Sopenharmony_ci   TEST(1,
96bf215546Sopenharmony_ci      (rpt1)mov.f32f32 r0.y, (r)c0.x
97bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.x, c0.x
98bf215546Sopenharmony_ci   ),
99bf215546Sopenharmony_ci   TEST(3,
100bf215546Sopenharmony_ci      (rpt1)mov.f32f32 r0.x, (r)c0.x
101bf215546Sopenharmony_ci      (rpt1)add.f r0.x, (r)r0.y, c0.x
102bf215546Sopenharmony_ci   ),
103bf215546Sopenharmony_ci   /* clang-format on */
104bf215546Sopenharmony_ci};
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_cistatic struct ir3_shader *
107bf215546Sopenharmony_ciparse_asm(struct ir3_compiler *c, const char *asmstr)
108bf215546Sopenharmony_ci{
109bf215546Sopenharmony_ci   struct ir3_kernel_info info = {};
110bf215546Sopenharmony_ci   FILE *in = fmemopen((void *)asmstr, strlen(asmstr), "r");
111bf215546Sopenharmony_ci   struct ir3_shader *shader = ir3_parse_asm(c, &info, in);
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   fclose(in);
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   if (!shader)
116bf215546Sopenharmony_ci      errx(-1, "assembler failed");
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   return shader;
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci/**
122bf215546Sopenharmony_ci * ir3_delay_calc_* relies on the src/dst wrmask being correct even for ALU
123bf215546Sopenharmony_ci * instructions, so this sets it here.
124bf215546Sopenharmony_ci *
125bf215546Sopenharmony_ci * Note that this is not clever enough to know how many src/dst there are
126bf215546Sopenharmony_ci * for various tex/mem instructions.  But the rules for tex consuming alu
127bf215546Sopenharmony_ci * are the same as sfu consuming alu.
128bf215546Sopenharmony_ci */
129bf215546Sopenharmony_cistatic void
130bf215546Sopenharmony_cifixup_wrmask(struct ir3 *ir)
131bf215546Sopenharmony_ci{
132bf215546Sopenharmony_ci   struct ir3_block *block = ir3_start_block(ir);
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   foreach_instr_safe (instr, &block->instr_list) {
135bf215546Sopenharmony_ci      instr->dsts[0]->wrmask = MASK(instr->repeat + 1);
136bf215546Sopenharmony_ci      foreach_src (reg, instr) {
137bf215546Sopenharmony_ci         if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED))
138bf215546Sopenharmony_ci            continue;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci         if (reg->flags & IR3_REG_R)
141bf215546Sopenharmony_ci            reg->wrmask = MASK(instr->repeat + 1);
142bf215546Sopenharmony_ci         else
143bf215546Sopenharmony_ci            reg->wrmask = 1;
144bf215546Sopenharmony_ci      }
145bf215546Sopenharmony_ci   }
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ciint
149bf215546Sopenharmony_cimain(int argc, char **argv)
150bf215546Sopenharmony_ci{
151bf215546Sopenharmony_ci   struct ir3_compiler *c;
152bf215546Sopenharmony_ci   int result = 0;
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   struct fd_dev_id dev_id = {
155bf215546Sopenharmony_ci         .gpu_id = 630,
156bf215546Sopenharmony_ci   };
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   c = ir3_compiler_create(NULL, &dev_id, &(struct ir3_compiler_options){});
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   for (int i = 0; i < ARRAY_SIZE(tests); i++) {
161bf215546Sopenharmony_ci      const struct test *test = &tests[i];
162bf215546Sopenharmony_ci      struct ir3_shader *shader = parse_asm(c, test->asmstr);
163bf215546Sopenharmony_ci      struct ir3 *ir = shader->variants->ir;
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci      fixup_wrmask(ir);
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci      ir3_debug_print(ir, "AFTER fixup_wrmask");
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci      struct ir3_block *block =
170bf215546Sopenharmony_ci         list_first_entry(&ir->block_list, struct ir3_block, node);
171bf215546Sopenharmony_ci      struct ir3_instruction *last = NULL;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci      foreach_instr_rev (instr, &block->instr_list) {
174bf215546Sopenharmony_ci         if (is_meta(instr))
175bf215546Sopenharmony_ci            continue;
176bf215546Sopenharmony_ci         last = instr;
177bf215546Sopenharmony_ci         break;
178bf215546Sopenharmony_ci      }
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci      /* The delay calc is expecting the instr to not yet be added to the
181bf215546Sopenharmony_ci       * block, so remove it from the block so that it doesn't get counted
182bf215546Sopenharmony_ci       * in the distance from assigner:
183bf215546Sopenharmony_ci       */
184bf215546Sopenharmony_ci      list_delinit(&last->node);
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci      unsigned n = ir3_delay_calc(block, last, true);
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci      if (n != test->expected_delay) {
189bf215546Sopenharmony_ci         printf("%d: FAIL: Expected delay %u, but got %u, for:\n%s\n", i,
190bf215546Sopenharmony_ci                test->expected_delay, n, test->asmstr);
191bf215546Sopenharmony_ci         result = -1;
192bf215546Sopenharmony_ci      } else {
193bf215546Sopenharmony_ci         printf("%d: PASS\n", i);
194bf215546Sopenharmony_ci      }
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci      ir3_shader_destroy(shader);
197bf215546Sopenharmony_ci   }
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   ir3_compiler_destroy(c);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   return result;
202bf215546Sopenharmony_ci}
203