1/* 2 * Copyright (C) 2021 Collabora Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "va_compiler.h" 25#include "valhall.h" 26#include "bi_builder.h" 27 28/* Valhall has limits on access to fast-access uniforms: 29 * 30 * An instruction may access no more than a single 64-bit uniform slot. 31 * An instruction may access no more than 64-bits of combined uniforms and constants. 32 * An instruction may access no more than a single special immediate (e.g. lane_id). 33 * 34 * We validate these constraints. 35 * 36 * An instruction may only access a single page of (special or uniform) FAU. 37 * This constraint does not need explicit validation: since FAU slots are 38 * naturally aligned, they never cross page boundaries, so this condition is 39 * implied by only acesssing a single 64-bit slot. 40 */ 41 42struct fau_state { 43 signed uniform_slot; 44 bi_index buffer[2]; 45}; 46 47static bool 48fau_state_buffer(struct fau_state *fau, bi_index idx) 49{ 50 for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) { 51 if (bi_is_word_equiv(fau->buffer[i], idx)) 52 return true; 53 else if (bi_is_null(fau->buffer[i])) { 54 fau->buffer[i] = idx; 55 return true; 56 } 57 } 58 59 return false; 60} 61 62static bool 63fau_state_uniform(struct fau_state *fau, bi_index idx) 64{ 65 /* Each slot is 64-bits. The low/high half is encoded as the offset of the 66 * bi_index, which we want to ignore. 67 */ 68 unsigned slot = (idx.value & 63); 69 70 if (fau->uniform_slot < 0) 71 fau->uniform_slot = slot; 72 73 return fau->uniform_slot == slot; 74} 75 76static bool 77fau_is_special(enum bir_fau fau) 78{ 79 return !(fau & (BIR_FAU_UNIFORM | BIR_FAU_IMMEDIATE)); 80} 81 82static bool 83fau_state_special(struct fau_state *fau, bi_index idx) 84{ 85 for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) { 86 bi_index buf = fau->buffer[i]; 87 bool special = !bi_is_null(buf) && fau_is_special(buf.value); 88 89 if (special && !bi_is_equiv(buf, idx)) 90 return false; 91 } 92 93 return true; 94} 95 96static bool 97valid_src(struct fau_state *fau, unsigned fau_page, bi_index src) 98{ 99 if (src.type != BI_INDEX_FAU) 100 return true; 101 102 bool valid = (fau_page == va_fau_page(src.value)); 103 valid &= fau_state_buffer(fau, src); 104 105 if (src.value & BIR_FAU_UNIFORM) 106 valid &= fau_state_uniform(fau, src); 107 else if (fau_is_special(src.value)) 108 valid &= fau_state_special(fau, src); 109 110 return valid; 111} 112 113bool 114va_validate_fau(bi_instr *I) 115{ 116 bool valid = true; 117 struct fau_state fau = { .uniform_slot = -1 }; 118 unsigned fau_page = va_select_fau_page(I); 119 120 bi_foreach_src(I, s) { 121 valid &= valid_src(&fau, fau_page, I->src[s]); 122 } 123 124 return valid; 125} 126 127void 128va_repair_fau(bi_builder *b, bi_instr *I) 129{ 130 struct fau_state fau = { .uniform_slot = -1 }; 131 unsigned fau_page = va_select_fau_page(I); 132 133 bi_foreach_src(I, s) { 134 struct fau_state push = fau; 135 bi_index src = I->src[s]; 136 137 if (!valid_src(&fau, fau_page, src)) { 138 bi_index copy = bi_mov_i32(b, bi_strip_index(src)); 139 I->src[s] = bi_replace_index(src, copy); 140 141 /* Rollback update. Since the replacement move doesn't affect FAU 142 * state, there is no need to call valid_src again. 143 */ 144 fau = push; 145 } 146 } 147} 148 149void 150va_validate(FILE *fp, bi_context *ctx) 151{ 152 bool errors = false; 153 154 bi_foreach_instr_global(ctx, I) { 155 if (!va_validate_fau(I)) { 156 if (!errors) { 157 fprintf(fp, "Validation failed, this is a bug. Shader:\n\n"); 158 bi_print_shader(ctx, fp); 159 fprintf(fp, "Offending code:\n"); 160 } 161 162 bi_print_instr(I, fp); 163 fprintf(fp, "\n"); 164 errors = true; 165 } 166 } 167 168 if (errors) 169 exit(1); 170} 171