aco: fix file leak in ra_fail()
[mesa.git] / src / amd / compiler / aco_validate.cpp
index e9cfe0b43551c81d2bd5fdffc389dfcf9c157a43..0d74458519c488dc15fb0b4f2c0cc5b53cb4a887 100644 (file)
 
 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;
       }
    };
@@ -455,25 +489,33 @@ struct Assignment {
    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;
 }
@@ -610,7 +652,7 @@ unsigned get_subdword_bytes_written(Program *program, const aco_ptr<Instruction>
 
 } /* 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;
 
@@ -638,16 +680,16 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
             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)
@@ -659,16 +701,16 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
             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;
@@ -695,7 +737,7 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
          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();
          }
@@ -711,7 +753,7 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
                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);
             }
@@ -771,7 +813,7 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
             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) {
@@ -780,7 +822,7 @@ bool validate_ra(Program *program, const struct radv_nir_compiler_options *optio
                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]);
                }
             }
          }