1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2018 Valve Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include "aco_ir.h"
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Worker #include "util/memstream.h"
10*61046927SAndroid Build Coastguard Worker #include "util/ralloc.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker #include <array>
13*61046927SAndroid Build Coastguard Worker #include <map>
14*61046927SAndroid Build Coastguard Worker #include <set>
15*61046927SAndroid Build Coastguard Worker #include <vector>
16*61046927SAndroid Build Coastguard Worker
17*61046927SAndroid Build Coastguard Worker namespace aco {
18*61046927SAndroid Build Coastguard Worker
19*61046927SAndroid Build Coastguard Worker static void
aco_log(Program * program,enum aco_compiler_debug_level level,const char * prefix,const char * file,unsigned line,const char * fmt,va_list args)20*61046927SAndroid Build Coastguard Worker aco_log(Program* program, enum aco_compiler_debug_level level, const char* prefix, const char* file,
21*61046927SAndroid Build Coastguard Worker unsigned line, const char* fmt, va_list args)
22*61046927SAndroid Build Coastguard Worker {
23*61046927SAndroid Build Coastguard Worker char* msg;
24*61046927SAndroid Build Coastguard Worker
25*61046927SAndroid Build Coastguard Worker if (program->debug.shorten_messages) {
26*61046927SAndroid Build Coastguard Worker msg = ralloc_vasprintf(NULL, fmt, args);
27*61046927SAndroid Build Coastguard Worker } else {
28*61046927SAndroid Build Coastguard Worker msg = ralloc_strdup(NULL, prefix);
29*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, " In file %s:%u\n", file, line);
30*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, " ");
31*61046927SAndroid Build Coastguard Worker ralloc_vasprintf_append(&msg, fmt, args);
32*61046927SAndroid Build Coastguard Worker }
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker if (program->debug.func)
35*61046927SAndroid Build Coastguard Worker program->debug.func(program->debug.private_data, level, msg);
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker fprintf(program->debug.output, "%s\n", msg);
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker ralloc_free(msg);
40*61046927SAndroid Build Coastguard Worker }
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Worker void
_aco_err(Program * program,const char * file,unsigned line,const char * fmt,...)43*61046927SAndroid Build Coastguard Worker _aco_err(Program* program, const char* file, unsigned line, const char* fmt, ...)
44*61046927SAndroid Build Coastguard Worker {
45*61046927SAndroid Build Coastguard Worker va_list args;
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker va_start(args, fmt);
48*61046927SAndroid Build Coastguard Worker aco_log(program, ACO_COMPILER_DEBUG_LEVEL_ERROR, "ACO ERROR:\n", file, line, fmt, args);
49*61046927SAndroid Build Coastguard Worker va_end(args);
50*61046927SAndroid Build Coastguard Worker }
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker bool
validate_ir(Program * program)53*61046927SAndroid Build Coastguard Worker validate_ir(Program* program)
54*61046927SAndroid Build Coastguard Worker {
55*61046927SAndroid Build Coastguard Worker bool is_valid = true;
56*61046927SAndroid Build Coastguard Worker auto check = [&program, &is_valid](bool success, const char* msg,
57*61046927SAndroid Build Coastguard Worker aco::Instruction* instr) -> void
58*61046927SAndroid Build Coastguard Worker {
59*61046927SAndroid Build Coastguard Worker if (!success) {
60*61046927SAndroid Build Coastguard Worker char* out;
61*61046927SAndroid Build Coastguard Worker size_t outsize;
62*61046927SAndroid Build Coastguard Worker struct u_memstream mem;
63*61046927SAndroid Build Coastguard Worker u_memstream_open(&mem, &out, &outsize);
64*61046927SAndroid Build Coastguard Worker FILE* const memf = u_memstream_get(&mem);
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Worker fprintf(memf, "%s: ", msg);
67*61046927SAndroid Build Coastguard Worker aco_print_instr(program->gfx_level, instr, memf);
68*61046927SAndroid Build Coastguard Worker u_memstream_close(&mem);
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Worker aco_err(program, "%s", out);
71*61046927SAndroid Build Coastguard Worker free(out);
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Worker is_valid = false;
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker };
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker /* check reachability */
78*61046927SAndroid Build Coastguard Worker if (program->progress < CompilationProgress::after_lower_to_hw) {
79*61046927SAndroid Build Coastguard Worker std::map<uint32_t, std::pair<uint32_t, bool>> def_blocks;
80*61046927SAndroid Build Coastguard Worker for (Block& block : program->blocks) {
81*61046927SAndroid Build Coastguard Worker for (aco_ptr<Instruction>& instr : block.instructions) {
82*61046927SAndroid Build Coastguard Worker for (Definition def : instr->definitions) {
83*61046927SAndroid Build Coastguard Worker if (!def.isTemp())
84*61046927SAndroid Build Coastguard Worker continue;
85*61046927SAndroid Build Coastguard Worker check(!def_blocks.count(def.tempId()), "Temporary defined twice", instr.get());
86*61046927SAndroid Build Coastguard Worker def_blocks[def.tempId()] = std::make_pair(block.index, false);
87*61046927SAndroid Build Coastguard Worker }
88*61046927SAndroid Build Coastguard Worker }
89*61046927SAndroid Build Coastguard Worker }
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker for (Block& block : program->blocks) {
92*61046927SAndroid Build Coastguard Worker for (aco_ptr<Instruction>& instr : block.instructions) {
93*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
94*61046927SAndroid Build Coastguard Worker Operand op = instr->operands[i];
95*61046927SAndroid Build Coastguard Worker if (!op.isTemp())
96*61046927SAndroid Build Coastguard Worker continue;
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker uint32_t use_block_idx = block.index;
99*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_phi || instr->opcode == aco_opcode::p_boolean_phi)
100*61046927SAndroid Build Coastguard Worker use_block_idx = block.logical_preds[i];
101*61046927SAndroid Build Coastguard Worker else if (instr->opcode == aco_opcode::p_linear_phi)
102*61046927SAndroid Build Coastguard Worker use_block_idx = block.linear_preds[i];
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker auto it = def_blocks.find(op.tempId());
105*61046927SAndroid Build Coastguard Worker if (it != def_blocks.end()) {
106*61046927SAndroid Build Coastguard Worker Block& def_block = program->blocks[it->second.first];
107*61046927SAndroid Build Coastguard Worker Block& use_block = program->blocks[use_block_idx];
108*61046927SAndroid Build Coastguard Worker bool dominates =
109*61046927SAndroid Build Coastguard Worker def_block.index == use_block_idx
110*61046927SAndroid Build Coastguard Worker ? (use_block_idx == block.index ? it->second.second : true)
111*61046927SAndroid Build Coastguard Worker : (op.regClass().is_linear() ? dominates_linear(def_block, use_block)
112*61046927SAndroid Build Coastguard Worker : dominates_logical(def_block, use_block));
113*61046927SAndroid Build Coastguard Worker if (!dominates) {
114*61046927SAndroid Build Coastguard Worker char msg[256];
115*61046927SAndroid Build Coastguard Worker snprintf(msg, sizeof(msg), "Definition of %%%u does not dominate use",
116*61046927SAndroid Build Coastguard Worker op.tempId());
117*61046927SAndroid Build Coastguard Worker check(false, msg, instr.get());
118*61046927SAndroid Build Coastguard Worker }
119*61046927SAndroid Build Coastguard Worker } else {
120*61046927SAndroid Build Coastguard Worker char msg[256];
121*61046927SAndroid Build Coastguard Worker snprintf(msg, sizeof(msg), "%%%u never defined", op.tempId());
122*61046927SAndroid Build Coastguard Worker check(false, msg, instr.get());
123*61046927SAndroid Build Coastguard Worker }
124*61046927SAndroid Build Coastguard Worker }
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Worker for (Definition def : instr->definitions) {
127*61046927SAndroid Build Coastguard Worker if (def.isTemp())
128*61046927SAndroid Build Coastguard Worker def_blocks[def.tempId()].second = true;
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker }
131*61046927SAndroid Build Coastguard Worker }
132*61046927SAndroid Build Coastguard Worker }
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker for (Block& block : program->blocks) {
135*61046927SAndroid Build Coastguard Worker for (aco_ptr<Instruction>& instr : block.instructions) {
136*61046927SAndroid Build Coastguard Worker
137*61046927SAndroid Build Coastguard Worker if (program->progress < CompilationProgress::after_lower_to_hw) {
138*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands)
139*61046927SAndroid Build Coastguard Worker check(!op.isTemp() || op.regClass() == program->temp_rc[op.tempId()],
140*61046927SAndroid Build Coastguard Worker "Operand RC not consistent.", instr.get());
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker for (const Definition& def : instr->definitions)
143*61046927SAndroid Build Coastguard Worker check(!def.isTemp() || def.regClass() == program->temp_rc[def.tempId()],
144*61046927SAndroid Build Coastguard Worker "Definition RC not consistent.", instr.get());
145*61046927SAndroid Build Coastguard Worker }
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker unsigned pck_defs = instr_info.definitions[(int)instr->opcode];
148*61046927SAndroid Build Coastguard Worker unsigned pck_ops = instr_info.operands[(int)instr->opcode];
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Worker if (pck_defs != 0) {
151*61046927SAndroid Build Coastguard Worker /* Before GFX10 v_cmpx also writes VCC. */
152*61046927SAndroid Build Coastguard Worker if (instr->isVOPC() && program->gfx_level < GFX10 && pck_defs == exec_hi)
153*61046927SAndroid Build Coastguard Worker pck_defs = vcc | (exec_hi << 8);
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 4; i++) {
156*61046927SAndroid Build Coastguard Worker uint32_t def = (pck_defs >> (i * 8)) & 0xff;
157*61046927SAndroid Build Coastguard Worker if (def == 0) {
158*61046927SAndroid Build Coastguard Worker check(i == instr->definitions.size(), "Too many definitions", instr.get());
159*61046927SAndroid Build Coastguard Worker break;
160*61046927SAndroid Build Coastguard Worker } else {
161*61046927SAndroid Build Coastguard Worker check(i < instr->definitions.size(), "Too few definitions", instr.get());
162*61046927SAndroid Build Coastguard Worker if (i >= instr->definitions.size())
163*61046927SAndroid Build Coastguard Worker break;
164*61046927SAndroid Build Coastguard Worker }
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker if (def == m0) {
167*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].isFixed() && instr->definitions[i].physReg() == m0,
168*61046927SAndroid Build Coastguard Worker "Definition needs m0", instr.get());
169*61046927SAndroid Build Coastguard Worker } else if (def == scc) {
170*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].isFixed() && instr->definitions[i].physReg() == scc,
171*61046927SAndroid Build Coastguard Worker "Definition needs scc", instr.get());
172*61046927SAndroid Build Coastguard Worker } else if (def == exec_hi) {
173*61046927SAndroid Build Coastguard Worker RegClass rc = instr->isSALU() ? s2 : program->lane_mask;
174*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].isFixed() &&
175*61046927SAndroid Build Coastguard Worker instr->definitions[i].physReg() == exec &&
176*61046927SAndroid Build Coastguard Worker instr->definitions[i].regClass() == rc,
177*61046927SAndroid Build Coastguard Worker "Definition needs exec", instr.get());
178*61046927SAndroid Build Coastguard Worker } else if (def == exec_lo) {
179*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].isFixed() &&
180*61046927SAndroid Build Coastguard Worker instr->definitions[i].physReg() == exec_lo &&
181*61046927SAndroid Build Coastguard Worker instr->definitions[i].regClass() == s1,
182*61046927SAndroid Build Coastguard Worker "Definition needs exec_lo", instr.get());
183*61046927SAndroid Build Coastguard Worker } else if (def == vcc) {
184*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].regClass() == program->lane_mask,
185*61046927SAndroid Build Coastguard Worker "Definition has to be lane mask", instr.get());
186*61046927SAndroid Build Coastguard Worker check(!instr->definitions[i].isFixed() ||
187*61046927SAndroid Build Coastguard Worker instr->definitions[i].physReg() == vcc || instr->isVOP3() ||
188*61046927SAndroid Build Coastguard Worker instr->isSDWA(),
189*61046927SAndroid Build Coastguard Worker "Definition has to be vcc", instr.get());
190*61046927SAndroid Build Coastguard Worker } else {
191*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].size() == def, "Definition has wrong size",
192*61046927SAndroid Build Coastguard Worker instr.get());
193*61046927SAndroid Build Coastguard Worker }
194*61046927SAndroid Build Coastguard Worker }
195*61046927SAndroid Build Coastguard Worker }
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker if (pck_ops != 0) {
198*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 4; i++) {
199*61046927SAndroid Build Coastguard Worker uint32_t op = (pck_ops >> (i * 8)) & 0xff;
200*61046927SAndroid Build Coastguard Worker if (op == 0) {
201*61046927SAndroid Build Coastguard Worker check(i == instr->operands.size(), "Too many operands", instr.get());
202*61046927SAndroid Build Coastguard Worker break;
203*61046927SAndroid Build Coastguard Worker } else {
204*61046927SAndroid Build Coastguard Worker check(i < instr->operands.size(), "Too few operands", instr.get());
205*61046927SAndroid Build Coastguard Worker if (i >= instr->operands.size())
206*61046927SAndroid Build Coastguard Worker break;
207*61046927SAndroid Build Coastguard Worker }
208*61046927SAndroid Build Coastguard Worker
209*61046927SAndroid Build Coastguard Worker if (op == m0) {
210*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isFixed() && instr->operands[i].physReg() == m0,
211*61046927SAndroid Build Coastguard Worker "Operand needs m0", instr.get());
212*61046927SAndroid Build Coastguard Worker } else if (op == scc) {
213*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isFixed() && instr->operands[i].physReg() == scc,
214*61046927SAndroid Build Coastguard Worker "Operand needs scc", instr.get());
215*61046927SAndroid Build Coastguard Worker } else if (op == exec_hi) {
216*61046927SAndroid Build Coastguard Worker RegClass rc = instr->isSALU() ? s2 : program->lane_mask;
217*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isFixed() && instr->operands[i].physReg() == exec &&
218*61046927SAndroid Build Coastguard Worker instr->operands[i].hasRegClass() && instr->operands[i].regClass() == rc,
219*61046927SAndroid Build Coastguard Worker "Operand needs exec", instr.get());
220*61046927SAndroid Build Coastguard Worker } else if (op == exec_lo) {
221*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isFixed() && instr->operands[i].physReg() == exec_lo &&
222*61046927SAndroid Build Coastguard Worker instr->operands[i].hasRegClass() && instr->operands[i].regClass() == s1,
223*61046927SAndroid Build Coastguard Worker "Operand needs exec_lo", instr.get());
224*61046927SAndroid Build Coastguard Worker } else if (op == vcc) {
225*61046927SAndroid Build Coastguard Worker check(instr->operands[i].hasRegClass() &&
226*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass() == program->lane_mask,
227*61046927SAndroid Build Coastguard Worker "Operand has to be lane mask", instr.get());
228*61046927SAndroid Build Coastguard Worker check(!instr->operands[i].isFixed() || instr->operands[i].physReg() == vcc ||
229*61046927SAndroid Build Coastguard Worker instr->isVOP3(),
230*61046927SAndroid Build Coastguard Worker "Operand has to be vcc", instr.get());
231*61046927SAndroid Build Coastguard Worker } else {
232*61046927SAndroid Build Coastguard Worker check(instr->operands[i].size() == op ||
233*61046927SAndroid Build Coastguard Worker (instr->operands[i].isFixed() && instr->operands[i].physReg() >= 128 &&
234*61046927SAndroid Build Coastguard Worker instr->operands[i].physReg() < 256),
235*61046927SAndroid Build Coastguard Worker "Operand has wrong size", instr.get());
236*61046927SAndroid Build Coastguard Worker }
237*61046927SAndroid Build Coastguard Worker }
238*61046927SAndroid Build Coastguard Worker }
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker /* check base format */
241*61046927SAndroid Build Coastguard Worker Format base_format = instr->format;
242*61046927SAndroid Build Coastguard Worker base_format = (Format)((uint32_t)base_format & ~(uint32_t)Format::SDWA);
243*61046927SAndroid Build Coastguard Worker base_format = (Format)((uint32_t)base_format & ~(uint32_t)Format::DPP16);
244*61046927SAndroid Build Coastguard Worker base_format = (Format)((uint32_t)base_format & ~(uint32_t)Format::DPP8);
245*61046927SAndroid Build Coastguard Worker if ((uint32_t)base_format & (uint32_t)Format::VOP1)
246*61046927SAndroid Build Coastguard Worker base_format = Format::VOP1;
247*61046927SAndroid Build Coastguard Worker else if ((uint32_t)base_format & (uint32_t)Format::VOP2)
248*61046927SAndroid Build Coastguard Worker base_format = Format::VOP2;
249*61046927SAndroid Build Coastguard Worker else if ((uint32_t)base_format & (uint32_t)Format::VOPC)
250*61046927SAndroid Build Coastguard Worker base_format = Format::VOPC;
251*61046927SAndroid Build Coastguard Worker else if (base_format == Format::VINTRP) {
252*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::v_interp_p1ll_f16 ||
253*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_interp_p1lv_f16 ||
254*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_interp_p2_legacy_f16 ||
255*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_interp_p2_f16 ||
256*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_interp_p2_hi_f16) {
257*61046927SAndroid Build Coastguard Worker /* v_interp_*_fp16 are considered VINTRP by the compiler but
258*61046927SAndroid Build Coastguard Worker * they are emitted as VOP3.
259*61046927SAndroid Build Coastguard Worker */
260*61046927SAndroid Build Coastguard Worker base_format = Format::VOP3;
261*61046927SAndroid Build Coastguard Worker } else {
262*61046927SAndroid Build Coastguard Worker base_format = Format::VINTRP;
263*61046927SAndroid Build Coastguard Worker }
264*61046927SAndroid Build Coastguard Worker }
265*61046927SAndroid Build Coastguard Worker check(base_format == instr_info.format[(int)instr->opcode],
266*61046927SAndroid Build Coastguard Worker "Wrong base format for instruction", instr.get());
267*61046927SAndroid Build Coastguard Worker
268*61046927SAndroid Build Coastguard Worker /* check VOP3 modifiers */
269*61046927SAndroid Build Coastguard Worker if (instr->isVOP3() && withoutDPP(instr->format) != Format::VOP3) {
270*61046927SAndroid Build Coastguard Worker check(base_format == Format::VOP2 || base_format == Format::VOP1 ||
271*61046927SAndroid Build Coastguard Worker base_format == Format::VOPC || base_format == Format::VINTRP,
272*61046927SAndroid Build Coastguard Worker "Format cannot have VOP3/VOP3B applied", instr.get());
273*61046927SAndroid Build Coastguard Worker }
274*61046927SAndroid Build Coastguard Worker
275*61046927SAndroid Build Coastguard Worker if (instr->isDPP()) {
276*61046927SAndroid Build Coastguard Worker check(base_format == Format::VOP2 || base_format == Format::VOP1 ||
277*61046927SAndroid Build Coastguard Worker base_format == Format::VOPC || base_format == Format::VOP3 ||
278*61046927SAndroid Build Coastguard Worker base_format == Format::VOP3P,
279*61046927SAndroid Build Coastguard Worker "Format cannot have DPP applied", instr.get());
280*61046927SAndroid Build Coastguard Worker check((!instr->isVOP3() && !instr->isVOP3P()) || program->gfx_level >= GFX11,
281*61046927SAndroid Build Coastguard Worker "VOP3+DPP is GFX11+ only", instr.get());
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker bool fi =
284*61046927SAndroid Build Coastguard Worker instr->isDPP8() ? instr->dpp8().fetch_inactive : instr->dpp16().fetch_inactive;
285*61046927SAndroid Build Coastguard Worker check(!fi || program->gfx_level >= GFX10, "DPP Fetch-Inactive is GFX10+ only",
286*61046927SAndroid Build Coastguard Worker instr.get());
287*61046927SAndroid Build Coastguard Worker }
288*61046927SAndroid Build Coastguard Worker
289*61046927SAndroid Build Coastguard Worker /* check SDWA */
290*61046927SAndroid Build Coastguard Worker if (instr->isSDWA()) {
291*61046927SAndroid Build Coastguard Worker check(base_format == Format::VOP2 || base_format == Format::VOP1 ||
292*61046927SAndroid Build Coastguard Worker base_format == Format::VOPC,
293*61046927SAndroid Build Coastguard Worker "Format cannot have SDWA applied", instr.get());
294*61046927SAndroid Build Coastguard Worker
295*61046927SAndroid Build Coastguard Worker check(program->gfx_level >= GFX8, "SDWA is GFX8 to GFX10.3 only", instr.get());
296*61046927SAndroid Build Coastguard Worker check(program->gfx_level < GFX11, "SDWA is GFX8 to GFX10.3 only", instr.get());
297*61046927SAndroid Build Coastguard Worker
298*61046927SAndroid Build Coastguard Worker SDWA_instruction& sdwa = instr->sdwa();
299*61046927SAndroid Build Coastguard Worker check(sdwa.omod == 0 || program->gfx_level >= GFX9, "SDWA omod only supported on GFX9+",
300*61046927SAndroid Build Coastguard Worker instr.get());
301*61046927SAndroid Build Coastguard Worker if (base_format == Format::VOPC) {
302*61046927SAndroid Build Coastguard Worker check(sdwa.clamp == false || program->gfx_level == GFX8,
303*61046927SAndroid Build Coastguard Worker "SDWA VOPC clamp only supported on GFX8", instr.get());
304*61046927SAndroid Build Coastguard Worker check((instr->definitions[0].isFixed() && instr->definitions[0].physReg() == vcc) ||
305*61046927SAndroid Build Coastguard Worker program->gfx_level >= GFX9,
306*61046927SAndroid Build Coastguard Worker "SDWA+VOPC definition must be fixed to vcc on GFX8", instr.get());
307*61046927SAndroid Build Coastguard Worker } else {
308*61046927SAndroid Build Coastguard Worker const Definition& def = instr->definitions[0];
309*61046927SAndroid Build Coastguard Worker check(def.bytes() <= 4, "SDWA definitions must not be larger than 4 bytes",
310*61046927SAndroid Build Coastguard Worker instr.get());
311*61046927SAndroid Build Coastguard Worker check(def.bytes() >= sdwa.dst_sel.size() + sdwa.dst_sel.offset(),
312*61046927SAndroid Build Coastguard Worker "SDWA definition selection size must be at most definition size", instr.get());
313*61046927SAndroid Build Coastguard Worker check(
314*61046927SAndroid Build Coastguard Worker sdwa.dst_sel.size() == 1 || sdwa.dst_sel.size() == 2 || sdwa.dst_sel.size() == 4,
315*61046927SAndroid Build Coastguard Worker "SDWA definition selection size must be 1, 2 or 4 bytes", instr.get());
316*61046927SAndroid Build Coastguard Worker check(sdwa.dst_sel.offset() % sdwa.dst_sel.size() == 0, "Invalid selection offset",
317*61046927SAndroid Build Coastguard Worker instr.get());
318*61046927SAndroid Build Coastguard Worker check(def.bytes() == 4 || def.bytes() == sdwa.dst_sel.size(),
319*61046927SAndroid Build Coastguard Worker "SDWA dst_sel size must be definition size for subdword definitions",
320*61046927SAndroid Build Coastguard Worker instr.get());
321*61046927SAndroid Build Coastguard Worker check(def.bytes() == 4 || sdwa.dst_sel.offset() == 0,
322*61046927SAndroid Build Coastguard Worker "SDWA dst_sel offset must be 0 for subdword definitions", instr.get());
323*61046927SAndroid Build Coastguard Worker }
324*61046927SAndroid Build Coastguard Worker
325*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < std::min<unsigned>(2, instr->operands.size()); i++) {
326*61046927SAndroid Build Coastguard Worker const Operand& op = instr->operands[i];
327*61046927SAndroid Build Coastguard Worker check(op.bytes() <= 4, "SDWA operands must not be larger than 4 bytes", instr.get());
328*61046927SAndroid Build Coastguard Worker check(op.bytes() >= sdwa.sel[i].size() + sdwa.sel[i].offset(),
329*61046927SAndroid Build Coastguard Worker "SDWA operand selection size must be at most operand size", instr.get());
330*61046927SAndroid Build Coastguard Worker check(sdwa.sel[i].size() == 1 || sdwa.sel[i].size() == 2 || sdwa.sel[i].size() == 4,
331*61046927SAndroid Build Coastguard Worker "SDWA operand selection size must be 1, 2 or 4 bytes", instr.get());
332*61046927SAndroid Build Coastguard Worker check(sdwa.sel[i].offset() % sdwa.sel[i].size() == 0, "Invalid selection offset",
333*61046927SAndroid Build Coastguard Worker instr.get());
334*61046927SAndroid Build Coastguard Worker }
335*61046927SAndroid Build Coastguard Worker if (instr->operands.size() >= 3) {
336*61046927SAndroid Build Coastguard Worker check(instr->operands[2].isFixed() && instr->operands[2].physReg() == vcc,
337*61046927SAndroid Build Coastguard Worker "3rd operand must be fixed to vcc with SDWA", instr.get());
338*61046927SAndroid Build Coastguard Worker }
339*61046927SAndroid Build Coastguard Worker if (instr->definitions.size() >= 2) {
340*61046927SAndroid Build Coastguard Worker check(instr->definitions[1].isFixed() && instr->definitions[1].physReg() == vcc,
341*61046927SAndroid Build Coastguard Worker "2nd definition must be fixed to vcc with SDWA", instr.get());
342*61046927SAndroid Build Coastguard Worker }
343*61046927SAndroid Build Coastguard Worker
344*61046927SAndroid Build Coastguard Worker const bool sdwa_opcodes =
345*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_fmac_f32 && instr->opcode != aco_opcode::v_fmac_f16 &&
346*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_fmamk_f32 &&
347*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_fmaak_f32 &&
348*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_fmamk_f16 &&
349*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_fmaak_f16 &&
350*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_madmk_f32 &&
351*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_madak_f32 &&
352*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_madmk_f16 &&
353*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_madak_f16 &&
354*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_readfirstlane_b32 &&
355*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::v_clrexcp && instr->opcode != aco_opcode::v_swap_b32;
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker const bool feature_mac =
358*61046927SAndroid Build Coastguard Worker program->gfx_level == GFX8 &&
359*61046927SAndroid Build Coastguard Worker (instr->opcode == aco_opcode::v_mac_f32 && instr->opcode == aco_opcode::v_mac_f16);
360*61046927SAndroid Build Coastguard Worker
361*61046927SAndroid Build Coastguard Worker check(sdwa_opcodes || feature_mac, "SDWA can't be used with this opcode", instr.get());
362*61046927SAndroid Build Coastguard Worker }
363*61046927SAndroid Build Coastguard Worker
364*61046927SAndroid Build Coastguard Worker /* check opsel */
365*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::v_permlane16_b32 ||
366*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_permlanex16_b32) {
367*61046927SAndroid Build Coastguard Worker check(instr->valu().opsel <= 0x3, "Unexpected opsel for permlane", instr.get());
368*61046927SAndroid Build Coastguard Worker } else if (instr->isVOP3() || instr->isVOP1() || instr->isVOP2() || instr->isVOPC()) {
369*61046927SAndroid Build Coastguard Worker VALU_instruction& valu = instr->valu();
370*61046927SAndroid Build Coastguard Worker check(valu.opsel == 0 || program->gfx_level >= GFX9, "Opsel is only supported on GFX9+",
371*61046927SAndroid Build Coastguard Worker instr.get());
372*61046927SAndroid Build Coastguard Worker check(valu.opsel == 0 || instr->format == Format::VOP3 || program->gfx_level >= GFX11,
373*61046927SAndroid Build Coastguard Worker "Opsel is only supported for VOP3 before GFX11", instr.get());
374*61046927SAndroid Build Coastguard Worker
375*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 3; i++) {
376*61046927SAndroid Build Coastguard Worker if (i >= instr->operands.size() ||
377*61046927SAndroid Build Coastguard Worker (!instr->isVOP3() && !instr->operands[i].isOfType(RegType::vgpr)) ||
378*61046927SAndroid Build Coastguard Worker (instr->operands[i].hasRegClass() &&
379*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().is_subdword() && !instr->operands[i].isFixed()))
380*61046927SAndroid Build Coastguard Worker check(!valu.opsel[i], "Unexpected opsel for operand", instr.get());
381*61046927SAndroid Build Coastguard Worker }
382*61046927SAndroid Build Coastguard Worker if (instr->definitions[0].regClass().is_subdword() && !instr->definitions[0].isFixed())
383*61046927SAndroid Build Coastguard Worker check(!valu.opsel[3], "Unexpected opsel for sub-dword definition", instr.get());
384*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::v_fma_mixlo_f16 ||
385*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_fma_mixhi_f16 ||
386*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_fma_mix_f32) {
387*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass() ==
388*61046927SAndroid Build Coastguard Worker (instr->opcode == aco_opcode::v_fma_mix_f32 ? v1 : v2b),
389*61046927SAndroid Build Coastguard Worker "v_fma_mix_f32/v_fma_mix_f16 must have v1/v2b definition", instr.get());
390*61046927SAndroid Build Coastguard Worker } else if (instr->isVOP3P()) {
391*61046927SAndroid Build Coastguard Worker VALU_instruction& vop3p = instr->valu();
392*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
393*61046927SAndroid Build Coastguard Worker if (instr->operands[i].hasRegClass() &&
394*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().is_subdword() && !instr->operands[i].isFixed())
395*61046927SAndroid Build Coastguard Worker check(!vop3p.opsel_lo[i] && !vop3p.opsel_hi[i],
396*61046927SAndroid Build Coastguard Worker "Unexpected opsel for subdword operand", instr.get());
397*61046927SAndroid Build Coastguard Worker }
398*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass() == v1 ||
399*61046927SAndroid Build Coastguard Worker instr_info.classes[(int)instr->opcode] == instr_class::wmma,
400*61046927SAndroid Build Coastguard Worker "VOP3P must have v1 definition", instr.get());
401*61046927SAndroid Build Coastguard Worker }
402*61046927SAndroid Build Coastguard Worker
403*61046927SAndroid Build Coastguard Worker /* check for undefs */
404*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
405*61046927SAndroid Build Coastguard Worker if (instr->operands[i].isUndefined()) {
406*61046927SAndroid Build Coastguard Worker bool flat = instr->isFlatLike();
407*61046927SAndroid Build Coastguard Worker bool can_be_undef = is_phi(instr) || instr->isEXP() || instr->isReduction() ||
408*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_create_vector ||
409*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_start_linear_vgpr ||
410*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_jump_to_epilog ||
411*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_dual_src_export_gfx11 ||
412*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_end_with_regs ||
413*61046927SAndroid Build Coastguard Worker (instr->opcode == aco_opcode::p_interp_gfx11 && i == 0) ||
414*61046927SAndroid Build Coastguard Worker (instr->opcode == aco_opcode::p_bpermute_permlane && i == 0) ||
415*61046927SAndroid Build Coastguard Worker (flat && i == 1) || (instr->isMIMG() && (i == 1 || i == 2)) ||
416*61046927SAndroid Build Coastguard Worker ((instr->isMUBUF() || instr->isMTBUF()) && i == 1) ||
417*61046927SAndroid Build Coastguard Worker (instr->isScratch() && i == 0) || (instr->isDS() && i == 0) ||
418*61046927SAndroid Build Coastguard Worker (instr->opcode == aco_opcode::p_init_scratch && i == 0);
419*61046927SAndroid Build Coastguard Worker check(can_be_undef, "Undefs can only be used in certain operands", instr.get());
420*61046927SAndroid Build Coastguard Worker } else {
421*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isFixed() || instr->operands[i].isTemp() ||
422*61046927SAndroid Build Coastguard Worker instr->operands[i].isConstant(),
423*61046927SAndroid Build Coastguard Worker "Uninitialized Operand", instr.get());
424*61046927SAndroid Build Coastguard Worker }
425*61046927SAndroid Build Coastguard Worker }
426*61046927SAndroid Build Coastguard Worker
427*61046927SAndroid Build Coastguard Worker for (Operand& op : instr->operands) {
428*61046927SAndroid Build Coastguard Worker if (op.isFixed() || !op.hasRegClass() || !op.regClass().is_linear_vgpr() ||
429*61046927SAndroid Build Coastguard Worker op.isUndefined())
430*61046927SAndroid Build Coastguard Worker continue;
431*61046927SAndroid Build Coastguard Worker
432*61046927SAndroid Build Coastguard Worker /* Only kill linear VGPRs in top-level blocks. Otherwise, we might have to move linear
433*61046927SAndroid Build Coastguard Worker * VGPRs to make space for normal ones and that isn't possible inside control flow. */
434*61046927SAndroid Build Coastguard Worker if (op.isKill()) {
435*61046927SAndroid Build Coastguard Worker check(block.kind & block_kind_top_level,
436*61046927SAndroid Build Coastguard Worker "Linear VGPR operands must only be killed at top-level blocks", instr.get());
437*61046927SAndroid Build Coastguard Worker }
438*61046927SAndroid Build Coastguard Worker }
439*61046927SAndroid Build Coastguard Worker
440*61046927SAndroid Build Coastguard Worker /* check subdword definitions */
441*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->definitions.size(); i++) {
442*61046927SAndroid Build Coastguard Worker if (instr->definitions[i].regClass().is_subdword())
443*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].bytes() <= 4 || instr->isPseudo() || instr->isVMEM(),
444*61046927SAndroid Build Coastguard Worker "Only Pseudo and VMEM instructions can write subdword registers > 4 bytes",
445*61046927SAndroid Build Coastguard Worker instr.get());
446*61046927SAndroid Build Coastguard Worker }
447*61046927SAndroid Build Coastguard Worker
448*61046927SAndroid Build Coastguard Worker if ((instr->isSALU() && instr->opcode != aco_opcode::p_constaddr_addlo &&
449*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::p_resumeaddr_addlo) ||
450*61046927SAndroid Build Coastguard Worker instr->isVALU()) {
451*61046927SAndroid Build Coastguard Worker /* check literals */
452*61046927SAndroid Build Coastguard Worker Operand literal(s1);
453*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
454*61046927SAndroid Build Coastguard Worker Operand op = instr->operands[i];
455*61046927SAndroid Build Coastguard Worker if (!op.isLiteral())
456*61046927SAndroid Build Coastguard Worker continue;
457*61046927SAndroid Build Coastguard Worker
458*61046927SAndroid Build Coastguard Worker check(!instr->isDPP() && !instr->isSDWA() &&
459*61046927SAndroid Build Coastguard Worker (!instr->isVOP3() || program->gfx_level >= GFX10) &&
460*61046927SAndroid Build Coastguard Worker (!instr->isVOP3P() || program->gfx_level >= GFX10),
461*61046927SAndroid Build Coastguard Worker "Literal applied on wrong instruction format", instr.get());
462*61046927SAndroid Build Coastguard Worker
463*61046927SAndroid Build Coastguard Worker check(literal.isUndefined() || (literal.size() == op.size() &&
464*61046927SAndroid Build Coastguard Worker literal.constantValue() == op.constantValue()),
465*61046927SAndroid Build Coastguard Worker "Only 1 Literal allowed", instr.get());
466*61046927SAndroid Build Coastguard Worker literal = op;
467*61046927SAndroid Build Coastguard Worker check(instr->isSALU() || instr->isVOP3() || instr->isVOP3P() || i == 0 || i == 2,
468*61046927SAndroid Build Coastguard Worker "Wrong source position for Literal argument", instr.get());
469*61046927SAndroid Build Coastguard Worker }
470*61046927SAndroid Build Coastguard Worker
471*61046927SAndroid Build Coastguard Worker /* check num sgprs for VALU */
472*61046927SAndroid Build Coastguard Worker if (instr->isVALU()) {
473*61046927SAndroid Build Coastguard Worker bool is_shift64 = instr->opcode == aco_opcode::v_lshlrev_b64_e64 ||
474*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_lshlrev_b64 ||
475*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_lshrrev_b64 ||
476*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_ashrrev_i64;
477*61046927SAndroid Build Coastguard Worker unsigned const_bus_limit = 1;
478*61046927SAndroid Build Coastguard Worker if (program->gfx_level >= GFX10 && !is_shift64)
479*61046927SAndroid Build Coastguard Worker const_bus_limit = 2;
480*61046927SAndroid Build Coastguard Worker
481*61046927SAndroid Build Coastguard Worker uint32_t scalar_mask =
482*61046927SAndroid Build Coastguard Worker instr->isVOP3() || instr->isVOP3P() || instr->isVINTERP_INREG() ? 0x7 : 0x5;
483*61046927SAndroid Build Coastguard Worker if (instr->isSDWA())
484*61046927SAndroid Build Coastguard Worker scalar_mask = program->gfx_level >= GFX9 ? 0x7 : 0x4;
485*61046927SAndroid Build Coastguard Worker else if (instr->isDPP())
486*61046927SAndroid Build Coastguard Worker scalar_mask = 0x4;
487*61046927SAndroid Build Coastguard Worker
488*61046927SAndroid Build Coastguard Worker if (instr->isVOPC() || instr->opcode == aco_opcode::v_readfirstlane_b32 ||
489*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_readlane_b32 ||
490*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_readlane_b32_e64 ||
491*61046927SAndroid Build Coastguard Worker instr_info.classes[(int)instr->opcode] ==
492*61046927SAndroid Build Coastguard Worker instr_class::valu_pseudo_scalar_trans) {
493*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::sgpr,
494*61046927SAndroid Build Coastguard Worker "Wrong Definition type for VALU instruction", instr.get());
495*61046927SAndroid Build Coastguard Worker } else {
496*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
497*61046927SAndroid Build Coastguard Worker "Wrong Definition type for VALU instruction", instr.get());
498*61046927SAndroid Build Coastguard Worker }
499*61046927SAndroid Build Coastguard Worker
500*61046927SAndroid Build Coastguard Worker unsigned num_sgprs = 0;
501*61046927SAndroid Build Coastguard Worker unsigned sgpr[] = {0, 0};
502*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
503*61046927SAndroid Build Coastguard Worker Operand op = instr->operands[i];
504*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::v_readfirstlane_b32 ||
505*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_readlane_b32 ||
506*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_readlane_b32_e64) {
507*61046927SAndroid Build Coastguard Worker check(i != 1 || op.isOfType(RegType::sgpr) || op.isConstant(),
508*61046927SAndroid Build Coastguard Worker "Must be a SGPR or a constant", instr.get());
509*61046927SAndroid Build Coastguard Worker check(i == 1 || (op.isOfType(RegType::vgpr) && op.bytes() <= 4),
510*61046927SAndroid Build Coastguard Worker "Wrong Operand type for VALU instruction", instr.get());
511*61046927SAndroid Build Coastguard Worker continue;
512*61046927SAndroid Build Coastguard Worker }
513*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::v_permlane16_b32 ||
514*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_permlanex16_b32 ||
515*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_permlane64_b32) {
516*61046927SAndroid Build Coastguard Worker check(i != 0 || op.isOfType(RegType::vgpr),
517*61046927SAndroid Build Coastguard Worker "Operand 0 of v_permlane must be VGPR", instr.get());
518*61046927SAndroid Build Coastguard Worker check(i == 0 || op.isOfType(RegType::sgpr) || op.isConstant(),
519*61046927SAndroid Build Coastguard Worker "Lane select operands of v_permlane must be SGPR or constant",
520*61046927SAndroid Build Coastguard Worker instr.get());
521*61046927SAndroid Build Coastguard Worker }
522*61046927SAndroid Build Coastguard Worker
523*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::v_writelane_b32 ||
524*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_writelane_b32_e64) {
525*61046927SAndroid Build Coastguard Worker check(i != 2 || (op.isOfType(RegType::vgpr) && op.bytes() <= 4),
526*61046927SAndroid Build Coastguard Worker "Wrong Operand type for VALU instruction", instr.get());
527*61046927SAndroid Build Coastguard Worker check(i == 2 || op.isOfType(RegType::sgpr) || op.isConstant(),
528*61046927SAndroid Build Coastguard Worker "Must be a SGPR or a constant", instr.get());
529*61046927SAndroid Build Coastguard Worker continue;
530*61046927SAndroid Build Coastguard Worker }
531*61046927SAndroid Build Coastguard Worker if (op.isOfType(RegType::sgpr)) {
532*61046927SAndroid Build Coastguard Worker check(scalar_mask & (1 << i), "Wrong source position for SGPR argument",
533*61046927SAndroid Build Coastguard Worker instr.get());
534*61046927SAndroid Build Coastguard Worker
535*61046927SAndroid Build Coastguard Worker if (op.tempId() != sgpr[0] && op.tempId() != sgpr[1]) {
536*61046927SAndroid Build Coastguard Worker if (num_sgprs < 2)
537*61046927SAndroid Build Coastguard Worker sgpr[num_sgprs++] = op.tempId();
538*61046927SAndroid Build Coastguard Worker }
539*61046927SAndroid Build Coastguard Worker }
540*61046927SAndroid Build Coastguard Worker
541*61046927SAndroid Build Coastguard Worker if (op.isConstant() && !op.isLiteral())
542*61046927SAndroid Build Coastguard Worker check(scalar_mask & (1 << i), "Wrong source position for constant argument",
543*61046927SAndroid Build Coastguard Worker instr.get());
544*61046927SAndroid Build Coastguard Worker }
545*61046927SAndroid Build Coastguard Worker check(num_sgprs + (literal.isUndefined() ? 0 : 1) <= const_bus_limit,
546*61046927SAndroid Build Coastguard Worker "Too many SGPRs/literals", instr.get());
547*61046927SAndroid Build Coastguard Worker
548*61046927SAndroid Build Coastguard Worker /* Validate modifiers. */
549*61046927SAndroid Build Coastguard Worker check(!instr->valu().opsel || instr->isVOP3() || instr->isVOP1() ||
550*61046927SAndroid Build Coastguard Worker instr->isVOP2() || instr->isVOPC() || instr->isVINTERP_INREG(),
551*61046927SAndroid Build Coastguard Worker "OPSEL set for unsupported instruction format", instr.get());
552*61046927SAndroid Build Coastguard Worker check(!instr->valu().opsel_lo || instr->isVOP3P(),
553*61046927SAndroid Build Coastguard Worker "OPSEL_LO set for unsupported instruction format", instr.get());
554*61046927SAndroid Build Coastguard Worker check(!instr->valu().opsel_hi || instr->isVOP3P(),
555*61046927SAndroid Build Coastguard Worker "OPSEL_HI set for unsupported instruction format", instr.get());
556*61046927SAndroid Build Coastguard Worker check(!instr->valu().omod || instr->isVOP3() || instr->isSDWA(),
557*61046927SAndroid Build Coastguard Worker "OMOD set for unsupported instruction format", instr.get());
558*61046927SAndroid Build Coastguard Worker check(!instr->valu().clamp || instr->isVOP3() || instr->isVOP3P() ||
559*61046927SAndroid Build Coastguard Worker instr->isSDWA() || instr->isVINTERP_INREG(),
560*61046927SAndroid Build Coastguard Worker "CLAMP set for unsupported instruction format", instr.get());
561*61046927SAndroid Build Coastguard Worker
562*61046927SAndroid Build Coastguard Worker for (bool abs : instr->valu().abs) {
563*61046927SAndroid Build Coastguard Worker check(!abs || instr->isVOP3() || instr->isVOP3P() || instr->isSDWA() ||
564*61046927SAndroid Build Coastguard Worker instr->isDPP16(),
565*61046927SAndroid Build Coastguard Worker "ABS/NEG_HI set for unsupported instruction format", instr.get());
566*61046927SAndroid Build Coastguard Worker }
567*61046927SAndroid Build Coastguard Worker for (bool neg : instr->valu().neg) {
568*61046927SAndroid Build Coastguard Worker check(!neg || instr->isVOP3() || instr->isVOP3P() || instr->isSDWA() ||
569*61046927SAndroid Build Coastguard Worker instr->isDPP16() || instr->isVINTERP_INREG(),
570*61046927SAndroid Build Coastguard Worker "NEG/NEG_LO set for unsupported instruction format", instr.get());
571*61046927SAndroid Build Coastguard Worker }
572*61046927SAndroid Build Coastguard Worker }
573*61046927SAndroid Build Coastguard Worker
574*61046927SAndroid Build Coastguard Worker if (instr->isSOP1() || instr->isSOP2()) {
575*61046927SAndroid Build Coastguard Worker if (!instr->definitions.empty())
576*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::sgpr,
577*61046927SAndroid Build Coastguard Worker "Wrong Definition type for SALU instruction", instr.get());
578*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
579*61046927SAndroid Build Coastguard Worker check(op.isConstant() || op.isOfType(RegType::sgpr),
580*61046927SAndroid Build Coastguard Worker "Wrong Operand type for SALU instruction", instr.get());
581*61046927SAndroid Build Coastguard Worker }
582*61046927SAndroid Build Coastguard Worker }
583*61046927SAndroid Build Coastguard Worker }
584*61046927SAndroid Build Coastguard Worker
585*61046927SAndroid Build Coastguard Worker switch (instr->format) {
586*61046927SAndroid Build Coastguard Worker case Format::PSEUDO: {
587*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_create_vector ||
588*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_start_linear_vgpr) {
589*61046927SAndroid Build Coastguard Worker unsigned size = 0;
590*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
591*61046927SAndroid Build Coastguard Worker check(op.bytes() < 4 || size % 4 == 0, "Operand is not aligned", instr.get());
592*61046927SAndroid Build Coastguard Worker size += op.bytes();
593*61046927SAndroid Build Coastguard Worker }
594*61046927SAndroid Build Coastguard Worker if (!instr->operands.empty() || instr->opcode == aco_opcode::p_create_vector) {
595*61046927SAndroid Build Coastguard Worker check(size == instr->definitions[0].bytes(),
596*61046927SAndroid Build Coastguard Worker "Definition size does not match operand sizes", instr.get());
597*61046927SAndroid Build Coastguard Worker }
598*61046927SAndroid Build Coastguard Worker if (instr->definitions[0].regClass().type() == RegType::sgpr) {
599*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
600*61046927SAndroid Build Coastguard Worker check(op.isConstant() || op.regClass().type() == RegType::sgpr,
601*61046927SAndroid Build Coastguard Worker "Wrong Operand type for scalar vector", instr.get());
602*61046927SAndroid Build Coastguard Worker }
603*61046927SAndroid Build Coastguard Worker }
604*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_start_linear_vgpr)
605*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().is_linear_vgpr(),
606*61046927SAndroid Build Coastguard Worker "Definition must be linear VGPR", instr.get());
607*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_extract_vector) {
608*61046927SAndroid Build Coastguard Worker check(!instr->operands[0].isConstant() && instr->operands[1].isConstant(),
609*61046927SAndroid Build Coastguard Worker "Wrong Operand types", instr.get());
610*61046927SAndroid Build Coastguard Worker check((instr->operands[1].constantValue() + 1) * instr->definitions[0].bytes() <=
611*61046927SAndroid Build Coastguard Worker instr->operands[0].bytes(),
612*61046927SAndroid Build Coastguard Worker "Index out of range", instr.get());
613*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr ||
614*61046927SAndroid Build Coastguard Worker instr->operands[0].regClass().type() == RegType::sgpr,
615*61046927SAndroid Build Coastguard Worker "Cannot extract SGPR value from VGPR vector", instr.get());
616*61046927SAndroid Build Coastguard Worker check(program->gfx_level >= GFX9 ||
617*61046927SAndroid Build Coastguard Worker !instr->definitions[0].regClass().is_subdword() ||
618*61046927SAndroid Build Coastguard Worker instr->operands[0].regClass().type() == RegType::vgpr,
619*61046927SAndroid Build Coastguard Worker "Cannot extract subdword from SGPR before GFX9+", instr.get());
620*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_split_vector) {
621*61046927SAndroid Build Coastguard Worker check(!instr->operands[0].isConstant(), "Operand must not be constant", instr.get());
622*61046927SAndroid Build Coastguard Worker unsigned size = 0;
623*61046927SAndroid Build Coastguard Worker for (const Definition& def : instr->definitions) {
624*61046927SAndroid Build Coastguard Worker size += def.bytes();
625*61046927SAndroid Build Coastguard Worker }
626*61046927SAndroid Build Coastguard Worker check(size == instr->operands[0].bytes(),
627*61046927SAndroid Build Coastguard Worker "Operand size does not match definition sizes", instr.get());
628*61046927SAndroid Build Coastguard Worker if (instr->operands[0].isOfType(RegType::vgpr)) {
629*61046927SAndroid Build Coastguard Worker for (const Definition& def : instr->definitions)
630*61046927SAndroid Build Coastguard Worker check(def.regClass().type() == RegType::vgpr,
631*61046927SAndroid Build Coastguard Worker "Wrong Definition type for VGPR split_vector", instr.get());
632*61046927SAndroid Build Coastguard Worker } else {
633*61046927SAndroid Build Coastguard Worker for (const Definition& def : instr->definitions)
634*61046927SAndroid Build Coastguard Worker check(program->gfx_level >= GFX9 || !def.regClass().is_subdword(),
635*61046927SAndroid Build Coastguard Worker "Cannot split SGPR into subdword VGPRs before GFX9+", instr.get());
636*61046927SAndroid Build Coastguard Worker }
637*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_parallelcopy) {
638*61046927SAndroid Build Coastguard Worker check(instr->definitions.size() == instr->operands.size(),
639*61046927SAndroid Build Coastguard Worker "Number of Operands does not match number of Definitions", instr.get());
640*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
641*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].bytes() == instr->operands[i].bytes(),
642*61046927SAndroid Build Coastguard Worker "Operand and Definition size must match", instr.get());
643*61046927SAndroid Build Coastguard Worker if (instr->operands[i].hasRegClass()) {
644*61046927SAndroid Build Coastguard Worker check((instr->definitions[i].regClass().type() ==
645*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().type()) ||
646*61046927SAndroid Build Coastguard Worker (instr->definitions[i].regClass().type() == RegType::vgpr &&
647*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().type() == RegType::sgpr),
648*61046927SAndroid Build Coastguard Worker "Operand and Definition types do not match", instr.get());
649*61046927SAndroid Build Coastguard Worker check(instr->definitions[i].regClass().is_linear_vgpr() ==
650*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().is_linear_vgpr(),
651*61046927SAndroid Build Coastguard Worker "Operand and Definition types do not match", instr.get());
652*61046927SAndroid Build Coastguard Worker } else {
653*61046927SAndroid Build Coastguard Worker check(!instr->definitions[i].regClass().is_linear_vgpr(),
654*61046927SAndroid Build Coastguard Worker "Can only copy linear VGPRs into linear VGPRs, not constant/undef",
655*61046927SAndroid Build Coastguard Worker instr.get());
656*61046927SAndroid Build Coastguard Worker }
657*61046927SAndroid Build Coastguard Worker }
658*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_phi) {
659*61046927SAndroid Build Coastguard Worker check(instr->operands.size() == block.logical_preds.size(),
660*61046927SAndroid Build Coastguard Worker "Number of Operands does not match number of predecessors", instr.get());
661*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
662*61046927SAndroid Build Coastguard Worker "Logical Phi Definition must be vgpr", instr.get());
663*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands)
664*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].size() == op.size(),
665*61046927SAndroid Build Coastguard Worker "Operand sizes must match Definition size", instr.get());
666*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_linear_phi) {
667*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
668*61046927SAndroid Build Coastguard Worker check(!op.isTemp() || op.getTemp().is_linear(), "Wrong Operand type",
669*61046927SAndroid Build Coastguard Worker instr.get());
670*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].size() == op.size(),
671*61046927SAndroid Build Coastguard Worker "Operand sizes must match Definition size", instr.get());
672*61046927SAndroid Build Coastguard Worker }
673*61046927SAndroid Build Coastguard Worker check(instr->operands.size() == block.linear_preds.size(),
674*61046927SAndroid Build Coastguard Worker "Number of Operands does not match number of predecessors", instr.get());
675*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_extract ||
676*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::p_insert) {
677*61046927SAndroid Build Coastguard Worker check(!instr->operands[0].isConstant(), "Data operand must not be constant",
678*61046927SAndroid Build Coastguard Worker instr.get());
679*61046927SAndroid Build Coastguard Worker check(instr->operands[1].isConstant(), "Index must be constant", instr.get());
680*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_extract)
681*61046927SAndroid Build Coastguard Worker check(instr->operands[3].isConstant(), "Sign-extend flag must be constant",
682*61046927SAndroid Build Coastguard Worker instr.get());
683*61046927SAndroid Build Coastguard Worker
684*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() != RegType::sgpr ||
685*61046927SAndroid Build Coastguard Worker instr->operands[0].regClass().type() == RegType::sgpr,
686*61046927SAndroid Build Coastguard Worker "Can't extract/insert VGPR to SGPR", instr.get());
687*61046927SAndroid Build Coastguard Worker
688*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_insert)
689*61046927SAndroid Build Coastguard Worker check(instr->operands[0].bytes() == instr->definitions[0].bytes(),
690*61046927SAndroid Build Coastguard Worker "Sizes of p_insert data operand and definition must match", instr.get());
691*61046927SAndroid Build Coastguard Worker
692*61046927SAndroid Build Coastguard Worker if (instr->definitions[0].regClass().type() == RegType::sgpr)
693*61046927SAndroid Build Coastguard Worker check(instr->definitions.size() >= 2 && instr->definitions[1].isFixed() &&
694*61046927SAndroid Build Coastguard Worker instr->definitions[1].physReg() == scc,
695*61046927SAndroid Build Coastguard Worker "SGPR extract/insert needs an SCC definition", instr.get());
696*61046927SAndroid Build Coastguard Worker
697*61046927SAndroid Build Coastguard Worker unsigned data_bits = instr->operands[0].bytes() * 8u;
698*61046927SAndroid Build Coastguard Worker unsigned op_bits = instr->operands[2].constantValue();
699*61046927SAndroid Build Coastguard Worker
700*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_insert) {
701*61046927SAndroid Build Coastguard Worker check(op_bits == 8 || op_bits == 16, "Size must be 8 or 16", instr.get());
702*61046927SAndroid Build Coastguard Worker check(op_bits < data_bits, "Size must be smaller than source", instr.get());
703*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_extract) {
704*61046927SAndroid Build Coastguard Worker check(op_bits == 8 || op_bits == 16 || op_bits == 32,
705*61046927SAndroid Build Coastguard Worker "Size must be 8 or 16 or 32", instr.get());
706*61046927SAndroid Build Coastguard Worker check(data_bits >= op_bits, "Can't extract more bits than what the data has.",
707*61046927SAndroid Build Coastguard Worker instr.get());
708*61046927SAndroid Build Coastguard Worker }
709*61046927SAndroid Build Coastguard Worker
710*61046927SAndroid Build Coastguard Worker unsigned comp = data_bits / MAX2(op_bits, 1);
711*61046927SAndroid Build Coastguard Worker check(instr->operands[1].constantValue() < comp, "Index must be in-bounds",
712*61046927SAndroid Build Coastguard Worker instr.get());
713*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_jump_to_epilog) {
714*61046927SAndroid Build Coastguard Worker check(instr->definitions.size() == 0, "p_jump_to_epilog must have 0 definitions",
715*61046927SAndroid Build Coastguard Worker instr.get());
716*61046927SAndroid Build Coastguard Worker check(instr->operands.size() > 0 && instr->operands[0].isOfType(RegType::sgpr) &&
717*61046927SAndroid Build Coastguard Worker instr->operands[0].size() == 2,
718*61046927SAndroid Build Coastguard Worker "First operand of p_jump_to_epilog must be a SGPR", instr.get());
719*61046927SAndroid Build Coastguard Worker for (unsigned i = 1; i < instr->operands.size(); i++) {
720*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isOfType(RegType::vgpr) ||
721*61046927SAndroid Build Coastguard Worker instr->operands[i].isOfType(RegType::sgpr) ||
722*61046927SAndroid Build Coastguard Worker instr->operands[i].isUndefined(),
723*61046927SAndroid Build Coastguard Worker "Other operands of p_jump_to_epilog must be VGPRs, SGPRs or undef",
724*61046927SAndroid Build Coastguard Worker instr.get());
725*61046927SAndroid Build Coastguard Worker }
726*61046927SAndroid Build Coastguard Worker } else if (instr->opcode == aco_opcode::p_dual_src_export_gfx11) {
727*61046927SAndroid Build Coastguard Worker check(instr->definitions.size() == 6,
728*61046927SAndroid Build Coastguard Worker "p_dual_src_export_gfx11 must have 6 definitions", instr.get());
729*61046927SAndroid Build Coastguard Worker check(instr->definitions[2].regClass() == program->lane_mask,
730*61046927SAndroid Build Coastguard Worker "Third definition of p_dual_src_export_gfx11 must be a lane mask",
731*61046927SAndroid Build Coastguard Worker instr.get());
732*61046927SAndroid Build Coastguard Worker check(instr->definitions[3].regClass() == program->lane_mask,
733*61046927SAndroid Build Coastguard Worker "Fourth definition of p_dual_src_export_gfx11 must be a lane mask",
734*61046927SAndroid Build Coastguard Worker instr.get());
735*61046927SAndroid Build Coastguard Worker check(instr->definitions[4].physReg() == vcc,
736*61046927SAndroid Build Coastguard Worker "Fifth definition of p_dual_src_export_gfx11 must be vcc", instr.get());
737*61046927SAndroid Build Coastguard Worker check(instr->definitions[5].physReg() == scc,
738*61046927SAndroid Build Coastguard Worker "Sixth definition of p_dual_src_export_gfx11 must be scc", instr.get());
739*61046927SAndroid Build Coastguard Worker check(instr->operands.size() == 8, "p_dual_src_export_gfx11 must have 8 operands",
740*61046927SAndroid Build Coastguard Worker instr.get());
741*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
742*61046927SAndroid Build Coastguard Worker check(
743*61046927SAndroid Build Coastguard Worker instr->operands[i].isOfType(RegType::vgpr) || instr->operands[i].isUndefined(),
744*61046927SAndroid Build Coastguard Worker "Operands of p_dual_src_export_gfx11 must be VGPRs or undef", instr.get());
745*61046927SAndroid Build Coastguard Worker }
746*61046927SAndroid Build Coastguard Worker }
747*61046927SAndroid Build Coastguard Worker break;
748*61046927SAndroid Build Coastguard Worker }
749*61046927SAndroid Build Coastguard Worker case Format::PSEUDO_REDUCTION: {
750*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands)
751*61046927SAndroid Build Coastguard Worker check(op.regClass().type() == RegType::vgpr,
752*61046927SAndroid Build Coastguard Worker "All operands of PSEUDO_REDUCTION instructions must be in VGPRs.",
753*61046927SAndroid Build Coastguard Worker instr.get());
754*61046927SAndroid Build Coastguard Worker
755*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_reduce &&
756*61046927SAndroid Build Coastguard Worker instr->reduction().cluster_size == program->wave_size)
757*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::sgpr ||
758*61046927SAndroid Build Coastguard Worker program->wave_size == 32,
759*61046927SAndroid Build Coastguard Worker "The result of unclustered reductions must go into an SGPR.", instr.get());
760*61046927SAndroid Build Coastguard Worker else
761*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
762*61046927SAndroid Build Coastguard Worker "The result of scans and clustered reductions must go into a VGPR.",
763*61046927SAndroid Build Coastguard Worker instr.get());
764*61046927SAndroid Build Coastguard Worker
765*61046927SAndroid Build Coastguard Worker break;
766*61046927SAndroid Build Coastguard Worker }
767*61046927SAndroid Build Coastguard Worker case Format::SMEM: {
768*61046927SAndroid Build Coastguard Worker if (instr->operands.size() >= 1)
769*61046927SAndroid Build Coastguard Worker check(instr->operands[0].isOfType(RegType::sgpr), "SMEM operands must be sgpr",
770*61046927SAndroid Build Coastguard Worker instr.get());
771*61046927SAndroid Build Coastguard Worker if (instr->operands.size() >= 2)
772*61046927SAndroid Build Coastguard Worker check(instr->operands[1].isConstant() || instr->operands[1].isOfType(RegType::sgpr),
773*61046927SAndroid Build Coastguard Worker "SMEM offset must be constant or sgpr", instr.get());
774*61046927SAndroid Build Coastguard Worker if (!instr->definitions.empty())
775*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::sgpr,
776*61046927SAndroid Build Coastguard Worker "SMEM result must be sgpr", instr.get());
777*61046927SAndroid Build Coastguard Worker break;
778*61046927SAndroid Build Coastguard Worker }
779*61046927SAndroid Build Coastguard Worker case Format::MTBUF:
780*61046927SAndroid Build Coastguard Worker case Format::MUBUF: {
781*61046927SAndroid Build Coastguard Worker check(instr->operands.size() > 1, "VMEM instructions must have at least one operand",
782*61046927SAndroid Build Coastguard Worker instr.get());
783*61046927SAndroid Build Coastguard Worker check(instr->operands[1].isOfType(RegType::vgpr),
784*61046927SAndroid Build Coastguard Worker "VADDR must be in vgpr for VMEM instructions", instr.get());
785*61046927SAndroid Build Coastguard Worker check(instr->operands[0].isOfType(RegType::sgpr), "VMEM resource constant must be sgpr",
786*61046927SAndroid Build Coastguard Worker instr.get());
787*61046927SAndroid Build Coastguard Worker check(instr->operands.size() < 4 || instr->operands[3].isOfType(RegType::vgpr),
788*61046927SAndroid Build Coastguard Worker "VMEM write data must be vgpr", instr.get());
789*61046927SAndroid Build Coastguard Worker if (instr->operands.size() >= 3 && instr->operands[2].isConstant())
790*61046927SAndroid Build Coastguard Worker check(program->gfx_level < GFX12 || instr->operands[2].constantValue() == 0,
791*61046927SAndroid Build Coastguard Worker "VMEM SOFFSET must not be non-zero constant on GFX12+", instr.get());
792*61046927SAndroid Build Coastguard Worker
793*61046927SAndroid Build Coastguard Worker const bool d16 =
794*61046927SAndroid Build Coastguard Worker instr->opcode ==
795*61046927SAndroid Build Coastguard Worker aco_opcode::buffer_load_dword || // FIXME: used to spill subdword variables
796*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_ubyte ||
797*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_sbyte ||
798*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_ushort ||
799*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_sshort ||
800*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_ubyte_d16 ||
801*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_ubyte_d16_hi ||
802*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_sbyte_d16 ||
803*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_sbyte_d16_hi ||
804*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_short_d16 ||
805*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_short_d16_hi ||
806*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_format_d16_x ||
807*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_format_d16_hi_x ||
808*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_format_d16_xy ||
809*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_format_d16_xyz ||
810*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::buffer_load_format_d16_xyzw ||
811*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::tbuffer_load_format_d16_x ||
812*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::tbuffer_load_format_d16_xy ||
813*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::tbuffer_load_format_d16_xyz ||
814*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::tbuffer_load_format_d16_xyzw;
815*61046927SAndroid Build Coastguard Worker if (instr->definitions.size()) {
816*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
817*61046927SAndroid Build Coastguard Worker "VMEM definitions[0] (VDATA) must be VGPR", instr.get());
818*61046927SAndroid Build Coastguard Worker check(d16 || !instr->definitions[0].regClass().is_subdword(),
819*61046927SAndroid Build Coastguard Worker "Only D16 opcodes can load subdword values.", instr.get());
820*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].bytes() <= 8 || !d16,
821*61046927SAndroid Build Coastguard Worker "D16 opcodes can only load up to 8 bytes.", instr.get());
822*61046927SAndroid Build Coastguard Worker }
823*61046927SAndroid Build Coastguard Worker break;
824*61046927SAndroid Build Coastguard Worker }
825*61046927SAndroid Build Coastguard Worker case Format::MIMG: {
826*61046927SAndroid Build Coastguard Worker check(instr->operands.size() >= 4, "MIMG instructions must have at least 4 operands",
827*61046927SAndroid Build Coastguard Worker instr.get());
828*61046927SAndroid Build Coastguard Worker check(instr->operands[0].hasRegClass() &&
829*61046927SAndroid Build Coastguard Worker (instr->operands[0].regClass() == s4 || instr->operands[0].regClass() == s8),
830*61046927SAndroid Build Coastguard Worker "MIMG operands[0] (resource constant) must be in 4 or 8 SGPRs", instr.get());
831*61046927SAndroid Build Coastguard Worker if (instr->operands[1].hasRegClass())
832*61046927SAndroid Build Coastguard Worker check(instr->operands[1].regClass() == s4,
833*61046927SAndroid Build Coastguard Worker "MIMG operands[1] (sampler constant) must be 4 SGPRs", instr.get());
834*61046927SAndroid Build Coastguard Worker if (!instr->operands[2].isUndefined()) {
835*61046927SAndroid Build Coastguard Worker bool is_cmpswap = instr->opcode == aco_opcode::image_atomic_cmpswap ||
836*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::image_atomic_fcmpswap;
837*61046927SAndroid Build Coastguard Worker check(instr->definitions.empty() ||
838*61046927SAndroid Build Coastguard Worker (instr->definitions[0].regClass() == instr->operands[2].regClass() ||
839*61046927SAndroid Build Coastguard Worker is_cmpswap),
840*61046927SAndroid Build Coastguard Worker "MIMG operands[2] (VDATA) must be the same as definitions[0] for atomics and "
841*61046927SAndroid Build Coastguard Worker "TFE/LWE loads",
842*61046927SAndroid Build Coastguard Worker instr.get());
843*61046927SAndroid Build Coastguard Worker }
844*61046927SAndroid Build Coastguard Worker
845*61046927SAndroid Build Coastguard Worker if (instr->mimg().strict_wqm) {
846*61046927SAndroid Build Coastguard Worker check(instr->operands[3].hasRegClass() &&
847*61046927SAndroid Build Coastguard Worker instr->operands[3].regClass().is_linear_vgpr(),
848*61046927SAndroid Build Coastguard Worker "MIMG operands[3] must be temp linear VGPR.", instr.get());
849*61046927SAndroid Build Coastguard Worker
850*61046927SAndroid Build Coastguard Worker unsigned total_size = 0;
851*61046927SAndroid Build Coastguard Worker for (unsigned i = 4; i < instr->operands.size(); i++) {
852*61046927SAndroid Build Coastguard Worker check(instr->operands[i].hasRegClass() && instr->operands[i].regClass() == v1,
853*61046927SAndroid Build Coastguard Worker "MIMG operands[4+] (VADDR) must be v1", instr.get());
854*61046927SAndroid Build Coastguard Worker total_size += instr->operands[i].bytes();
855*61046927SAndroid Build Coastguard Worker }
856*61046927SAndroid Build Coastguard Worker check(total_size <= instr->operands[3].bytes(),
857*61046927SAndroid Build Coastguard Worker "MIMG operands[4+] must fit within operands[3].", instr.get());
858*61046927SAndroid Build Coastguard Worker } else {
859*61046927SAndroid Build Coastguard Worker check(instr->operands.size() == 4 || program->gfx_level >= GFX10,
860*61046927SAndroid Build Coastguard Worker "NSA is only supported on GFX10+", instr.get());
861*61046927SAndroid Build Coastguard Worker for (unsigned i = 3; i < instr->operands.size(); i++) {
862*61046927SAndroid Build Coastguard Worker check(instr->operands[i].hasRegClass() &&
863*61046927SAndroid Build Coastguard Worker instr->operands[i].regClass().type() == RegType::vgpr,
864*61046927SAndroid Build Coastguard Worker "MIMG operands[3+] (VADDR) must be VGPR", instr.get());
865*61046927SAndroid Build Coastguard Worker if (instr->operands.size() > 4) {
866*61046927SAndroid Build Coastguard Worker if (program->gfx_level < GFX11) {
867*61046927SAndroid Build Coastguard Worker check(instr->operands[i].regClass() == v1,
868*61046927SAndroid Build Coastguard Worker "GFX10 MIMG VADDR must be v1 if NSA is used", instr.get());
869*61046927SAndroid Build Coastguard Worker } else {
870*61046927SAndroid Build Coastguard Worker unsigned num_scalar =
871*61046927SAndroid Build Coastguard Worker program->gfx_level >= GFX12 ? (instr->operands.size() - 4) : 4;
872*61046927SAndroid Build Coastguard Worker if (instr->opcode != aco_opcode::image_bvh_intersect_ray &&
873*61046927SAndroid Build Coastguard Worker instr->opcode != aco_opcode::image_bvh64_intersect_ray &&
874*61046927SAndroid Build Coastguard Worker i < 3 + num_scalar) {
875*61046927SAndroid Build Coastguard Worker check(instr->operands[i].regClass() == v1,
876*61046927SAndroid Build Coastguard Worker "first 4 GFX11 MIMG VADDR must be v1 if NSA is used", instr.get());
877*61046927SAndroid Build Coastguard Worker }
878*61046927SAndroid Build Coastguard Worker }
879*61046927SAndroid Build Coastguard Worker }
880*61046927SAndroid Build Coastguard Worker }
881*61046927SAndroid Build Coastguard Worker }
882*61046927SAndroid Build Coastguard Worker
883*61046927SAndroid Build Coastguard Worker if (instr->definitions.size()) {
884*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
885*61046927SAndroid Build Coastguard Worker "MIMG definitions[0] (VDATA) must be VGPR", instr.get());
886*61046927SAndroid Build Coastguard Worker check(instr->mimg().d16 || !instr->definitions[0].regClass().is_subdword(),
887*61046927SAndroid Build Coastguard Worker "Only D16 MIMG instructions can load subdword values.", instr.get());
888*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].bytes() <= 8 || !instr->mimg().d16,
889*61046927SAndroid Build Coastguard Worker "D16 MIMG instructions can only load up to 8 bytes.", instr.get());
890*61046927SAndroid Build Coastguard Worker }
891*61046927SAndroid Build Coastguard Worker break;
892*61046927SAndroid Build Coastguard Worker }
893*61046927SAndroid Build Coastguard Worker case Format::DS: {
894*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
895*61046927SAndroid Build Coastguard Worker check(op.isOfType(RegType::vgpr) || op.physReg() == m0 || op.isUndefined(),
896*61046927SAndroid Build Coastguard Worker "Only VGPRs are valid DS instruction operands", instr.get());
897*61046927SAndroid Build Coastguard Worker }
898*61046927SAndroid Build Coastguard Worker if (!instr->definitions.empty())
899*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
900*61046927SAndroid Build Coastguard Worker "DS instruction must return VGPR", instr.get());
901*61046927SAndroid Build Coastguard Worker break;
902*61046927SAndroid Build Coastguard Worker }
903*61046927SAndroid Build Coastguard Worker case Format::EXP: {
904*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 4; i++)
905*61046927SAndroid Build Coastguard Worker check(instr->operands[i].isOfType(RegType::vgpr),
906*61046927SAndroid Build Coastguard Worker "Only VGPRs are valid Export arguments", instr.get());
907*61046927SAndroid Build Coastguard Worker break;
908*61046927SAndroid Build Coastguard Worker }
909*61046927SAndroid Build Coastguard Worker case Format::FLAT:
910*61046927SAndroid Build Coastguard Worker check(instr->operands[1].isUndefined(), "Flat instructions don't support SADDR",
911*61046927SAndroid Build Coastguard Worker instr.get());
912*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
913*61046927SAndroid Build Coastguard Worker case Format::GLOBAL:
914*61046927SAndroid Build Coastguard Worker check(instr->operands[0].isOfType(RegType::vgpr), "FLAT/GLOBAL address must be vgpr",
915*61046927SAndroid Build Coastguard Worker instr.get());
916*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
917*61046927SAndroid Build Coastguard Worker case Format::SCRATCH: {
918*61046927SAndroid Build Coastguard Worker check(instr->operands[0].isOfType(RegType::vgpr),
919*61046927SAndroid Build Coastguard Worker "FLAT/GLOBAL/SCRATCH address must be undefined or vgpr", instr.get());
920*61046927SAndroid Build Coastguard Worker check(instr->operands[1].isOfType(RegType::sgpr),
921*61046927SAndroid Build Coastguard Worker "FLAT/GLOBAL/SCRATCH sgpr address must be undefined or sgpr", instr.get());
922*61046927SAndroid Build Coastguard Worker if (instr->format == Format::SCRATCH && program->gfx_level < GFX10_3)
923*61046927SAndroid Build Coastguard Worker check(!instr->operands[0].isUndefined() || !instr->operands[1].isUndefined(),
924*61046927SAndroid Build Coastguard Worker "SCRATCH must have either SADDR or ADDR operand", instr.get());
925*61046927SAndroid Build Coastguard Worker if (!instr->definitions.empty())
926*61046927SAndroid Build Coastguard Worker check(instr->definitions[0].regClass().type() == RegType::vgpr,
927*61046927SAndroid Build Coastguard Worker "FLAT/GLOBAL/SCRATCH result must be vgpr", instr.get());
928*61046927SAndroid Build Coastguard Worker else
929*61046927SAndroid Build Coastguard Worker check(instr->operands[2].isOfType(RegType::vgpr),
930*61046927SAndroid Build Coastguard Worker "FLAT/GLOBAL/SCRATCH data must be vgpr", instr.get());
931*61046927SAndroid Build Coastguard Worker break;
932*61046927SAndroid Build Coastguard Worker }
933*61046927SAndroid Build Coastguard Worker case Format::LDSDIR: {
934*61046927SAndroid Build Coastguard Worker check(instr->definitions.size() == 1 && instr->definitions[0].regClass() == v1,
935*61046927SAndroid Build Coastguard Worker "LDSDIR must have an v1 definition", instr.get());
936*61046927SAndroid Build Coastguard Worker check(instr->operands.size() == 1, "LDSDIR must have an operand", instr.get());
937*61046927SAndroid Build Coastguard Worker if (!instr->operands.empty()) {
938*61046927SAndroid Build Coastguard Worker check(instr->operands[0].regClass() == s1, "LDSDIR must have an s1 operand",
939*61046927SAndroid Build Coastguard Worker instr.get());
940*61046927SAndroid Build Coastguard Worker check(instr->operands[0].isFixed() && instr->operands[0].physReg() == m0,
941*61046927SAndroid Build Coastguard Worker "LDSDIR must have an operand fixed to m0", instr.get());
942*61046927SAndroid Build Coastguard Worker }
943*61046927SAndroid Build Coastguard Worker break;
944*61046927SAndroid Build Coastguard Worker }
945*61046927SAndroid Build Coastguard Worker default: break;
946*61046927SAndroid Build Coastguard Worker }
947*61046927SAndroid Build Coastguard Worker }
948*61046927SAndroid Build Coastguard Worker }
949*61046927SAndroid Build Coastguard Worker
950*61046927SAndroid Build Coastguard Worker return is_valid;
951*61046927SAndroid Build Coastguard Worker }
952*61046927SAndroid Build Coastguard Worker
953*61046927SAndroid Build Coastguard Worker bool
validate_cfg(Program * program)954*61046927SAndroid Build Coastguard Worker validate_cfg(Program* program)
955*61046927SAndroid Build Coastguard Worker {
956*61046927SAndroid Build Coastguard Worker if (!(debug_flags & DEBUG_VALIDATE_IR))
957*61046927SAndroid Build Coastguard Worker return true;
958*61046927SAndroid Build Coastguard Worker
959*61046927SAndroid Build Coastguard Worker bool is_valid = true;
960*61046927SAndroid Build Coastguard Worker auto check_block = [&program, &is_valid](bool success, const char* msg,
961*61046927SAndroid Build Coastguard Worker aco::Block* block) -> void
962*61046927SAndroid Build Coastguard Worker {
963*61046927SAndroid Build Coastguard Worker if (!success) {
964*61046927SAndroid Build Coastguard Worker aco_err(program, "%s: BB%u", msg, block->index);
965*61046927SAndroid Build Coastguard Worker is_valid = false;
966*61046927SAndroid Build Coastguard Worker }
967*61046927SAndroid Build Coastguard Worker };
968*61046927SAndroid Build Coastguard Worker
969*61046927SAndroid Build Coastguard Worker /* validate CFG */
970*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
971*61046927SAndroid Build Coastguard Worker Block& block = program->blocks[i];
972*61046927SAndroid Build Coastguard Worker check_block(block.index == i, "block.index must match actual index", &block);
973*61046927SAndroid Build Coastguard Worker
974*61046927SAndroid Build Coastguard Worker /* predecessors/successors should be sorted */
975*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j + 1 < block.linear_preds.size(); j++)
976*61046927SAndroid Build Coastguard Worker check_block(block.linear_preds[j] < block.linear_preds[j + 1],
977*61046927SAndroid Build Coastguard Worker "linear predecessors must be sorted", &block);
978*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j + 1 < block.logical_preds.size(); j++)
979*61046927SAndroid Build Coastguard Worker check_block(block.logical_preds[j] < block.logical_preds[j + 1],
980*61046927SAndroid Build Coastguard Worker "logical predecessors must be sorted", &block);
981*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j + 1 < block.linear_succs.size(); j++)
982*61046927SAndroid Build Coastguard Worker check_block(block.linear_succs[j] < block.linear_succs[j + 1],
983*61046927SAndroid Build Coastguard Worker "linear successors must be sorted", &block);
984*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j + 1 < block.logical_succs.size(); j++)
985*61046927SAndroid Build Coastguard Worker check_block(block.logical_succs[j] < block.logical_succs[j + 1],
986*61046927SAndroid Build Coastguard Worker "logical successors must be sorted", &block);
987*61046927SAndroid Build Coastguard Worker
988*61046927SAndroid Build Coastguard Worker /* critical edges are not allowed */
989*61046927SAndroid Build Coastguard Worker if (block.linear_preds.size() > 1) {
990*61046927SAndroid Build Coastguard Worker for (unsigned pred : block.linear_preds)
991*61046927SAndroid Build Coastguard Worker check_block(program->blocks[pred].linear_succs.size() == 1,
992*61046927SAndroid Build Coastguard Worker "linear critical edges are not allowed", &program->blocks[pred]);
993*61046927SAndroid Build Coastguard Worker for (unsigned pred : block.logical_preds)
994*61046927SAndroid Build Coastguard Worker check_block(program->blocks[pred].logical_succs.size() == 1,
995*61046927SAndroid Build Coastguard Worker "logical critical edges are not allowed", &program->blocks[pred]);
996*61046927SAndroid Build Coastguard Worker }
997*61046927SAndroid Build Coastguard Worker }
998*61046927SAndroid Build Coastguard Worker
999*61046927SAndroid Build Coastguard Worker return is_valid;
1000*61046927SAndroid Build Coastguard Worker }
1001*61046927SAndroid Build Coastguard Worker
1002*61046927SAndroid Build Coastguard Worker bool
validate_live_vars(Program * program)1003*61046927SAndroid Build Coastguard Worker validate_live_vars(Program* program)
1004*61046927SAndroid Build Coastguard Worker {
1005*61046927SAndroid Build Coastguard Worker if (!(debug_flags & DEBUG_VALIDATE_LIVE_VARS))
1006*61046927SAndroid Build Coastguard Worker return true;
1007*61046927SAndroid Build Coastguard Worker
1008*61046927SAndroid Build Coastguard Worker bool is_valid = true;
1009*61046927SAndroid Build Coastguard Worker const int prev_num_waves = program->num_waves;
1010*61046927SAndroid Build Coastguard Worker const monotonic_buffer_resource old_memory = std::move(program->live.memory);
1011*61046927SAndroid Build Coastguard Worker const std::vector<IDSet> prev_live_in = std::move(program->live.live_in);
1012*61046927SAndroid Build Coastguard Worker const RegisterDemand prev_max_demand = program->max_reg_demand;
1013*61046927SAndroid Build Coastguard Worker std::vector<RegisterDemand> block_demands(program->blocks.size());
1014*61046927SAndroid Build Coastguard Worker std::vector<RegisterDemand> live_in_demands(program->blocks.size());
1015*61046927SAndroid Build Coastguard Worker std::vector<std::vector<RegisterDemand>> register_demands(program->blocks.size());
1016*61046927SAndroid Build Coastguard Worker
1017*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
1018*61046927SAndroid Build Coastguard Worker Block& b = program->blocks[i];
1019*61046927SAndroid Build Coastguard Worker block_demands[i] = b.register_demand;
1020*61046927SAndroid Build Coastguard Worker live_in_demands[i] = b.live_in_demand;
1021*61046927SAndroid Build Coastguard Worker register_demands[i].reserve(b.instructions.size());
1022*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < b.instructions.size(); j++)
1023*61046927SAndroid Build Coastguard Worker register_demands[i].emplace_back(b.instructions[j]->register_demand);
1024*61046927SAndroid Build Coastguard Worker }
1025*61046927SAndroid Build Coastguard Worker
1026*61046927SAndroid Build Coastguard Worker aco::live_var_analysis(program);
1027*61046927SAndroid Build Coastguard Worker
1028*61046927SAndroid Build Coastguard Worker /* Validate RegisterDemand calculation */
1029*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
1030*61046927SAndroid Build Coastguard Worker Block& b = program->blocks[i];
1031*61046927SAndroid Build Coastguard Worker
1032*61046927SAndroid Build Coastguard Worker if (!(b.register_demand == block_demands[i])) {
1033*61046927SAndroid Build Coastguard Worker is_valid = false;
1034*61046927SAndroid Build Coastguard Worker aco_err(program,
1035*61046927SAndroid Build Coastguard Worker "Register Demand not updated correctly for BB%d: got (%3u vgpr, %3u sgpr), but "
1036*61046927SAndroid Build Coastguard Worker "should be (%3u vgpr, %3u sgpr)",
1037*61046927SAndroid Build Coastguard Worker i, block_demands[i].vgpr, block_demands[i].sgpr, b.register_demand.vgpr,
1038*61046927SAndroid Build Coastguard Worker b.register_demand.sgpr);
1039*61046927SAndroid Build Coastguard Worker }
1040*61046927SAndroid Build Coastguard Worker if (!(b.live_in_demand == live_in_demands[i])) {
1041*61046927SAndroid Build Coastguard Worker is_valid = false;
1042*61046927SAndroid Build Coastguard Worker aco_err(program,
1043*61046927SAndroid Build Coastguard Worker "Live-in Demand not updated correctly for BB%d: got (%3u vgpr, %3u sgpr), but "
1044*61046927SAndroid Build Coastguard Worker "should be (%3u vgpr, %3u sgpr)",
1045*61046927SAndroid Build Coastguard Worker i, live_in_demands[i].vgpr, live_in_demands[i].sgpr, b.live_in_demand.vgpr,
1046*61046927SAndroid Build Coastguard Worker b.live_in_demand.sgpr);
1047*61046927SAndroid Build Coastguard Worker }
1048*61046927SAndroid Build Coastguard Worker
1049*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < b.instructions.size(); j++) {
1050*61046927SAndroid Build Coastguard Worker if (b.instructions[j]->register_demand == register_demands[i][j])
1051*61046927SAndroid Build Coastguard Worker continue;
1052*61046927SAndroid Build Coastguard Worker
1053*61046927SAndroid Build Coastguard Worker char* out;
1054*61046927SAndroid Build Coastguard Worker size_t outsize;
1055*61046927SAndroid Build Coastguard Worker struct u_memstream mem;
1056*61046927SAndroid Build Coastguard Worker u_memstream_open(&mem, &out, &outsize);
1057*61046927SAndroid Build Coastguard Worker FILE* const memf = u_memstream_get(&mem);
1058*61046927SAndroid Build Coastguard Worker
1059*61046927SAndroid Build Coastguard Worker fprintf(memf,
1060*61046927SAndroid Build Coastguard Worker "Register Demand not updated correctly: got (%3u vgpr, %3u sgpr), but should be "
1061*61046927SAndroid Build Coastguard Worker "(%3u vgpr, %3u sgpr): \n\t",
1062*61046927SAndroid Build Coastguard Worker register_demands[i][j].vgpr, register_demands[i][j].sgpr,
1063*61046927SAndroid Build Coastguard Worker b.instructions[j]->register_demand.vgpr, b.instructions[j]->register_demand.sgpr);
1064*61046927SAndroid Build Coastguard Worker aco_print_instr(program->gfx_level, b.instructions[j].get(), memf, print_kill);
1065*61046927SAndroid Build Coastguard Worker u_memstream_close(&mem);
1066*61046927SAndroid Build Coastguard Worker
1067*61046927SAndroid Build Coastguard Worker aco_err(program, "%s", out);
1068*61046927SAndroid Build Coastguard Worker free(out);
1069*61046927SAndroid Build Coastguard Worker
1070*61046927SAndroid Build Coastguard Worker is_valid = false;
1071*61046927SAndroid Build Coastguard Worker }
1072*61046927SAndroid Build Coastguard Worker }
1073*61046927SAndroid Build Coastguard Worker if (!(program->max_reg_demand == prev_max_demand) || program->num_waves != prev_num_waves) {
1074*61046927SAndroid Build Coastguard Worker is_valid = false;
1075*61046927SAndroid Build Coastguard Worker aco_err(program,
1076*61046927SAndroid Build Coastguard Worker "Max Register Demand and Num Waves not updated correctly: got (%3u vgpr, %3u sgpr) "
1077*61046927SAndroid Build Coastguard Worker "and %2u waves, but should be (%3u vgpr, %3u sgpr) and %2u waves",
1078*61046927SAndroid Build Coastguard Worker prev_max_demand.vgpr, prev_max_demand.sgpr, prev_num_waves,
1079*61046927SAndroid Build Coastguard Worker program->max_reg_demand.vgpr, program->max_reg_demand.sgpr, program->num_waves);
1080*61046927SAndroid Build Coastguard Worker }
1081*61046927SAndroid Build Coastguard Worker
1082*61046927SAndroid Build Coastguard Worker /* Validate Live-in sets */
1083*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
1084*61046927SAndroid Build Coastguard Worker if (prev_live_in[i] != program->live.live_in[i]) {
1085*61046927SAndroid Build Coastguard Worker char* out;
1086*61046927SAndroid Build Coastguard Worker size_t outsize;
1087*61046927SAndroid Build Coastguard Worker struct u_memstream mem;
1088*61046927SAndroid Build Coastguard Worker u_memstream_open(&mem, &out, &outsize);
1089*61046927SAndroid Build Coastguard Worker FILE* const memf = u_memstream_get(&mem);
1090*61046927SAndroid Build Coastguard Worker
1091*61046927SAndroid Build Coastguard Worker fprintf(memf, "Live-in set not updated correctly for BB%d:", i);
1092*61046927SAndroid Build Coastguard Worker fprintf(memf, "\nMissing values: ");
1093*61046927SAndroid Build Coastguard Worker for (unsigned t : program->live.live_in[i]) {
1094*61046927SAndroid Build Coastguard Worker if (prev_live_in[i].count(t) == 0)
1095*61046927SAndroid Build Coastguard Worker fprintf(memf, "%%%d, ", t);
1096*61046927SAndroid Build Coastguard Worker }
1097*61046927SAndroid Build Coastguard Worker fprintf(memf, "\nAdditional values: ");
1098*61046927SAndroid Build Coastguard Worker for (unsigned t : prev_live_in[i]) {
1099*61046927SAndroid Build Coastguard Worker if (program->live.live_in[i].count(t) == 0)
1100*61046927SAndroid Build Coastguard Worker fprintf(memf, "%%%d, ", t);
1101*61046927SAndroid Build Coastguard Worker }
1102*61046927SAndroid Build Coastguard Worker u_memstream_close(&mem);
1103*61046927SAndroid Build Coastguard Worker aco_err(program, "%s", out);
1104*61046927SAndroid Build Coastguard Worker free(out);
1105*61046927SAndroid Build Coastguard Worker is_valid = false;
1106*61046927SAndroid Build Coastguard Worker }
1107*61046927SAndroid Build Coastguard Worker }
1108*61046927SAndroid Build Coastguard Worker
1109*61046927SAndroid Build Coastguard Worker return is_valid;
1110*61046927SAndroid Build Coastguard Worker }
1111*61046927SAndroid Build Coastguard Worker
1112*61046927SAndroid Build Coastguard Worker /* RA validation */
1113*61046927SAndroid Build Coastguard Worker namespace {
1114*61046927SAndroid Build Coastguard Worker
1115*61046927SAndroid Build Coastguard Worker struct Location {
Locationaco::__anon701c7ea20311::Location1116*61046927SAndroid Build Coastguard Worker Location() : block(NULL), instr(NULL) {}
1117*61046927SAndroid Build Coastguard Worker
1118*61046927SAndroid Build Coastguard Worker Block* block;
1119*61046927SAndroid Build Coastguard Worker Instruction* instr; // NULL if it's the block's live-in
1120*61046927SAndroid Build Coastguard Worker };
1121*61046927SAndroid Build Coastguard Worker
1122*61046927SAndroid Build Coastguard Worker struct Assignment {
1123*61046927SAndroid Build Coastguard Worker Location defloc;
1124*61046927SAndroid Build Coastguard Worker Location firstloc;
1125*61046927SAndroid Build Coastguard Worker PhysReg reg;
1126*61046927SAndroid Build Coastguard Worker bool valid;
1127*61046927SAndroid Build Coastguard Worker };
1128*61046927SAndroid Build Coastguard Worker
1129*61046927SAndroid Build Coastguard Worker bool
ra_fail(Program * program,Location loc,Location loc2,const char * fmt,...)1130*61046927SAndroid Build Coastguard Worker ra_fail(Program* program, Location loc, Location loc2, const char* fmt, ...)
1131*61046927SAndroid Build Coastguard Worker {
1132*61046927SAndroid Build Coastguard Worker va_list args;
1133*61046927SAndroid Build Coastguard Worker va_start(args, fmt);
1134*61046927SAndroid Build Coastguard Worker char msg[1024];
1135*61046927SAndroid Build Coastguard Worker vsprintf(msg, fmt, args);
1136*61046927SAndroid Build Coastguard Worker va_end(args);
1137*61046927SAndroid Build Coastguard Worker
1138*61046927SAndroid Build Coastguard Worker char* out;
1139*61046927SAndroid Build Coastguard Worker size_t outsize;
1140*61046927SAndroid Build Coastguard Worker struct u_memstream mem;
1141*61046927SAndroid Build Coastguard Worker u_memstream_open(&mem, &out, &outsize);
1142*61046927SAndroid Build Coastguard Worker FILE* const memf = u_memstream_get(&mem);
1143*61046927SAndroid Build Coastguard Worker
1144*61046927SAndroid Build Coastguard Worker fprintf(memf, "RA error found at instruction in BB%d:\n", loc.block->index);
1145*61046927SAndroid Build Coastguard Worker if (loc.instr) {
1146*61046927SAndroid Build Coastguard Worker aco_print_instr(program->gfx_level, loc.instr, memf);
1147*61046927SAndroid Build Coastguard Worker fprintf(memf, "\n%s", msg);
1148*61046927SAndroid Build Coastguard Worker } else {
1149*61046927SAndroid Build Coastguard Worker fprintf(memf, "%s", msg);
1150*61046927SAndroid Build Coastguard Worker }
1151*61046927SAndroid Build Coastguard Worker if (loc2.block) {
1152*61046927SAndroid Build Coastguard Worker fprintf(memf, " in BB%d:\n", loc2.block->index);
1153*61046927SAndroid Build Coastguard Worker aco_print_instr(program->gfx_level, loc2.instr, memf);
1154*61046927SAndroid Build Coastguard Worker }
1155*61046927SAndroid Build Coastguard Worker fprintf(memf, "\n\n");
1156*61046927SAndroid Build Coastguard Worker u_memstream_close(&mem);
1157*61046927SAndroid Build Coastguard Worker
1158*61046927SAndroid Build Coastguard Worker aco_err(program, "%s", out);
1159*61046927SAndroid Build Coastguard Worker free(out);
1160*61046927SAndroid Build Coastguard Worker
1161*61046927SAndroid Build Coastguard Worker return true;
1162*61046927SAndroid Build Coastguard Worker }
1163*61046927SAndroid Build Coastguard Worker
1164*61046927SAndroid Build Coastguard Worker bool
validate_subdword_operand(amd_gfx_level gfx_level,const aco_ptr<Instruction> & instr,unsigned index)1165*61046927SAndroid Build Coastguard Worker validate_subdword_operand(amd_gfx_level gfx_level, const aco_ptr<Instruction>& instr,
1166*61046927SAndroid Build Coastguard Worker unsigned index)
1167*61046927SAndroid Build Coastguard Worker {
1168*61046927SAndroid Build Coastguard Worker Operand op = instr->operands[index];
1169*61046927SAndroid Build Coastguard Worker unsigned byte = op.physReg().byte();
1170*61046927SAndroid Build Coastguard Worker
1171*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_as_uniform)
1172*61046927SAndroid Build Coastguard Worker return byte == 0;
1173*61046927SAndroid Build Coastguard Worker if (instr->isPseudo() && gfx_level >= GFX8)
1174*61046927SAndroid Build Coastguard Worker return true;
1175*61046927SAndroid Build Coastguard Worker if (instr->isSDWA())
1176*61046927SAndroid Build Coastguard Worker return byte + instr->sdwa().sel[index].offset() + instr->sdwa().sel[index].size() <= 4 &&
1177*61046927SAndroid Build Coastguard Worker byte % instr->sdwa().sel[index].size() == 0;
1178*61046927SAndroid Build Coastguard Worker if (instr->isVOP3P()) {
1179*61046927SAndroid Build Coastguard Worker bool fma_mix = instr->opcode == aco_opcode::v_fma_mixlo_f16 ||
1180*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_fma_mixhi_f16 ||
1181*61046927SAndroid Build Coastguard Worker instr->opcode == aco_opcode::v_fma_mix_f32;
1182*61046927SAndroid Build Coastguard Worker return instr->valu().opsel_lo[index] == (byte >> 1) &&
1183*61046927SAndroid Build Coastguard Worker instr->valu().opsel_hi[index] == (fma_mix || (byte >> 1));
1184*61046927SAndroid Build Coastguard Worker }
1185*61046927SAndroid Build Coastguard Worker if (byte == 2 && can_use_opsel(gfx_level, instr->opcode, index))
1186*61046927SAndroid Build Coastguard Worker return true;
1187*61046927SAndroid Build Coastguard Worker
1188*61046927SAndroid Build Coastguard Worker switch (instr->opcode) {
1189*61046927SAndroid Build Coastguard Worker case aco_opcode::v_cvt_f32_ubyte1:
1190*61046927SAndroid Build Coastguard Worker if (byte == 1)
1191*61046927SAndroid Build Coastguard Worker return true;
1192*61046927SAndroid Build Coastguard Worker break;
1193*61046927SAndroid Build Coastguard Worker case aco_opcode::v_cvt_f32_ubyte2:
1194*61046927SAndroid Build Coastguard Worker if (byte == 2)
1195*61046927SAndroid Build Coastguard Worker return true;
1196*61046927SAndroid Build Coastguard Worker break;
1197*61046927SAndroid Build Coastguard Worker case aco_opcode::v_cvt_f32_ubyte3:
1198*61046927SAndroid Build Coastguard Worker if (byte == 3)
1199*61046927SAndroid Build Coastguard Worker return true;
1200*61046927SAndroid Build Coastguard Worker break;
1201*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_write_b8_d16_hi:
1202*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_write_b16_d16_hi:
1203*61046927SAndroid Build Coastguard Worker if (byte == 2 && index == 1)
1204*61046927SAndroid Build Coastguard Worker return true;
1205*61046927SAndroid Build Coastguard Worker break;
1206*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_store_byte_d16_hi:
1207*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_store_short_d16_hi:
1208*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_store_format_d16_hi_x:
1209*61046927SAndroid Build Coastguard Worker if (byte == 2 && index == 3)
1210*61046927SAndroid Build Coastguard Worker return true;
1211*61046927SAndroid Build Coastguard Worker break;
1212*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_store_byte_d16_hi:
1213*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_store_short_d16_hi:
1214*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_store_byte_d16_hi:
1215*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_store_short_d16_hi:
1216*61046927SAndroid Build Coastguard Worker case aco_opcode::global_store_byte_d16_hi:
1217*61046927SAndroid Build Coastguard Worker case aco_opcode::global_store_short_d16_hi:
1218*61046927SAndroid Build Coastguard Worker if (byte == 2 && index == 2)
1219*61046927SAndroid Build Coastguard Worker return true;
1220*61046927SAndroid Build Coastguard Worker break;
1221*61046927SAndroid Build Coastguard Worker default: break;
1222*61046927SAndroid Build Coastguard Worker }
1223*61046927SAndroid Build Coastguard Worker
1224*61046927SAndroid Build Coastguard Worker return byte == 0;
1225*61046927SAndroid Build Coastguard Worker }
1226*61046927SAndroid Build Coastguard Worker
1227*61046927SAndroid Build Coastguard Worker bool
validate_subdword_definition(amd_gfx_level gfx_level,const aco_ptr<Instruction> & instr)1228*61046927SAndroid Build Coastguard Worker validate_subdword_definition(amd_gfx_level gfx_level, const aco_ptr<Instruction>& instr)
1229*61046927SAndroid Build Coastguard Worker {
1230*61046927SAndroid Build Coastguard Worker Definition def = instr->definitions[0];
1231*61046927SAndroid Build Coastguard Worker unsigned byte = def.physReg().byte();
1232*61046927SAndroid Build Coastguard Worker
1233*61046927SAndroid Build Coastguard Worker if (instr->isPseudo() && gfx_level >= GFX8)
1234*61046927SAndroid Build Coastguard Worker return true;
1235*61046927SAndroid Build Coastguard Worker if (instr->isSDWA())
1236*61046927SAndroid Build Coastguard Worker return byte + instr->sdwa().dst_sel.offset() + instr->sdwa().dst_sel.size() <= 4 &&
1237*61046927SAndroid Build Coastguard Worker byte % instr->sdwa().dst_sel.size() == 0;
1238*61046927SAndroid Build Coastguard Worker if (byte == 2 && can_use_opsel(gfx_level, instr->opcode, -1))
1239*61046927SAndroid Build Coastguard Worker return true;
1240*61046927SAndroid Build Coastguard Worker
1241*61046927SAndroid Build Coastguard Worker switch (instr->opcode) {
1242*61046927SAndroid Build Coastguard Worker case aco_opcode::v_interp_p2_hi_f16:
1243*61046927SAndroid Build Coastguard Worker case aco_opcode::v_fma_mixhi_f16:
1244*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_ubyte_d16_hi:
1245*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_sbyte_d16_hi:
1246*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_short_d16_hi:
1247*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_format_d16_hi_x:
1248*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_ubyte_d16_hi:
1249*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_short_d16_hi:
1250*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_ubyte_d16_hi:
1251*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_short_d16_hi:
1252*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_ubyte_d16_hi:
1253*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_short_d16_hi:
1254*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u8_d16_hi:
1255*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u16_d16_hi: return byte == 2;
1256*61046927SAndroid Build Coastguard Worker case aco_opcode::p_v_cvt_pk_u8_f32: return true;
1257*61046927SAndroid Build Coastguard Worker default: break;
1258*61046927SAndroid Build Coastguard Worker }
1259*61046927SAndroid Build Coastguard Worker
1260*61046927SAndroid Build Coastguard Worker return byte == 0;
1261*61046927SAndroid Build Coastguard Worker }
1262*61046927SAndroid Build Coastguard Worker
1263*61046927SAndroid Build Coastguard Worker unsigned
get_subdword_bytes_written(Program * program,const aco_ptr<Instruction> & instr,unsigned index)1264*61046927SAndroid Build Coastguard Worker get_subdword_bytes_written(Program* program, const aco_ptr<Instruction>& instr, unsigned index)
1265*61046927SAndroid Build Coastguard Worker {
1266*61046927SAndroid Build Coastguard Worker amd_gfx_level gfx_level = program->gfx_level;
1267*61046927SAndroid Build Coastguard Worker Definition def = instr->definitions[index];
1268*61046927SAndroid Build Coastguard Worker
1269*61046927SAndroid Build Coastguard Worker if (instr->isPseudo())
1270*61046927SAndroid Build Coastguard Worker return gfx_level >= GFX8 ? def.bytes() : def.size() * 4u;
1271*61046927SAndroid Build Coastguard Worker if (instr->isVALU() || instr->isVINTRP()) {
1272*61046927SAndroid Build Coastguard Worker assert(def.bytes() <= 2);
1273*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_v_cvt_pk_u8_f32)
1274*61046927SAndroid Build Coastguard Worker return 1;
1275*61046927SAndroid Build Coastguard Worker
1276*61046927SAndroid Build Coastguard Worker if (instr->isSDWA())
1277*61046927SAndroid Build Coastguard Worker return instr->sdwa().dst_sel.size();
1278*61046927SAndroid Build Coastguard Worker
1279*61046927SAndroid Build Coastguard Worker if (instr_is_16bit(gfx_level, instr->opcode))
1280*61046927SAndroid Build Coastguard Worker return 2;
1281*61046927SAndroid Build Coastguard Worker
1282*61046927SAndroid Build Coastguard Worker return 4;
1283*61046927SAndroid Build Coastguard Worker }
1284*61046927SAndroid Build Coastguard Worker
1285*61046927SAndroid Build Coastguard Worker if (instr->isMIMG()) {
1286*61046927SAndroid Build Coastguard Worker assert(instr->mimg().d16);
1287*61046927SAndroid Build Coastguard Worker return program->dev.sram_ecc_enabled ? def.size() * 4u : def.bytes();
1288*61046927SAndroid Build Coastguard Worker }
1289*61046927SAndroid Build Coastguard Worker
1290*61046927SAndroid Build Coastguard Worker switch (instr->opcode) {
1291*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_ubyte_d16:
1292*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_sbyte_d16:
1293*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_short_d16:
1294*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_format_d16_x:
1295*61046927SAndroid Build Coastguard Worker case aco_opcode::tbuffer_load_format_d16_x:
1296*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_ubyte_d16:
1297*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_short_d16:
1298*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_ubyte_d16:
1299*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_short_d16:
1300*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_ubyte_d16:
1301*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_short_d16:
1302*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u8_d16:
1303*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u16_d16:
1304*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_ubyte_d16_hi:
1305*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_sbyte_d16_hi:
1306*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_short_d16_hi:
1307*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_format_d16_hi_x:
1308*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_ubyte_d16_hi:
1309*61046927SAndroid Build Coastguard Worker case aco_opcode::flat_load_short_d16_hi:
1310*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_ubyte_d16_hi:
1311*61046927SAndroid Build Coastguard Worker case aco_opcode::scratch_load_short_d16_hi:
1312*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_ubyte_d16_hi:
1313*61046927SAndroid Build Coastguard Worker case aco_opcode::global_load_short_d16_hi:
1314*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u8_d16_hi:
1315*61046927SAndroid Build Coastguard Worker case aco_opcode::ds_read_u16_d16_hi: return program->dev.sram_ecc_enabled ? 4 : 2;
1316*61046927SAndroid Build Coastguard Worker case aco_opcode::buffer_load_format_d16_xyz:
1317*61046927SAndroid Build Coastguard Worker case aco_opcode::tbuffer_load_format_d16_xyz: return program->dev.sram_ecc_enabled ? 8 : 6;
1318*61046927SAndroid Build Coastguard Worker default: return def.size() * 4;
1319*61046927SAndroid Build Coastguard Worker }
1320*61046927SAndroid Build Coastguard Worker }
1321*61046927SAndroid Build Coastguard Worker
1322*61046927SAndroid Build Coastguard Worker bool
validate_instr_defs(Program * program,std::array<unsigned,2048> & regs,const std::vector<Assignment> & assignments,const Location & loc,aco_ptr<Instruction> & instr)1323*61046927SAndroid Build Coastguard Worker validate_instr_defs(Program* program, std::array<unsigned, 2048>& regs,
1324*61046927SAndroid Build Coastguard Worker const std::vector<Assignment>& assignments, const Location& loc,
1325*61046927SAndroid Build Coastguard Worker aco_ptr<Instruction>& instr)
1326*61046927SAndroid Build Coastguard Worker {
1327*61046927SAndroid Build Coastguard Worker bool err = false;
1328*61046927SAndroid Build Coastguard Worker
1329*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->definitions.size(); i++) {
1330*61046927SAndroid Build Coastguard Worker Definition& def = instr->definitions[i];
1331*61046927SAndroid Build Coastguard Worker if (!def.isTemp())
1332*61046927SAndroid Build Coastguard Worker continue;
1333*61046927SAndroid Build Coastguard Worker Temp tmp = def.getTemp();
1334*61046927SAndroid Build Coastguard Worker PhysReg reg = assignments[tmp.id()].reg;
1335*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < tmp.bytes(); j++) {
1336*61046927SAndroid Build Coastguard Worker if (regs[reg.reg_b + j])
1337*61046927SAndroid Build Coastguard Worker err |=
1338*61046927SAndroid Build Coastguard Worker ra_fail(program, loc, assignments[regs[reg.reg_b + j]].defloc,
1339*61046927SAndroid Build Coastguard Worker "Assignment of element %d of %%%d already taken by %%%d from instruction", i,
1340*61046927SAndroid Build Coastguard Worker tmp.id(), regs[reg.reg_b + j]);
1341*61046927SAndroid Build Coastguard Worker regs[reg.reg_b + j] = tmp.id();
1342*61046927SAndroid Build Coastguard Worker }
1343*61046927SAndroid Build Coastguard Worker if (def.regClass().is_subdword() && def.bytes() < 4) {
1344*61046927SAndroid Build Coastguard Worker unsigned written = get_subdword_bytes_written(program, instr, i);
1345*61046927SAndroid Build Coastguard Worker /* If written=4, the instruction still might write the upper half. In that case, it's
1346*61046927SAndroid Build Coastguard Worker * the lower half that isn't preserved */
1347*61046927SAndroid Build Coastguard Worker for (unsigned j = reg.byte() & ~(written - 1); j < written; j++) {
1348*61046927SAndroid Build Coastguard Worker unsigned written_reg = reg.reg() * 4u + j;
1349*61046927SAndroid Build Coastguard Worker if (regs[written_reg] && regs[written_reg] != def.tempId())
1350*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, assignments[regs[written_reg]].defloc,
1351*61046927SAndroid Build Coastguard Worker "Assignment of element %d of %%%d overwrites the full register "
1352*61046927SAndroid Build Coastguard Worker "taken by %%%d from instruction",
1353*61046927SAndroid Build Coastguard Worker i, tmp.id(), regs[written_reg]);
1354*61046927SAndroid Build Coastguard Worker }
1355*61046927SAndroid Build Coastguard Worker }
1356*61046927SAndroid Build Coastguard Worker }
1357*61046927SAndroid Build Coastguard Worker
1358*61046927SAndroid Build Coastguard Worker for (const Definition& def : instr->definitions) {
1359*61046927SAndroid Build Coastguard Worker if (!def.isTemp())
1360*61046927SAndroid Build Coastguard Worker continue;
1361*61046927SAndroid Build Coastguard Worker if (def.isKill()) {
1362*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < def.getTemp().bytes(); j++)
1363*61046927SAndroid Build Coastguard Worker regs[def.physReg().reg_b + j] = 0;
1364*61046927SAndroid Build Coastguard Worker }
1365*61046927SAndroid Build Coastguard Worker }
1366*61046927SAndroid Build Coastguard Worker
1367*61046927SAndroid Build Coastguard Worker return err;
1368*61046927SAndroid Build Coastguard Worker }
1369*61046927SAndroid Build Coastguard Worker
1370*61046927SAndroid Build Coastguard Worker } /* end namespace */
1371*61046927SAndroid Build Coastguard Worker
1372*61046927SAndroid Build Coastguard Worker bool
validate_ra(Program * program)1373*61046927SAndroid Build Coastguard Worker validate_ra(Program* program)
1374*61046927SAndroid Build Coastguard Worker {
1375*61046927SAndroid Build Coastguard Worker if (!(debug_flags & DEBUG_VALIDATE_RA))
1376*61046927SAndroid Build Coastguard Worker return false;
1377*61046927SAndroid Build Coastguard Worker
1378*61046927SAndroid Build Coastguard Worker bool err = false;
1379*61046927SAndroid Build Coastguard Worker aco::live_var_analysis(program);
1380*61046927SAndroid Build Coastguard Worker std::vector<std::vector<Temp>> phi_sgpr_ops(program->blocks.size());
1381*61046927SAndroid Build Coastguard Worker uint16_t sgpr_limit = get_addr_sgpr_from_waves(program, program->num_waves);
1382*61046927SAndroid Build Coastguard Worker
1383*61046927SAndroid Build Coastguard Worker std::vector<Assignment> assignments(program->peekAllocationId());
1384*61046927SAndroid Build Coastguard Worker for (Block& block : program->blocks) {
1385*61046927SAndroid Build Coastguard Worker Location loc;
1386*61046927SAndroid Build Coastguard Worker loc.block = █
1387*61046927SAndroid Build Coastguard Worker for (aco_ptr<Instruction>& instr : block.instructions) {
1388*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_phi) {
1389*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
1390*61046927SAndroid Build Coastguard Worker if (instr->operands[i].isTemp() &&
1391*61046927SAndroid Build Coastguard Worker instr->operands[i].getTemp().type() == RegType::sgpr &&
1392*61046927SAndroid Build Coastguard Worker instr->operands[i].isFirstKill())
1393*61046927SAndroid Build Coastguard Worker phi_sgpr_ops[block.logical_preds[i]].emplace_back(instr->operands[i].getTemp());
1394*61046927SAndroid Build Coastguard Worker }
1395*61046927SAndroid Build Coastguard Worker }
1396*61046927SAndroid Build Coastguard Worker
1397*61046927SAndroid Build Coastguard Worker loc.instr = instr.get();
1398*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->operands.size(); i++) {
1399*61046927SAndroid Build Coastguard Worker Operand& op = instr->operands[i];
1400*61046927SAndroid Build Coastguard Worker if (!op.isTemp())
1401*61046927SAndroid Build Coastguard Worker continue;
1402*61046927SAndroid Build Coastguard Worker if (!op.isFixed())
1403*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(), "Operand %d is not assigned a register", i);
1404*61046927SAndroid Build Coastguard Worker if (assignments[op.tempId()].valid && assignments[op.tempId()].reg != op.physReg())
1405*61046927SAndroid Build Coastguard Worker err |=
1406*61046927SAndroid Build Coastguard Worker ra_fail(program, loc, assignments[op.tempId()].firstloc,
1407*61046927SAndroid Build Coastguard Worker "Operand %d has an inconsistent register assignment with instruction", i);
1408*61046927SAndroid Build Coastguard Worker if ((op.getTemp().type() == RegType::vgpr &&
1409*61046927SAndroid Build Coastguard Worker op.physReg().reg_b + op.bytes() > (256 + program->config->num_vgprs) * 4) ||
1410*61046927SAndroid Build Coastguard Worker (op.getTemp().type() == RegType::sgpr &&
1411*61046927SAndroid Build Coastguard Worker op.physReg() + op.size() > program->config->num_sgprs &&
1412*61046927SAndroid Build Coastguard Worker op.physReg() < sgpr_limit))
1413*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, assignments[op.tempId()].firstloc,
1414*61046927SAndroid Build Coastguard Worker "Operand %d has an out-of-bounds register assignment", i);
1415*61046927SAndroid Build Coastguard Worker if (op.physReg() == vcc && !program->needs_vcc)
1416*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(),
1417*61046927SAndroid Build Coastguard Worker "Operand %d fixed to vcc but needs_vcc=false", i);
1418*61046927SAndroid Build Coastguard Worker if (op.regClass().is_subdword() &&
1419*61046927SAndroid Build Coastguard Worker !validate_subdword_operand(program->gfx_level, instr, i))
1420*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(), "Operand %d not aligned correctly", i);
1421*61046927SAndroid Build Coastguard Worker if (!assignments[op.tempId()].firstloc.block)
1422*61046927SAndroid Build Coastguard Worker assignments[op.tempId()].firstloc = loc;
1423*61046927SAndroid Build Coastguard Worker if (!assignments[op.tempId()].defloc.block) {
1424*61046927SAndroid Build Coastguard Worker assignments[op.tempId()].reg = op.physReg();
1425*61046927SAndroid Build Coastguard Worker assignments[op.tempId()].valid = true;
1426*61046927SAndroid Build Coastguard Worker }
1427*61046927SAndroid Build Coastguard Worker }
1428*61046927SAndroid Build Coastguard Worker
1429*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->definitions.size(); i++) {
1430*61046927SAndroid Build Coastguard Worker Definition& def = instr->definitions[i];
1431*61046927SAndroid Build Coastguard Worker if (!def.isTemp())
1432*61046927SAndroid Build Coastguard Worker continue;
1433*61046927SAndroid Build Coastguard Worker if (!def.isFixed())
1434*61046927SAndroid Build Coastguard Worker err |=
1435*61046927SAndroid Build Coastguard Worker ra_fail(program, loc, Location(), "Definition %d is not assigned a register", i);
1436*61046927SAndroid Build Coastguard Worker if (assignments[def.tempId()].defloc.block)
1437*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, assignments[def.tempId()].defloc,
1438*61046927SAndroid Build Coastguard Worker "Temporary %%%d also defined by instruction", def.tempId());
1439*61046927SAndroid Build Coastguard Worker if ((def.getTemp().type() == RegType::vgpr &&
1440*61046927SAndroid Build Coastguard Worker def.physReg().reg_b + def.bytes() > (256 + program->config->num_vgprs) * 4) ||
1441*61046927SAndroid Build Coastguard Worker (def.getTemp().type() == RegType::sgpr &&
1442*61046927SAndroid Build Coastguard Worker def.physReg() + def.size() > program->config->num_sgprs &&
1443*61046927SAndroid Build Coastguard Worker def.physReg() < sgpr_limit))
1444*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, assignments[def.tempId()].firstloc,
1445*61046927SAndroid Build Coastguard Worker "Definition %d has an out-of-bounds register assignment", i);
1446*61046927SAndroid Build Coastguard Worker if (def.physReg() == vcc && !program->needs_vcc)
1447*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(),
1448*61046927SAndroid Build Coastguard Worker "Definition %d fixed to vcc but needs_vcc=false", i);
1449*61046927SAndroid Build Coastguard Worker if (def.regClass().is_subdword() &&
1450*61046927SAndroid Build Coastguard Worker !validate_subdword_definition(program->gfx_level, instr))
1451*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(), "Definition %d not aligned correctly", i);
1452*61046927SAndroid Build Coastguard Worker if (!assignments[def.tempId()].firstloc.block)
1453*61046927SAndroid Build Coastguard Worker assignments[def.tempId()].firstloc = loc;
1454*61046927SAndroid Build Coastguard Worker assignments[def.tempId()].defloc = loc;
1455*61046927SAndroid Build Coastguard Worker assignments[def.tempId()].reg = def.physReg();
1456*61046927SAndroid Build Coastguard Worker assignments[def.tempId()].valid = true;
1457*61046927SAndroid Build Coastguard Worker }
1458*61046927SAndroid Build Coastguard Worker }
1459*61046927SAndroid Build Coastguard Worker }
1460*61046927SAndroid Build Coastguard Worker
1461*61046927SAndroid Build Coastguard Worker for (Block& block : program->blocks) {
1462*61046927SAndroid Build Coastguard Worker Location loc;
1463*61046927SAndroid Build Coastguard Worker loc.block = █
1464*61046927SAndroid Build Coastguard Worker
1465*61046927SAndroid Build Coastguard Worker std::array<unsigned, 2048> regs; /* register file in bytes */
1466*61046927SAndroid Build Coastguard Worker regs.fill(0);
1467*61046927SAndroid Build Coastguard Worker
1468*61046927SAndroid Build Coastguard Worker /* check live in */
1469*61046927SAndroid Build Coastguard Worker for (unsigned id : program->live.live_in[block.index]) {
1470*61046927SAndroid Build Coastguard Worker Temp tmp(id, program->temp_rc[id]);
1471*61046927SAndroid Build Coastguard Worker PhysReg reg = assignments[id].reg;
1472*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < tmp.bytes(); i++) {
1473*61046927SAndroid Build Coastguard Worker if (regs[reg.reg_b + i]) {
1474*61046927SAndroid Build Coastguard Worker err |= ra_fail(program, loc, Location(),
1475*61046927SAndroid Build Coastguard Worker "Assignment of element %d of %%%d already taken by %%%d in live-in",
1476*61046927SAndroid Build Coastguard Worker i, id, regs[reg.reg_b + i]);
1477*61046927SAndroid Build Coastguard Worker }
1478*61046927SAndroid Build Coastguard Worker regs[reg.reg_b + i] = id;
1479*61046927SAndroid Build Coastguard Worker }
1480*61046927SAndroid Build Coastguard Worker }
1481*61046927SAndroid Build Coastguard Worker
1482*61046927SAndroid Build Coastguard Worker for (aco_ptr<Instruction>& instr : block.instructions) {
1483*61046927SAndroid Build Coastguard Worker loc.instr = instr.get();
1484*61046927SAndroid Build Coastguard Worker
1485*61046927SAndroid Build Coastguard Worker /* remove killed p_phi operands from regs */
1486*61046927SAndroid Build Coastguard Worker if (instr->opcode == aco_opcode::p_logical_end) {
1487*61046927SAndroid Build Coastguard Worker for (Temp tmp : phi_sgpr_ops[block.index]) {
1488*61046927SAndroid Build Coastguard Worker PhysReg reg = assignments[tmp.id()].reg;
1489*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < tmp.bytes(); i++)
1490*61046927SAndroid Build Coastguard Worker regs[reg.reg_b + i] = 0;
1491*61046927SAndroid Build Coastguard Worker }
1492*61046927SAndroid Build Coastguard Worker }
1493*61046927SAndroid Build Coastguard Worker
1494*61046927SAndroid Build Coastguard Worker if (instr->opcode != aco_opcode::p_phi && instr->opcode != aco_opcode::p_linear_phi) {
1495*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
1496*61046927SAndroid Build Coastguard Worker if (!op.isTemp())
1497*61046927SAndroid Build Coastguard Worker continue;
1498*61046927SAndroid Build Coastguard Worker if (op.isFirstKillBeforeDef()) {
1499*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < op.getTemp().bytes(); j++)
1500*61046927SAndroid Build Coastguard Worker regs[op.physReg().reg_b + j] = 0;
1501*61046927SAndroid Build Coastguard Worker }
1502*61046927SAndroid Build Coastguard Worker }
1503*61046927SAndroid Build Coastguard Worker }
1504*61046927SAndroid Build Coastguard Worker
1505*61046927SAndroid Build Coastguard Worker if (!instr->isBranch() || block.linear_succs.size() != 1)
1506*61046927SAndroid Build Coastguard Worker err |= validate_instr_defs(program, regs, assignments, loc, instr);
1507*61046927SAndroid Build Coastguard Worker
1508*61046927SAndroid Build Coastguard Worker if (!is_phi(instr)) {
1509*61046927SAndroid Build Coastguard Worker for (const Operand& op : instr->operands) {
1510*61046927SAndroid Build Coastguard Worker if (!op.isTemp())
1511*61046927SAndroid Build Coastguard Worker continue;
1512*61046927SAndroid Build Coastguard Worker if (op.isLateKill() && op.isFirstKill()) {
1513*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < op.getTemp().bytes(); j++)
1514*61046927SAndroid Build Coastguard Worker regs[op.physReg().reg_b + j] = 0;
1515*61046927SAndroid Build Coastguard Worker }
1516*61046927SAndroid Build Coastguard Worker }
1517*61046927SAndroid Build Coastguard Worker } else if (block.linear_preds.size() != 1 ||
1518*61046927SAndroid Build Coastguard Worker program->blocks[block.linear_preds[0]].linear_succs.size() == 1) {
1519*61046927SAndroid Build Coastguard Worker for (unsigned pred : block.linear_preds) {
1520*61046927SAndroid Build Coastguard Worker aco_ptr<Instruction>& br = program->blocks[pred].instructions.back();
1521*61046927SAndroid Build Coastguard Worker assert(br->isBranch());
1522*61046927SAndroid Build Coastguard Worker err |= validate_instr_defs(program, regs, assignments, loc, br);
1523*61046927SAndroid Build Coastguard Worker }
1524*61046927SAndroid Build Coastguard Worker }
1525*61046927SAndroid Build Coastguard Worker }
1526*61046927SAndroid Build Coastguard Worker }
1527*61046927SAndroid Build Coastguard Worker
1528*61046927SAndroid Build Coastguard Worker return err;
1529*61046927SAndroid Build Coastguard Worker }
1530*61046927SAndroid Build Coastguard Worker } // namespace aco
1531