• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bi_builder.h"
25 #include "va_compiler.h"
26 #include "valhall.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
32  * constants. An instruction may access no more than a single special immediate
33  * (e.g. lane_id).
34  *
35  * We validate these constraints.
36  *
37  * An instruction may only access a single page of (special or uniform) FAU.
38  * This constraint does not need explicit validation: since FAU slots are
39  * naturally aligned, they never cross page boundaries, so this condition is
40  * implied by only acesssing a single 64-bit slot.
41  */
42 
43 struct fau_state {
44    signed uniform_slot;
45    bi_index buffer[2];
46 };
47 
48 static bool
fau_state_buffer(struct fau_state * fau,bi_index idx)49 fau_state_buffer(struct fau_state *fau, bi_index idx)
50 {
51    for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) {
52       if (bi_is_word_equiv(fau->buffer[i], idx))
53          return true;
54       else if (bi_is_null(fau->buffer[i])) {
55          fau->buffer[i] = idx;
56          return true;
57       }
58    }
59 
60    return false;
61 }
62 
63 /* Instructions executed in the execution engine may only encode one FAU index.
64  * Instructions executed by the message unit may encode two FAU indices,
65  * except for ATEST and BLEND which may sometimes run in the execution engine.
66  */
67 static bool
can_use_two_fau_indices(enum bi_opcode op)68 can_use_two_fau_indices(enum bi_opcode op)
69 {
70    return bi_opcode_props[op].message != BIFROST_MESSAGE_NONE &&
71           op != BI_OPCODE_ATEST &&
72           op != BI_OPCODE_BLEND;
73 }
74 
75 static bool
can_run_on_message_unit(enum bi_opcode op)76 can_run_on_message_unit(enum bi_opcode op)
77 {
78    return bi_opcode_props[op].message != BIFROST_MESSAGE_NONE ||
79           op == BI_OPCODE_ATEST || op == BI_OPCODE_BLEND;
80 }
81 
82 static bool
fau_is_special(enum bir_fau fau)83 fau_is_special(enum bir_fau fau)
84 {
85    return !(fau & (BIR_FAU_UNIFORM | BIR_FAU_IMMEDIATE));
86 }
87 
88 static bool
fau_state_uniform(struct fau_state * fau,bi_index idx,enum bi_opcode op)89 fau_state_uniform(struct fau_state *fau, bi_index idx, enum bi_opcode op)
90 {
91    /* Each slot is 64-bits. The low/high half is encoded as the offset of the
92     * bi_index, which we want to ignore.
93     */
94    unsigned slot = (idx.value & 63);
95 
96    if (fau->uniform_slot < 0)
97       fau->uniform_slot = slot;
98 
99    if (fau->uniform_slot != slot)
100       return false;
101 
102    if (!can_use_two_fau_indices(op)) {
103       for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) {
104          bi_index buf = fau->buffer[i];
105          if (!bi_is_null(buf) && fau_is_special(buf.value))
106            return false;
107       }
108    }
109 
110    return true;
111 }
112 
113 static bool
fau_state_special(struct fau_state * fau,bi_index idx,enum bi_opcode op)114 fau_state_special(struct fau_state *fau, bi_index idx, enum bi_opcode op)
115 {
116    for (unsigned i = 0; i < ARRAY_SIZE(fau->buffer); ++i) {
117       bi_index buf = fau->buffer[i];
118       bool special = !bi_is_null(buf) && fau_is_special(buf.value);
119 
120       if (special && !bi_is_equiv(buf, idx))
121          return false;
122    }
123 
124    /* Instructions executed by the messaging unit should not encode WARP_ID or
125     * anything from special page 3. */
126    if (can_run_on_message_unit(op) &&
127        (va_fau_page(idx.value) == 3 || idx.value == BIR_FAU_WARP_ID))
128       return false;
129 
130    return fau->uniform_slot == -1 || can_use_two_fau_indices(op);
131 }
132 
133 static bool
valid_src(struct fau_state * fau,unsigned fau_page,bi_index src,enum bi_opcode op)134 valid_src(struct fau_state *fau, unsigned fau_page, bi_index src,
135           enum bi_opcode op)
136 {
137    if (src.type != BI_INDEX_FAU)
138       return true;
139 
140    bool valid = (fau_page == va_fau_page(src.value));
141    valid &= fau_state_buffer(fau, src);
142 
143    if (src.value & BIR_FAU_UNIFORM)
144       valid &= fau_state_uniform(fau, src, op);
145    else if (fau_is_special(src.value))
146       valid &= fau_state_special(fau, src, op);
147 
148    return valid;
149 }
150 
151 bool
va_validate_fau(bi_instr * I)152 va_validate_fau(bi_instr *I)
153 {
154    bool valid = true;
155    struct fau_state fau = {.uniform_slot = -1};
156    unsigned fau_page = va_select_fau_page(I);
157 
158    bi_foreach_src(I, s) {
159       valid &= valid_src(&fau, fau_page, I->src[s], I->op);
160    }
161 
162    return valid;
163 }
164 
165 void
va_repair_fau(bi_builder * b,bi_instr * I)166 va_repair_fau(bi_builder *b, bi_instr *I)
167 {
168    struct fau_state fau = {.uniform_slot = -1};
169    unsigned fau_page = va_select_fau_page(I);
170 
171    bi_foreach_src(I, s) {
172       struct fau_state push = fau;
173       bi_index src = I->src[s];
174 
175       if (!valid_src(&fau, fau_page, src, I->op)) {
176          bi_replace_src(I, s, bi_mov_i32(b, bi_strip_index(src)));
177 
178          /* Rollback update. Since the replacement move doesn't affect FAU
179           * state, there is no need to call valid_src again.
180           */
181          fau = push;
182       }
183    }
184 }
185 
186 void
va_validate(FILE * fp,bi_context * ctx)187 va_validate(FILE *fp, bi_context *ctx)
188 {
189    bool errors = false;
190 
191    bi_foreach_instr_global(ctx, I) {
192       if (!va_validate_fau(I)) {
193          if (!errors) {
194             fprintf(fp, "Validation failed, this is a bug. Shader:\n\n");
195             bi_print_shader(ctx, fp);
196             fprintf(fp, "Offending code:\n");
197          }
198 
199          bi_print_instr(I, fp);
200          fprintf(fp, "\n");
201          errors = true;
202       }
203    }
204 
205    if (errors)
206       exit(1);
207 }
208