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