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();
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))
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<PhysReg, bool> 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 */
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.
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;