aco: introduce Operand flag 'CopyKill'

This flag indicates that the Operand must be copied in order to satisfy register
constraints. The copy is immediately killed by the instruction.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30299>
This commit is contained in:
Daniel Schürmann 2024-07-04 11:03:43 +02:00 committed by Marge Bot
parent 91f65d5935
commit dfc13fcf9f
2 changed files with 33 additions and 4 deletions

View file

@ -460,7 +460,7 @@ public:
constexpr Operand()
: reg_(PhysReg{128}), isTemp_(false), isFixed_(true), isConstant_(false), isKill_(false),
isUndef_(true), isFirstKill_(false), constSize(0), isLateKill_(false), isClobbered_(false),
is16bit_(false), is24bit_(false), signext(false)
isCopyKill_(false), is16bit_(false), is24bit_(false), signext(false)
{}
explicit Operand(Temp r) noexcept
@ -809,11 +809,24 @@ public:
constexpr void setClobbered(bool flag) noexcept { isClobbered_ = flag; }
constexpr bool isClobbered() const noexcept { return isClobbered_; }
/* Indicates that the Operand must be copied in order to satisfy register
* constraints. The copy is immediately killed by the instruction.
*/
constexpr void setCopyKill(bool flag) noexcept
{
isCopyKill_ = flag;
if (flag)
setKill(flag);
}
constexpr bool isCopyKill() const noexcept { return isCopyKill_; }
constexpr void setKill(bool flag) noexcept
{
isKill_ = flag;
if (!flag)
if (!flag) {
setFirstKill(false);
setCopyKill(false);
}
}
constexpr bool isKill() const noexcept { return isKill_ || isFirstKill(); }
@ -879,6 +892,7 @@ private:
uint8_t constSize : 2;
uint8_t isLateKill_ : 1;
uint8_t isClobbered_ : 1;
uint8_t isCopyKill_ : 1;
uint8_t is16bit_ : 1;
uint8_t is24bit_ : 1;
uint8_t signext : 1;

View file

@ -42,7 +42,7 @@ get_temp_registers(Instruction* instr)
}
for (Operand op : instr->operands) {
if (op.isFirstKill()) {
if (op.isFirstKill() || op.isCopyKill()) {
demand_before += op.getTemp();
if (op.isLateKill())
demand_after += op.getTemp();
@ -252,8 +252,12 @@ process_live_temps_per_block(live_ctx& ctx, Block* block)
Operand& operand = insn->operands[i];
if (!operand.isTemp())
continue;
const Temp temp = operand.getTemp();
if (operand.isFixed() && ctx.program->progress < CompilationProgress::after_ra) {
assert(!operand.isLateKill());
ctx.program->needs_vcc |= operand.physReg() == vcc;
/* Check if this operand gets overwritten by a precolored definition. */
if (std::any_of(insn->definitions.begin(), insn->definitions.end(),
[=](Definition def)
@ -263,8 +267,19 @@ process_live_temps_per_block(live_ctx& ctx, Block* block)
operand.physReg() + operand.size() > def.physReg();
}))
operand.setClobbered(true);
/* Check if this temp is fixed to a different register as well.
* This assumes that operands of one instruction are not precolored twice to
* the same register. In this case, register pressure might be overestimated.
*/
for (unsigned j = i + 1; !operand.isCopyKill() && j < insn->operands.size(); ++j) {
if (insn->operands[j].isTemp() && insn->operands[j].getTemp() == temp &&
insn->operands[j].isFixed()) {
operand_demand += temp;
insn->operands[j].setCopyKill(true);
}
}
}
const Temp temp = operand.getTemp();
if (operand.isKill())
continue;