1 /*
2 * Copyright © 2015 Intel Corporation
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 /** @file brw_fs_validate.cpp
25 *
26 * Implements a pass that validates various invariants of the IR. The current
27 * pass only validates that GRF's uses are sane. More can be added later.
28 */
29
30 #include "brw_fs.h"
31 #include "brw_cfg.h"
32
33 #define fsv_assert(assertion) \
34 { \
35 if (!(assertion)) { \
36 fprintf(stderr, "ASSERT: Scalar %s validation failed!\n", \
37 _mesa_shader_stage_to_abbrev(stage)); \
38 dump_instruction(inst, stderr); \
39 fprintf(stderr, "%s:%d: '%s' failed\n", __FILE__, __LINE__, #assertion); \
40 abort(); \
41 } \
42 }
43
44 #define fsv_assert_eq(first, second) \
45 { \
46 unsigned f = (first); \
47 unsigned s = (second); \
48 if (f != s) { \
49 fprintf(stderr, "ASSERT: Scalar %s validation failed!\n", \
50 _mesa_shader_stage_to_abbrev(stage)); \
51 dump_instruction(inst, stderr); \
52 fprintf(stderr, "%s:%d: A == B failed\n", __FILE__, __LINE__); \
53 fprintf(stderr, " A = %s = %u\n", #first, f); \
54 fprintf(stderr, " B = %s = %u\n", #second, s); \
55 abort(); \
56 } \
57 }
58
59 #define fsv_assert_ne(first, second) \
60 { \
61 unsigned f = (first); \
62 unsigned s = (second); \
63 if (f == s) { \
64 fprintf(stderr, "ASSERT: Scalar %s validation failed!\n", \
65 _mesa_shader_stage_to_abbrev(stage)); \
66 dump_instruction(inst, stderr); \
67 fprintf(stderr, "%s:%d: A != B failed\n", __FILE__, __LINE__); \
68 fprintf(stderr, " A = %s = %u\n", #first, f); \
69 fprintf(stderr, " B = %s = %u\n", #second, s); \
70 abort(); \
71 } \
72 }
73
74 #define fsv_assert_lte(first, second) \
75 { \
76 unsigned f = (first); \
77 unsigned s = (second); \
78 if (f > s) { \
79 fprintf(stderr, "ASSERT: Scalar %s validation failed!\n", \
80 _mesa_shader_stage_to_abbrev(stage)); \
81 dump_instruction(inst, stderr); \
82 fprintf(stderr, "%s:%d: A <= B failed\n", __FILE__, __LINE__); \
83 fprintf(stderr, " A = %s = %u\n", #first, f); \
84 fprintf(stderr, " B = %s = %u\n", #second, s); \
85 abort(); \
86 } \
87 }
88
89 #ifndef NDEBUG
90 void
validate()91 fs_visitor::validate()
92 {
93 cfg->validate(_mesa_shader_stage_to_abbrev(stage));
94
95 foreach_block_and_inst (block, fs_inst, inst, cfg) {
96 switch (inst->opcode) {
97 case SHADER_OPCODE_SEND:
98 fsv_assert(is_uniform(inst->src[0]) && is_uniform(inst->src[1]));
99 break;
100
101 case BRW_OPCODE_MOV:
102 fsv_assert(inst->sources == 1);
103 break;
104
105 default:
106 break;
107 }
108
109 if (inst->is_3src(compiler)) {
110 const unsigned integer_sources =
111 brw_reg_type_is_integer(inst->src[0].type) +
112 brw_reg_type_is_integer(inst->src[1].type) +
113 brw_reg_type_is_integer(inst->src[2].type);
114 const unsigned float_sources =
115 brw_reg_type_is_floating_point(inst->src[0].type) +
116 brw_reg_type_is_floating_point(inst->src[1].type) +
117 brw_reg_type_is_floating_point(inst->src[2].type);
118
119 fsv_assert((integer_sources == 3 && float_sources == 0) ||
120 (integer_sources == 0 && float_sources == 3));
121
122 if (devinfo->ver >= 10) {
123 for (unsigned i = 0; i < 3; i++) {
124 if (inst->src[i].file == BRW_IMMEDIATE_VALUE)
125 continue;
126
127 switch (inst->src[i].vstride) {
128 case BRW_VERTICAL_STRIDE_0:
129 case BRW_VERTICAL_STRIDE_4:
130 case BRW_VERTICAL_STRIDE_8:
131 case BRW_VERTICAL_STRIDE_16:
132 break;
133
134 case BRW_VERTICAL_STRIDE_1:
135 fsv_assert_lte(12, devinfo->ver);
136 break;
137
138 case BRW_VERTICAL_STRIDE_2:
139 fsv_assert_lte(devinfo->ver, 11);
140 break;
141
142 default:
143 fsv_assert(!"invalid vstride");
144 break;
145 }
146 }
147 } else if (grf_used != 0) {
148 /* Only perform the pre-Gfx10 checks after register allocation has
149 * occured.
150 *
151 * Many passes (e.g., constant copy propagation) will genenerate
152 * invalid 3-source instructions with the expectation that later
153 * passes (e.g., combine constants) will fix them.
154 */
155 for (unsigned i = 0; i < 3; i++) {
156 fsv_assert_ne(inst->src[i].file, BRW_IMMEDIATE_VALUE);
157
158 /* A stride of 1 (the usual case) or 0, with a special
159 * "repctrl" bit, is allowed. The repctrl bit doesn't work for
160 * 64-bit datatypes, so if the source type is 64-bit then only
161 * a stride of 1 is allowed. From the Broadwell PRM, Volume 7
162 * "3D Media GPGPU", page 944:
163 *
164 * This is applicable to 32b datatypes and 16b datatype. 64b
165 * datatypes cannot use the replicate control.
166 */
167 fsv_assert_lte(inst->src[i].vstride, 1);
168
169 if (type_sz(inst->src[i].type) > 4)
170 fsv_assert_eq(inst->src[i].vstride, 1);
171 }
172 }
173 }
174
175 if (inst->dst.file == VGRF) {
176 fsv_assert_lte(inst->dst.offset / REG_SIZE + regs_written(inst),
177 alloc.sizes[inst->dst.nr]);
178 }
179
180 for (unsigned i = 0; i < inst->sources; i++) {
181 if (inst->src[i].file == VGRF) {
182 fsv_assert_lte(inst->src[i].offset / REG_SIZE + regs_read(inst, i),
183 alloc.sizes[inst->src[i].nr]);
184 }
185 }
186
187 /* Accumulator Registers, bspec 47251:
188 *
189 * "When destination is accumulator with offset 0, destination
190 * horizontal stride must be 1."
191 */
192 if (intel_needs_workaround(devinfo, 14014617373) &&
193 inst->dst.is_accumulator() &&
194 inst->dst.offset == 0) {
195 fsv_assert_eq(inst->dst.stride, 1);
196 }
197 }
198 }
199 #endif
200