• 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 "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 
42 struct fau_state {
43    signed uniform_slot;
44    bi_index buffer[2];
45 };
46 
47 static bool
fau_state_buffer(struct fau_state * fau,bi_index idx)48 fau_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 
62 static bool
fau_state_uniform(struct fau_state * fau,bi_index idx)63 fau_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 
76 static bool
fau_is_special(enum bir_fau fau)77 fau_is_special(enum bir_fau fau)
78 {
79    return !(fau & (BIR_FAU_UNIFORM | BIR_FAU_IMMEDIATE));
80 }
81 
82 static bool
fau_state_special(struct fau_state * fau,bi_index idx)83 fau_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 
96 static bool
valid_src(struct fau_state * fau,unsigned fau_page,bi_index src)97 valid_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 
113 bool
va_validate_fau(bi_instr * I)114 va_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 
127 void
va_repair_fau(bi_builder * b,bi_instr * I)128 va_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 
149 void
va_validate(FILE * fp,bi_context * ctx)150 va_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