bool flat = instr->format == Format::FLAT || instr->format == Format::SCRATCH || instr->format == Format::GLOBAL;
bool can_be_undef = is_phi(instr) || instr->format == Format::EXP ||
instr->format == Format::PSEUDO_REDUCTION ||
+ instr->opcode == aco_opcode::p_create_vector ||
(flat && i == 1) || (instr->format == Format::MIMG && i == 1) ||
((instr->format == Format::MUBUF || instr->format == Format::MTBUF) && i == 1);
check(can_be_undef, "Undefs can only be used in certain operands", instr.get());
+ } else {
+ check(instr->operands[i].isFixed() || instr->operands[i].isTemp() || instr->operands[i].isConstant(), "Uninitialized Operand", instr.get());
}
}
+ /* check subdword definitions */
+ for (unsigned i = 0; i < instr->definitions.size(); i++) {
+ if (instr->definitions[i].regClass().is_subdword())
+ check(instr->isSDWA() || instr->format == Format::PSEUDO, "Only SDWA and Pseudo instructions can write subdword registers", instr.get());
+ }
+
if (instr->isSALU() || instr->isVALU()) {
/* check literals */
Operand literal(s1);
if (instr->opcode == aco_opcode::p_create_vector) {
unsigned size = 0;
for (const Operand& op : instr->operands) {
- size += op.size();
+ size += op.bytes();
}
- check(size == instr->definitions[0].size(), "Definition size does not match operand sizes", instr.get());
+ check(size == instr->definitions[0].bytes(), "Definition size does not match operand sizes", instr.get());
if (instr->definitions[0].getTemp().type() == RegType::sgpr) {
for (const Operand& op : instr->operands) {
check(op.isConstant() || op.regClass().type() == RegType::sgpr,
}
} else if (instr->opcode == aco_opcode::p_extract_vector) {
check((instr->operands[0].isTemp()) && instr->operands[1].isConstant(), "Wrong Operand types", instr.get());
- check(instr->operands[1].constantValue() < instr->operands[0].size(), "Index out of range", instr.get());
+ check((instr->operands[1].constantValue() + 1) * instr->definitions[0].bytes() <= instr->operands[0].bytes(), "Index out of range", instr.get());
check(instr->definitions[0].getTemp().type() == RegType::vgpr || instr->operands[0].regClass().type() == RegType::sgpr,
"Cannot extract SGPR value from VGPR vector", instr.get());
} else if (instr->opcode == aco_opcode::p_parallelcopy) {
err |= ra_fail(output, loc, assignments.at(op.tempId()).firstloc, "Operand %d has an out-of-bounds register assignment", i);
if (op.physReg() == vcc && !program->needs_vcc)
err |= ra_fail(output, loc, Location(), "Operand %d fixed to vcc but needs_vcc=false", i);
+ if (!(instr->isSDWA() || instr->format == Format::PSEUDO) && op.regClass().is_subdword() && op.physReg().byte())
+ err |= ra_fail(output, loc, assignments.at(op.tempId()).firstloc, "Operand %d must be aligned to a full register", i);
if (!assignments[op.tempId()].firstloc.block)
assignments[op.tempId()].firstloc = loc;
if (!assignments[op.tempId()].defloc.block)
Location loc;
loc.block = █
- std::array<unsigned, 512> regs;
+ std::array<unsigned, 2048> regs; /* register file in bytes */
regs.fill(0);
std::set<Temp> live;
/* check live out */
for (Temp tmp : live) {
PhysReg reg = assignments.at(tmp.id()).reg;
- for (unsigned i = 0; i < tmp.size(); i++) {
- if (regs[reg + i]) {
- err |= ra_fail(output, loc, Location(), "Assignment of element %d of %%%d already taken by %%%d in live-out", i, tmp.id(), regs[reg + i]);
+ for (unsigned i = 0; i < tmp.bytes(); i++) {
+ if (regs[reg.reg_b + i]) {
+ err |= ra_fail(output, loc, Location(), "Assignment of element %d of %%%d already taken by %%%d in live-out", i, tmp.id(), regs[reg.reg_b + i]);
}
- regs[reg + i] = tmp.id();
+ regs[reg.reg_b + i] = tmp.id();
}
}
regs.fill(0);
if (instr->opcode == aco_opcode::p_logical_end) {
for (Temp tmp : phi_sgpr_ops[block.index]) {
PhysReg reg = assignments.at(tmp.id()).reg;
- for (unsigned i = 0; i < tmp.size(); i++) {
- if (regs[reg + i])
- err |= ra_fail(output, loc, Location(), "Assignment of element %d of %%%d already taken by %%%d in live-out", i, tmp.id(), regs[reg + i]);
+ for (unsigned i = 0; i < tmp.bytes(); i++) {
+ if (regs[reg.reg_b + i])
+ err |= ra_fail(output, loc, Location(), "Assignment of element %d of %%%d already taken by %%%d in live-out", i, tmp.id(), regs[reg.reg_b + i]);
}
live.emplace(tmp);
}
for (Temp tmp : live) {
PhysReg reg = assignments.at(tmp.id()).reg;
- for (unsigned i = 0; i < tmp.size(); i++)
- regs[reg + i] = tmp.id();
+ for (unsigned i = 0; i < tmp.bytes(); i++)
+ regs[reg.reg_b + i] = tmp.id();
}
for (aco_ptr<Instruction>& instr : block.instructions) {
if (instr->opcode == aco_opcode::p_logical_end) {
for (Temp tmp : phi_sgpr_ops[block.index]) {
PhysReg reg = assignments.at(tmp.id()).reg;
- regs[reg] = 0;
+ for (unsigned i = 0; i < tmp.bytes(); i++)
+ regs[reg.reg_b + i] = 0;
}
}
if (!op.isTemp())
continue;
if (op.isFirstKillBeforeDef()) {
- for (unsigned j = 0; j < op.getTemp().size(); j++)
- regs[op.physReg() + j] = 0;
+ for (unsigned j = 0; j < op.getTemp().bytes(); j++)
+ regs[op.physReg().reg_b + j] = 0;
}
}
}
continue;
Temp tmp = def.getTemp();
PhysReg reg = assignments.at(tmp.id()).reg;
- for (unsigned j = 0; j < tmp.size(); j++) {
- if (regs[reg + j])
- err |= ra_fail(output, loc, assignments.at(regs[reg + i]).defloc, "Assignment of element %d of %%%d already taken by %%%d from instruction", i, tmp.id(), regs[reg + j]);
- regs[reg + j] = tmp.id();
+ for (unsigned j = 0; j < tmp.bytes(); j++) {
+ if (regs[reg.reg_b + j])
+ err |= ra_fail(output, loc, assignments.at(regs[reg.reg_b + i]).defloc, "Assignment of element %d of %%%d already taken by %%%d from instruction", i, tmp.id(), regs[reg.reg_b + j]);
+ regs[reg.reg_b + j] = tmp.id();
}
}
if (!def.isTemp())
continue;
if (def.isKill()) {
- for (unsigned j = 0; j < def.getTemp().size(); j++)
- regs[def.physReg() + j] = 0;
+ for (unsigned j = 0; j < def.getTemp().bytes(); j++)
+ regs[def.physReg().reg_b + j] = 0;
}
}
if (!op.isTemp())
continue;
if (op.isLateKill() && op.isFirstKill()) {
- for (unsigned j = 0; j < op.getTemp().size(); j++)
- regs[op.physReg() + j] = 0;
+ for (unsigned j = 0; j < op.getTemp().bytes(); j++)
+ regs[op.physReg().reg_b + j] = 0;
}
}
}