namespace aco {
-#ifndef NDEBUG
-void perfwarn(bool cond, const char *msg, Instruction *instr)
+static void aco_log(Program *program, enum radv_compiler_debug_level level,
+ const char *prefix, const char *file, unsigned line,
+ const char *fmt, va_list args)
{
- if (cond) {
- fprintf(stderr, "ACO performance warning: %s\n", msg);
- if (instr) {
- fprintf(stderr, "instruction: ");
- aco_print_instr(instr, stderr);
- fprintf(stderr, "\n");
- }
+ char *msg;
- if (debug_flags & DEBUG_PERFWARN)
- exit(1);
- }
+ msg = ralloc_strdup(NULL, prefix);
+
+ ralloc_asprintf_append(&msg, " In file %s:%u\n", file, line);
+ ralloc_asprintf_append(&msg, " ");
+ ralloc_vasprintf_append(&msg, fmt, args);
+
+ if (program->debug.func)
+ program->debug.func(program->debug.private_data, level, msg);
+
+ fprintf(stderr, "%s\n", msg);
+
+ ralloc_free(msg);
+}
+
+void _aco_perfwarn(Program *program, const char *file, unsigned line,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ aco_log(program, RADV_COMPILER_DEBUG_LEVEL_PERFWARN,
+ "ACO PERFWARN:\n", file, line, fmt, args);
+ va_end(args);
}
-#endif
-bool validate_ir(Program* program, FILE *output)
+void _aco_err(Program *program, const char *file, unsigned line,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ aco_log(program, RADV_COMPILER_DEBUG_LEVEL_ERROR,
+ "ACO ERROR:\n", file, line, fmt, args);
+ va_end(args);
+}
+
+bool validate_ir(Program* program)
{
bool is_valid = true;
- auto check = [&output, &is_valid](bool check, const char * msg, aco::Instruction * instr) -> void {
+ auto check = [&program, &is_valid](bool check, const char * msg, aco::Instruction * instr) -> void {
if (!check) {
- fprintf(output, "%s: ", msg);
- aco_print_instr(instr, output);
- fprintf(output, "\n");
+ char *out;
+ size_t outsize;
+ FILE *memf = open_memstream(&out, &outsize);
+
+ fprintf(memf, "%s: ", msg);
+ aco_print_instr(instr, memf);
+ fclose(memf);
+
+ aco_err(program, out);
+ free(out);
+
is_valid = false;
}
};
- auto check_block = [&output, &is_valid](bool check, const char * msg, aco::Block * block) -> void {
+
+ auto check_block = [&program, &is_valid](bool check, const char * msg, aco::Block * block) -> void {
if (!check) {
- fprintf(output, "%s: BB%u\n", msg, block->index);
+ aco_err(program, "%s: BB%u", msg, block->index);
is_valid = false;
}
};
PhysReg reg;
};
-bool ra_fail(FILE *output, Location loc, Location loc2, const char *fmt, ...) {
+bool ra_fail(Program *program, Location loc, Location loc2, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char msg[1024];
vsprintf(msg, fmt, args);
va_end(args);
- fprintf(stderr, "RA error found at instruction in BB%d:\n", loc.block->index);
+ char *out;
+ size_t outsize;
+ FILE *memf = open_memstream(&out, &outsize);
+
+ fprintf(memf, "RA error found at instruction in BB%d:\n", loc.block->index);
if (loc.instr) {
- aco_print_instr(loc.instr, stderr);
- fprintf(stderr, "\n%s", msg);
+ aco_print_instr(loc.instr, memf);
+ fprintf(memf, "\n%s", msg);
} else {
- fprintf(stderr, "%s", msg);
+ fprintf(memf, "%s", msg);
}
if (loc2.block) {
- fprintf(stderr, " in BB%d:\n", loc2.block->index);
- aco_print_instr(loc2.instr, stderr);
+ fprintf(memf, " in BB%d:\n", loc2.block->index);
+ aco_print_instr(loc2.instr, memf);
}
- fprintf(stderr, "\n\n");
+ fprintf(memf, "\n\n");
+ fclose(memf);
+
+ aco_err(program, out);
+ free(out);
return true;
}
} /* end namespace */
-bool validate_ra(Program *program, const struct radv_nir_compiler_options *options, FILE *output) {
+bool validate_ra(Program *program, const struct radv_nir_compiler_options *options) {
if (!(debug_flags & DEBUG_VALIDATE_RA))
return false;
if (!op.isTemp())
continue;
if (!op.isFixed())
- err |= ra_fail(output, loc, Location(), "Operand %d is not assigned a register", i);
+ err |= ra_fail(program, loc, Location(), "Operand %d is not assigned a register", i);
if (assignments.count(op.tempId()) && assignments[op.tempId()].reg != op.physReg())
- err |= ra_fail(output, loc, assignments.at(op.tempId()).firstloc, "Operand %d has an inconsistent register assignment with instruction", i);
+ err |= ra_fail(program, loc, assignments.at(op.tempId()).firstloc, "Operand %d has an inconsistent register assignment with instruction", i);
if ((op.getTemp().type() == RegType::vgpr && op.physReg().reg_b + op.bytes() > (256 + program->config->num_vgprs) * 4) ||
(op.getTemp().type() == RegType::sgpr && op.physReg() + op.size() > program->config->num_sgprs && op.physReg() < program->sgpr_limit))
- err |= ra_fail(output, loc, assignments.at(op.tempId()).firstloc, "Operand %d has an out-of-bounds register assignment", i);
+ err |= ra_fail(program, 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);
+ err |= ra_fail(program, loc, Location(), "Operand %d fixed to vcc but needs_vcc=false", i);
if (op.regClass().is_subdword() && !validate_subdword_operand(program->chip_class, instr, i))
- err |= ra_fail(output, loc, Location(), "Operand %d not aligned correctly", i);
+ err |= ra_fail(program, loc, Location(), "Operand %d not aligned correctly", i);
if (!assignments[op.tempId()].firstloc.block)
assignments[op.tempId()].firstloc = loc;
if (!assignments[op.tempId()].defloc.block)
if (!def.isTemp())
continue;
if (!def.isFixed())
- err |= ra_fail(output, loc, Location(), "Definition %d is not assigned a register", i);
+ err |= ra_fail(program, loc, Location(), "Definition %d is not assigned a register", i);
if (assignments[def.tempId()].defloc.block)
- err |= ra_fail(output, loc, assignments.at(def.tempId()).defloc, "Temporary %%%d also defined by instruction", def.tempId());
+ err |= ra_fail(program, loc, assignments.at(def.tempId()).defloc, "Temporary %%%d also defined by instruction", def.tempId());
if ((def.getTemp().type() == RegType::vgpr && def.physReg().reg_b + def.bytes() > (256 + program->config->num_vgprs) * 4) ||
(def.getTemp().type() == RegType::sgpr && def.physReg() + def.size() > program->config->num_sgprs && def.physReg() < program->sgpr_limit))
- err |= ra_fail(output, loc, assignments.at(def.tempId()).firstloc, "Definition %d has an out-of-bounds register assignment", i);
+ err |= ra_fail(program, loc, assignments.at(def.tempId()).firstloc, "Definition %d has an out-of-bounds register assignment", i);
if (def.physReg() == vcc && !program->needs_vcc)
- err |= ra_fail(output, loc, Location(), "Definition %d fixed to vcc but needs_vcc=false", i);
+ err |= ra_fail(program, loc, Location(), "Definition %d fixed to vcc but needs_vcc=false", i);
if (def.regClass().is_subdword() && !validate_subdword_definition(program->chip_class, instr))
- err |= ra_fail(output, loc, Location(), "Definition %d not aligned correctly", i);
+ err |= ra_fail(program, loc, Location(), "Definition %d not aligned correctly", i);
if (!assignments[def.tempId()].firstloc.block)
assignments[def.tempId()].firstloc = loc;
assignments[def.tempId()].defloc = loc;
PhysReg reg = assignments.at(tmp.id()).reg;
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]);
+ err |= ra_fail(program, 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.reg_b + i] = tmp.id();
}
PhysReg reg = assignments.at(tmp.id()).reg;
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]);
+ err |= ra_fail(program, 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);
}
PhysReg reg = assignments.at(tmp.id()).reg;
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 + j]).defloc, "Assignment of element %d of %%%d already taken by %%%d from instruction", i, tmp.id(), regs[reg.reg_b + j]);
+ err |= ra_fail(program, loc, assignments.at(regs[reg.reg_b + j]).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.regClass().is_subdword() && def.bytes() < 4) {
for (unsigned j = reg.byte() & ~(written - 1); j < written; j++) {
unsigned written_reg = reg.reg() * 4u + j;
if (regs[written_reg] && regs[written_reg] != def.tempId())
- err |= ra_fail(output, loc, assignments.at(regs[written_reg]).defloc, "Assignment of element %d of %%%d overwrites the full register taken by %%%d from instruction", i, tmp.id(), regs[written_reg]);
+ err |= ra_fail(program, loc, assignments.at(regs[written_reg]).defloc, "Assignment of element %d of %%%d overwrites the full register taken by %%%d from instruction", i, tmp.id(), regs[written_reg]);
}
}
}