1/*
2 * Copyright © 2016 Broadcom Limited
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "vc4_qir.h"
25#include "vc4_qpu.h"
26
27static void
28fail_instr(struct vc4_compile *c, struct qinst *inst, const char *msg)
29{
30        fprintf(stderr, "qir_validate: %s: ", msg);
31        qir_dump_inst(c, inst);
32        fprintf(stderr, "\n");
33        abort();
34}
35
36void qir_validate(struct vc4_compile *c)
37{
38        bool already_assigned[c->num_temps];
39        memset(&already_assigned, 0, sizeof(already_assigned));
40
41        /* We don't want to do validation in release builds, but we want to
42         * keep compiling the validation code to make sure it doesn't get
43         * broken.
44         */
45#ifndef DEBUG
46        return;
47#endif
48
49        for (int i = 0; i < c->num_temps; i++) {
50                struct qinst *def = c->defs[i];
51
52                if (def && def->cond != QPU_COND_ALWAYS)
53                        fail_instr(c, def, "SSA def with condition");
54        }
55
56        qir_for_each_inst_inorder(inst, c) {
57                switch (inst->dst.file) {
58                case QFILE_TEMP:
59                        if (inst->dst.index >= c->num_temps)
60                                fail_instr(c, inst, "bad temp index");
61
62                        if (c->defs[inst->dst.index] &&
63                            already_assigned[inst->dst.index]) {
64                                fail_instr(c, inst, "Re-assignment of SSA value");
65                        }
66                        already_assigned[inst->dst.index] = true;
67                        break;
68
69                case QFILE_NULL:
70                case QFILE_VPM:
71                case QFILE_TLB_COLOR_WRITE:
72                case QFILE_TLB_COLOR_WRITE_MS:
73                case QFILE_TLB_Z_WRITE:
74                case QFILE_TLB_STENCIL_SETUP:
75                        break;
76
77                case QFILE_VARY:
78                case QFILE_UNIF:
79                case QFILE_FRAG_X:
80                case QFILE_FRAG_Y:
81                case QFILE_FRAG_REV_FLAG:
82                case QFILE_QPU_ELEMENT:
83                case QFILE_SMALL_IMM:
84                case QFILE_LOAD_IMM:
85                        fail_instr(c, inst, "Bad dest file");
86                        break;
87
88                case QFILE_TEX_S:
89                case QFILE_TEX_T:
90                case QFILE_TEX_R:
91                case QFILE_TEX_B:
92                        if (inst->src[qir_get_tex_uniform_src(inst)].file !=
93                            QFILE_UNIF) {
94                                fail_instr(c, inst,
95                                           "tex op missing implicit uniform");
96                        }
97                        break;
98
99                case QFILE_TEX_S_DIRECT:
100                        if (inst->op != QOP_ADD) {
101                                fail_instr(c, inst,
102                                           "kernel validation requires that "
103                                           "direct texture lookups use an ADD");
104                        }
105                        break;
106                }
107
108                for (int i = 0; i < qir_get_nsrc(inst); i++) {
109                        struct qreg src = inst->src[i];
110
111                        switch (src.file) {
112                        case QFILE_TEMP:
113                                if (src.index >= c->num_temps)
114                                        fail_instr(c, inst, "bad temp index");
115                                break;
116
117                        case QFILE_VARY:
118                        case QFILE_UNIF:
119                        case QFILE_VPM:
120                        case QFILE_LOAD_IMM:
121                        case QFILE_QPU_ELEMENT:
122                                break;
123
124                        case QFILE_SMALL_IMM:
125                                if (qpu_encode_small_immediate(src.index) == ~0)
126                                        fail_instr(c, inst, "bad small immediate");
127                                break;
128
129                        case QFILE_FRAG_X:
130                        case QFILE_FRAG_Y:
131                        case QFILE_FRAG_REV_FLAG:
132                                if (c->stage != QSTAGE_FRAG)
133                                        fail_instr(c, inst, "frag access in VS/CS");
134                                break;
135
136                        case QFILE_NULL:
137                        case QFILE_TLB_COLOR_WRITE:
138                        case QFILE_TLB_COLOR_WRITE_MS:
139                        case QFILE_TLB_Z_WRITE:
140                        case QFILE_TLB_STENCIL_SETUP:
141                        case QFILE_TEX_S_DIRECT:
142                        case QFILE_TEX_S:
143                        case QFILE_TEX_T:
144                        case QFILE_TEX_R:
145                        case QFILE_TEX_B:
146                                fail_instr(c, inst, "Bad src file");
147                                break;
148                        }
149                }
150        }
151}
152