diff --git a/src/amd/compiler/aco_register_allocation.cpp b/src/amd/compiler/aco_register_allocation.cpp index 82af2951ade..3b723d9e485 100644 --- a/src/amd/compiler/aco_register_allocation.cpp +++ b/src/amd/compiler/aco_register_allocation.cpp @@ -1680,6 +1680,7 @@ get_reg_create_vector(ra_ctx& ctx, RegisterFile& reg_file, Temp temp, PhysReg best_pos{0xFFF}; unsigned num_moves = 0xFF; bool best_avoid = true; + uint32_t correct_pos_mask = 0; /* test for each operand which definition placement causes the least shuffle instructions */ for (unsigned i = 0, offset = 0; i < instr->operands.size(); @@ -1744,13 +1745,14 @@ get_reg_create_vector(ra_ctx& ctx, RegisterFile& reg_file, Temp temp, continue; /* count operands in wrong positions */ + uint32_t correct_pos_mask_new = 0; for (unsigned j = 0, offset2 = 0; j < instr->operands.size(); offset2 += instr->operands[j].bytes(), j++) { - if (j == i || !instr->operands[j].isTemp() || - instr->operands[j].getTemp().type() != rc.type()) - continue; - if (instr->operands[j].physReg().reg_b != reg_win.lo() * 4 + offset2) - k += instr->operands[j].bytes(); + Operand& op = instr->operands[j]; + if (op.isTemp() && op.physReg().reg_b == reg_win.lo() * 4 + offset2) + correct_pos_mask_new |= 1 << j; + else + k += op.bytes(); } bool aligned = rc == RegClass::v4 && reg_win.lo() % 4 == 0; if (k > num_moves || (!aligned && k == num_moves)) @@ -1759,18 +1761,28 @@ get_reg_create_vector(ra_ctx& ctx, RegisterFile& reg_file, Temp temp, best_pos = reg_win.lo(); num_moves = k; best_avoid = avoid; + correct_pos_mask = correct_pos_mask_new; } - if (num_moves >= bytes) + /* too many moves: try the generic get_reg() function */ + if (num_moves >= 2 * bytes) { return get_reg(ctx, reg_file, temp, parallelcopies, instr); + } else if (num_moves > bytes) { + DefInfo info(ctx, instr, rc, -1); + std::pair res = get_reg_simple(ctx, reg_file, info); + if (res.second) + return res.first; + } /* re-enable killed operands which are in the wrong position */ RegisterFile tmp_file(reg_file); - for (unsigned i = 0, offset = 0; i < instr->operands.size(); - offset += instr->operands[i].bytes(), i++) { - if (instr->operands[i].isTemp() && instr->operands[i].isFirstKillBeforeDef() && - instr->operands[i].physReg().reg_b != best_pos.reg_b + offset) - tmp_file.fill(instr->operands[i]); + for (Operand& op : instr->operands) { + if (op.isTemp() && op.isFirstKillBeforeDef()) + tmp_file.fill(op); + } + for (unsigned i = 0; i < instr->operands.size(); i++) { + if ((correct_pos_mask >> i) & 1u && instr->operands[i].isKill()) + tmp_file.clear(instr->operands[i]); } /* collect variables to be moved */ @@ -1782,7 +1794,7 @@ get_reg_create_vector(ra_ctx& ctx, RegisterFile& reg_file, Temp temp, if (!instr->operands[i].isTemp() || !instr->operands[i].isFirstKillBeforeDef() || instr->operands[i].getTemp().type() != rc.type()) continue; - bool correct_pos = instr->operands[i].physReg().reg_b == best_pos.reg_b + offset; + bool correct_pos = !tmp_file.test(instr->operands[i].physReg(), instr->operands[i].bytes()); /* GFX9+: move killed operands which aren't yet at the correct position * Moving all killed operands generally leads to more register swaps. * This is only done on GFX9+ because of the cheap v_swap instruction. @@ -1790,9 +1802,6 @@ get_reg_create_vector(ra_ctx& ctx, RegisterFile& reg_file, Temp temp, if (ctx.program->chip_class >= GFX9 && !correct_pos) { vars.emplace(instr->operands[i].bytes(), instr->operands[i].tempId()); tmp_file.clear(instr->operands[i]); - /* fill operands which are in the correct position to avoid overwriting */ - } else if (correct_pos) { - tmp_file.fill(instr->operands[i]); } } bool success = false;