aco: remove ordered/unordered optimizations
Reviewed-by: Timur Kristóf <timur.kristof@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29467>
This commit is contained in:
@@ -2130,163 +2130,6 @@ follow_operand(opt_ctx& ctx, Operand op, bool ignore_uses = false)
|
||||
return instr;
|
||||
}
|
||||
|
||||
/* s_or_b64(neq(a, a), neq(b, b)) -> v_cmp_u_f32(a, b)
|
||||
* s_and_b64(eq(a, a), eq(b, b)) -> v_cmp_o_f32(a, b) */
|
||||
bool
|
||||
combine_ordering_test(opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
{
|
||||
if (instr->definitions[0].regClass() != ctx.program->lane_mask)
|
||||
return false;
|
||||
if (instr->definitions[1].isTemp() && ctx.uses[instr->definitions[1].tempId()])
|
||||
return false;
|
||||
|
||||
bool is_or = instr->opcode == aco_opcode::s_or_b64 || instr->opcode == aco_opcode::s_or_b32;
|
||||
|
||||
bitarray8 opsel = 0;
|
||||
Instruction* op_instr[2];
|
||||
Temp op[2];
|
||||
|
||||
unsigned bitsize = 0;
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
op_instr[i] = follow_operand(ctx, instr->operands[i], true);
|
||||
if (!op_instr[i])
|
||||
return false;
|
||||
|
||||
aco_opcode expected_cmp = is_or ? aco_opcode::v_cmp_neq_f32 : aco_opcode::v_cmp_eq_f32;
|
||||
unsigned op_bitsize = get_cmp_bitsize(op_instr[i]->opcode);
|
||||
|
||||
if (get_f32_cmp(op_instr[i]->opcode) != expected_cmp)
|
||||
return false;
|
||||
if (bitsize && op_bitsize != bitsize)
|
||||
return false;
|
||||
if (!op_instr[i]->operands[0].isTemp() || !op_instr[i]->operands[1].isTemp())
|
||||
return false;
|
||||
|
||||
if (op_instr[i]->isSDWA() || op_instr[i]->isDPP())
|
||||
return false;
|
||||
|
||||
VALU_instruction& valu = op_instr[i]->valu();
|
||||
if (valu.neg[0] != valu.neg[1] || valu.abs[0] != valu.abs[1] ||
|
||||
valu.opsel[0] != valu.opsel[1])
|
||||
return false;
|
||||
opsel[i] = valu.opsel[0];
|
||||
|
||||
Temp op0 = op_instr[i]->operands[0].getTemp();
|
||||
Temp op1 = op_instr[i]->operands[1].getTemp();
|
||||
if (original_temp_id(ctx, op0) != original_temp_id(ctx, op1))
|
||||
return false;
|
||||
|
||||
op[i] = op1;
|
||||
bitsize = op_bitsize;
|
||||
}
|
||||
|
||||
if (op[1].type() == RegType::sgpr) {
|
||||
std::swap(op[0], op[1]);
|
||||
opsel[0].swap(opsel[1]);
|
||||
}
|
||||
unsigned num_sgprs = (op[0].type() == RegType::sgpr) + (op[1].type() == RegType::sgpr);
|
||||
if (num_sgprs > (ctx.program->gfx_level >= GFX10 ? 2 : 1))
|
||||
return false;
|
||||
|
||||
aco_opcode new_op = aco_opcode::num_opcodes;
|
||||
switch (bitsize) {
|
||||
case 16: new_op = is_or ? aco_opcode::v_cmp_u_f16 : aco_opcode::v_cmp_o_f16; break;
|
||||
case 32: new_op = is_or ? aco_opcode::v_cmp_u_f32 : aco_opcode::v_cmp_o_f32; break;
|
||||
case 64: new_op = is_or ? aco_opcode::v_cmp_u_f64 : aco_opcode::v_cmp_o_f64; break;
|
||||
}
|
||||
bool needs_vop3 = num_sgprs > 1 || (opsel[0] && op[0].type() != RegType::vgpr);
|
||||
Instruction* new_instr =
|
||||
create_instruction(new_op, needs_vop3 ? asVOP3(Format::VOPC) : Format::VOPC, 2, 1);
|
||||
|
||||
new_instr->valu().opsel = opsel;
|
||||
new_instr->operands[0] = copy_operand(ctx, Operand(op[0]));
|
||||
new_instr->operands[1] = copy_operand(ctx, Operand(op[1]));
|
||||
new_instr->definitions[0] = instr->definitions[0];
|
||||
new_instr->pass_flags = instr->pass_flags;
|
||||
|
||||
decrease_uses(ctx, op_instr[0]);
|
||||
decrease_uses(ctx, op_instr[1]);
|
||||
|
||||
ctx.info[instr->definitions[0].tempId()].label = 0;
|
||||
ctx.info[instr->definitions[0].tempId()].set_vopc(new_instr);
|
||||
|
||||
instr.reset(new_instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* s_or_b64(v_cmp_u_f32(a, b), cmp(a, b)) -> get_unordered(cmp)(a, b)
|
||||
* s_and_b64(v_cmp_o_f32(a, b), cmp(a, b)) -> get_ordered(cmp)(a, b) */
|
||||
bool
|
||||
combine_comparison_ordering(opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
{
|
||||
if (instr->definitions[0].regClass() != ctx.program->lane_mask)
|
||||
return false;
|
||||
if (instr->definitions[1].isTemp() && ctx.uses[instr->definitions[1].tempId()])
|
||||
return false;
|
||||
|
||||
bool is_or = instr->opcode == aco_opcode::s_or_b64 || instr->opcode == aco_opcode::s_or_b32;
|
||||
aco_opcode expected_nan_test = is_or ? aco_opcode::v_cmp_u_f32 : aco_opcode::v_cmp_o_f32;
|
||||
|
||||
Instruction* nan_test = follow_operand(ctx, instr->operands[0], true);
|
||||
Instruction* cmp = follow_operand(ctx, instr->operands[1], true);
|
||||
if (!nan_test || !cmp)
|
||||
return false;
|
||||
if (nan_test->isSDWA() || cmp->isSDWA())
|
||||
return false;
|
||||
|
||||
if (get_f32_cmp(cmp->opcode) == expected_nan_test)
|
||||
std::swap(nan_test, cmp);
|
||||
else if (get_f32_cmp(nan_test->opcode) != expected_nan_test)
|
||||
return false;
|
||||
|
||||
if (!is_fp_cmp(cmp->opcode) || get_cmp_bitsize(cmp->opcode) != get_cmp_bitsize(nan_test->opcode))
|
||||
return false;
|
||||
|
||||
if (!nan_test->operands[0].isTemp() || !nan_test->operands[1].isTemp())
|
||||
return false;
|
||||
if (!cmp->operands[0].isTemp() || !cmp->operands[1].isTemp())
|
||||
return false;
|
||||
|
||||
unsigned prop_cmp0 = original_temp_id(ctx, cmp->operands[0].getTemp());
|
||||
unsigned prop_cmp1 = original_temp_id(ctx, cmp->operands[1].getTemp());
|
||||
unsigned prop_nan0 = original_temp_id(ctx, nan_test->operands[0].getTemp());
|
||||
unsigned prop_nan1 = original_temp_id(ctx, nan_test->operands[1].getTemp());
|
||||
VALU_instruction& cmp_valu = cmp->valu();
|
||||
VALU_instruction& nan_valu = nan_test->valu();
|
||||
if ((prop_cmp0 != prop_nan0 || cmp_valu.opsel[0] != nan_valu.opsel[0]) &&
|
||||
(prop_cmp0 != prop_nan1 || cmp_valu.opsel[0] != nan_valu.opsel[1]))
|
||||
return false;
|
||||
if ((prop_cmp1 != prop_nan0 || cmp_valu.opsel[1] != nan_valu.opsel[0]) &&
|
||||
(prop_cmp1 != prop_nan1 || cmp_valu.opsel[1] != nan_valu.opsel[1]))
|
||||
return false;
|
||||
if (prop_cmp0 == prop_cmp1 && cmp_valu.opsel[0] == cmp_valu.opsel[1])
|
||||
return false;
|
||||
|
||||
aco_opcode new_op = is_or ? get_unordered(cmp->opcode) : get_ordered(cmp->opcode);
|
||||
Instruction* new_instr =
|
||||
create_instruction(new_op, cmp->isVOP3() ? asVOP3(Format::VOPC) : Format::VOPC, 2, 1);
|
||||
new_instr->valu().neg = cmp_valu.neg;
|
||||
new_instr->valu().abs = cmp_valu.abs;
|
||||
new_instr->valu().clamp = cmp_valu.clamp;
|
||||
new_instr->valu().omod = cmp_valu.omod;
|
||||
new_instr->valu().opsel = cmp_valu.opsel;
|
||||
new_instr->operands[0] = copy_operand(ctx, cmp->operands[0]);
|
||||
new_instr->operands[1] = copy_operand(ctx, cmp->operands[1]);
|
||||
new_instr->definitions[0] = instr->definitions[0];
|
||||
new_instr->pass_flags = instr->pass_flags;
|
||||
|
||||
decrease_uses(ctx, nan_test);
|
||||
decrease_uses(ctx, cmp);
|
||||
|
||||
ctx.info[instr->definitions[0].tempId()].label = 0;
|
||||
ctx.info[instr->definitions[0].tempId()].set_vopc(new_instr);
|
||||
|
||||
instr.reset(new_instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Optimize v_cmp of constant with subgroup invocation to a constant mask.
|
||||
* Ideally, we can trade v_cmp for a constant (or literal).
|
||||
* In a less ideal case, we trade v_cmp for a SALU instruction, which is still a win.
|
||||
@@ -2384,101 +2227,6 @@ is_operand_constant(opt_ctx& ctx, Operand op, unsigned bit_size, uint64_t* value
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
is_constant_nan(uint64_t value, unsigned bit_size)
|
||||
{
|
||||
if (bit_size == 16)
|
||||
return ((value >> 10) & 0x1f) == 0x1f && (value & 0x3ff);
|
||||
else if (bit_size == 32)
|
||||
return ((value >> 23) & 0xff) == 0xff && (value & 0x7fffff);
|
||||
else
|
||||
return ((value >> 52) & 0x7ff) == 0x7ff && (value & 0xfffffffffffff);
|
||||
}
|
||||
|
||||
/* s_or_b64(v_cmp_neq_f32(a, a), cmp(a, #b)) and b is not NaN -> get_unordered(cmp)(a, b)
|
||||
* s_and_b64(v_cmp_eq_f32(a, a), cmp(a, #b)) and b is not NaN -> get_ordered(cmp)(a, b) */
|
||||
bool
|
||||
combine_constant_comparison_ordering(opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
{
|
||||
if (instr->definitions[0].regClass() != ctx.program->lane_mask)
|
||||
return false;
|
||||
if (instr->definitions[1].isTemp() && ctx.uses[instr->definitions[1].tempId()])
|
||||
return false;
|
||||
|
||||
bool is_or = instr->opcode == aco_opcode::s_or_b64 || instr->opcode == aco_opcode::s_or_b32;
|
||||
|
||||
Instruction* nan_test = follow_operand(ctx, instr->operands[0], true);
|
||||
Instruction* cmp = follow_operand(ctx, instr->operands[1], true);
|
||||
|
||||
if (!nan_test || !cmp || nan_test->isSDWA() || cmp->isSDWA() || nan_test->isDPP() ||
|
||||
cmp->isDPP())
|
||||
return false;
|
||||
|
||||
aco_opcode expected_nan_test = is_or ? aco_opcode::v_cmp_neq_f32 : aco_opcode::v_cmp_eq_f32;
|
||||
if (get_f32_cmp(cmp->opcode) == expected_nan_test)
|
||||
std::swap(nan_test, cmp);
|
||||
else if (get_f32_cmp(nan_test->opcode) != expected_nan_test)
|
||||
return false;
|
||||
|
||||
unsigned bit_size = get_cmp_bitsize(cmp->opcode);
|
||||
if (!is_fp_cmp(cmp->opcode) || get_cmp_bitsize(nan_test->opcode) != bit_size)
|
||||
return false;
|
||||
|
||||
if (!nan_test->operands[0].isTemp() || !nan_test->operands[1].isTemp())
|
||||
return false;
|
||||
if (!cmp->operands[0].isTemp() && !cmp->operands[1].isTemp())
|
||||
return false;
|
||||
|
||||
unsigned prop_nan0 = original_temp_id(ctx, nan_test->operands[0].getTemp());
|
||||
unsigned prop_nan1 = original_temp_id(ctx, nan_test->operands[1].getTemp());
|
||||
if (prop_nan0 != prop_nan1)
|
||||
return false;
|
||||
|
||||
VALU_instruction& vop3 = nan_test->valu();
|
||||
if (vop3.neg[0] != vop3.neg[1] || vop3.abs[0] != vop3.abs[1] || vop3.opsel[0] != vop3.opsel[1])
|
||||
return false;
|
||||
|
||||
int constant_operand = -1;
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
if (cmp->operands[i].isTemp() &&
|
||||
original_temp_id(ctx, cmp->operands[i].getTemp()) == prop_nan0 &&
|
||||
cmp->valu().opsel[i] == nan_test->valu().opsel[0]) {
|
||||
constant_operand = !i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (constant_operand == -1)
|
||||
return false;
|
||||
|
||||
uint64_t constant_value;
|
||||
if (!is_operand_constant(ctx, cmp->operands[constant_operand], bit_size, &constant_value))
|
||||
return false;
|
||||
if (is_constant_nan(constant_value >> (cmp->valu().opsel[constant_operand] * 16), bit_size))
|
||||
return false;
|
||||
|
||||
aco_opcode new_op = is_or ? get_unordered(cmp->opcode) : get_ordered(cmp->opcode);
|
||||
Instruction* new_instr = create_instruction(new_op, cmp->format, 2, 1);
|
||||
new_instr->valu().neg = cmp->valu().neg;
|
||||
new_instr->valu().abs = cmp->valu().abs;
|
||||
new_instr->valu().clamp = cmp->valu().clamp;
|
||||
new_instr->valu().omod = cmp->valu().omod;
|
||||
new_instr->valu().opsel = cmp->valu().opsel;
|
||||
new_instr->operands[0] = copy_operand(ctx, cmp->operands[0]);
|
||||
new_instr->operands[1] = copy_operand(ctx, cmp->operands[1]);
|
||||
new_instr->definitions[0] = instr->definitions[0];
|
||||
new_instr->pass_flags = instr->pass_flags;
|
||||
|
||||
decrease_uses(ctx, nan_test);
|
||||
decrease_uses(ctx, cmp);
|
||||
|
||||
ctx.info[instr->definitions[0].tempId()].label = 0;
|
||||
ctx.info[instr->definitions[0].tempId()].set_vopc(new_instr);
|
||||
|
||||
instr.reset(new_instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* s_not(cmp(a, b)) -> get_inverse(cmp)(a, b) */
|
||||
bool
|
||||
combine_inverse_comparison(opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
@@ -4455,11 +4203,7 @@ combine_instruction(opt_ctx& ctx, aco_ptr<Instruction>& instr)
|
||||
combine_inverse_comparison(ctx, instr);
|
||||
} else if (instr->opcode == aco_opcode::s_and_b32 || instr->opcode == aco_opcode::s_or_b32 ||
|
||||
instr->opcode == aco_opcode::s_and_b64 || instr->opcode == aco_opcode::s_or_b64) {
|
||||
if (combine_ordering_test(ctx, instr)) {
|
||||
} else if (combine_comparison_ordering(ctx, instr)) {
|
||||
} else if (combine_constant_comparison_ordering(ctx, instr)) {
|
||||
} else if (combine_salu_n2(ctx, instr)) {
|
||||
}
|
||||
combine_salu_n2(ctx, instr);
|
||||
} else if (instr->opcode == aco_opcode::s_abs_i32) {
|
||||
combine_sabsdiff(ctx, instr);
|
||||
} else if (instr->opcode == aco_opcode::v_and_b32) {
|
||||
|
||||
@@ -540,139 +540,6 @@ BEGIN_TEST(optimize.clamp)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(optimize.const_comparison_ordering)
|
||||
//>> v1: %a, v1: %b, v2: %c, v1: %d = p_startpgm
|
||||
if (!setup_cs("v1 v1 v2 v1", GFX9))
|
||||
return;
|
||||
|
||||
/* optimize to unordered comparison */
|
||||
//! s2: %res0 = v_cmp_nge_f32 4.0, %a
|
||||
//! p_unit_test 0, %res0
|
||||
writeout(0, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm),
|
||||
Operand::c32(0x40800000u), inputs[0])));
|
||||
|
||||
//! s2: %res1 = v_cmp_nge_f32 4.0, %a
|
||||
//! p_unit_test 1, %res1
|
||||
writeout(1, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_nge_f32, bld.def(bld.lm),
|
||||
Operand::c32(0x40800000u), inputs[0])));
|
||||
|
||||
//! s2: %res2 = v_cmp_nge_f32 0x40a00000, %a
|
||||
//! p_unit_test 2, %res2
|
||||
writeout(2, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm),
|
||||
bld.copy(bld.def(v1), Operand::c32(0x40a00000u)), inputs[0])));
|
||||
|
||||
/* optimize to ordered comparison */
|
||||
//! s2: %res3 = v_cmp_lt_f32 4.0, %a
|
||||
//! p_unit_test 3, %res3
|
||||
writeout(3, bld.sop2(aco_opcode::s_and_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_eq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_nge_f32, bld.def(bld.lm),
|
||||
Operand::c32(0x40800000u), inputs[0])));
|
||||
|
||||
//! s2: %res4 = v_cmp_lt_f32 4.0, %a
|
||||
//! p_unit_test 4, %res4
|
||||
writeout(4, bld.sop2(aco_opcode::s_and_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_eq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm),
|
||||
Operand::c32(0x40800000u), inputs[0])));
|
||||
|
||||
//! s2: %res5 = v_cmp_lt_f32 0x40a00000, %a
|
||||
//! p_unit_test 5, %res5
|
||||
writeout(5, bld.sop2(aco_opcode::s_and_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_eq_f32, bld.def(bld.lm), inputs[0], inputs[0]),
|
||||
bld.vopc(aco_opcode::v_cmp_nge_f32, bld.def(bld.lm),
|
||||
bld.copy(bld.def(v1), Operand::c32(0x40a00000u)), inputs[0])));
|
||||
|
||||
/* similar but unoptimizable expressions */
|
||||
//! s2: %tmp6_0 = v_cmp_lt_f32 4.0, %a
|
||||
//! s2: %tmp6_1 = v_cmp_neq_f32 %a, %a
|
||||
//! s2: %res6, s1: %_:scc = s_and_b64 %tmp6_1, %tmp6_0
|
||||
//! p_unit_test 6, %res6
|
||||
Temp src1 =
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm), Operand::c32(0x40800000u), inputs[0]);
|
||||
Temp src0 = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]);
|
||||
writeout(6, bld.sop2(aco_opcode::s_and_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
//! s2: %tmp7_0 = v_cmp_nge_f32 4.0, %a
|
||||
//! s2: %tmp7_1 = v_cmp_eq_f32 %a, %a
|
||||
//! s2: %res7, s1: %_:scc = s_or_b64 %tmp7_1, %tmp7_0
|
||||
//! p_unit_test 7, %res7
|
||||
src1 =
|
||||
bld.vopc(aco_opcode::v_cmp_nge_f32, bld.def(bld.lm), Operand::c32(0x40800000u), inputs[0]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_eq_f32, bld.def(bld.lm), inputs[0], inputs[0]);
|
||||
writeout(7, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
//! s2: %tmp8_0 = v_cmp_lt_f32 4.0, %d
|
||||
//! s2: %tmp8_1 = v_cmp_neq_f32 %a, %a
|
||||
//! s2: %res8, s1: %_:scc = s_or_b64 %tmp8_1, %tmp8_0
|
||||
//! p_unit_test 8, %res8
|
||||
src1 = bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm), Operand::c32(0x40800000u), inputs[3]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]);
|
||||
writeout(8, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
//! s2: %tmp9_0 = v_cmp_lt_f32 4.0, %a
|
||||
//! s2: %tmp9_1 = v_cmp_neq_f32 %a, %d
|
||||
//! s2: %res9, s1: %_:scc = s_or_b64 %tmp9_1, %tmp9_0
|
||||
//! p_unit_test 9, %res9
|
||||
src1 = bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm), Operand::c32(0x40800000u), inputs[0]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[3]);
|
||||
writeout(9, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
/* bit sizes */
|
||||
//! s2: %res10 = v_cmp_nge_f16 4.0, %b
|
||||
//! p_unit_test 10, %res10
|
||||
Temp input1_16 =
|
||||
bld.pseudo(aco_opcode::p_extract_vector, bld.def(v2b), inputs[1], Operand::zero());
|
||||
writeout(10, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), input1_16, input1_16),
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), Operand::c16(0x4400u),
|
||||
input1_16)));
|
||||
|
||||
//! s2: %res11 = v_cmp_nge_f64 4.0, %c
|
||||
//! p_unit_test 11, %res11
|
||||
writeout(11, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc),
|
||||
bld.vopc(aco_opcode::v_cmp_neq_f64, bld.def(bld.lm), inputs[2], inputs[2]),
|
||||
bld.vopc(aco_opcode::v_cmp_lt_f64, bld.def(bld.lm),
|
||||
Operand::c64(0x4010000000000000u), inputs[2])));
|
||||
|
||||
/* NaN */
|
||||
uint16_t nan16 = 0x7e00;
|
||||
uint32_t nan32 = 0x7fc00000;
|
||||
uint64_t nan64 = 0xffffffffffffffffllu;
|
||||
|
||||
//! s2: %tmp12_0 = v_cmp_lt_f16 0x7e00, %a
|
||||
//! s2: %tmp12_1 = v_cmp_neq_f16 %a, %a
|
||||
//! s2: %res12, s1: %_:scc = s_or_b64 %tmp12_1, %tmp12_0
|
||||
//! p_unit_test 12, %res12
|
||||
src1 = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), Operand::c16(nan16), inputs[0]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), inputs[0], inputs[0]);
|
||||
writeout(12, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
//! s2: %tmp13_0 = v_cmp_lt_f32 0x7fc00000, %a
|
||||
//! s2: %tmp13_1 = v_cmp_neq_f32 %a, %a
|
||||
//! s2: %res13, s1: %_:scc = s_or_b64 %tmp13_1, %tmp13_0
|
||||
//! p_unit_test 13, %res13
|
||||
src1 = bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm), Operand::c32(nan32), inputs[0]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), inputs[0], inputs[0]);
|
||||
writeout(13, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
//! s2: %tmp14_0 = v_cmp_lt_f64 -1, %c
|
||||
//! s2: %tmp14_1 = v_cmp_neq_f64 %c, %c
|
||||
//! s2: %res14, s1: %_:scc = s_or_b64 %tmp14_1, %tmp14_0
|
||||
//! p_unit_test 14, %res14
|
||||
src1 = bld.vopc(aco_opcode::v_cmp_lt_f64, bld.def(bld.lm), Operand::c64(nan64), inputs[2]);
|
||||
src0 = bld.vopc(aco_opcode::v_cmp_neq_f64, bld.def(bld.lm), inputs[2], inputs[2]);
|
||||
writeout(14, bld.sop2(aco_opcode::s_or_b64, bld.def(bld.lm), bld.def(s1, scc), src0, src1));
|
||||
|
||||
finish_opt_test();
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(optimize.add3)
|
||||
//>> v1: %a, v1: %b, v1: %c = p_startpgm
|
||||
if (!setup_cs("v1 v1 v1", GFX9))
|
||||
@@ -2026,115 +1893,6 @@ BEGIN_TEST(optimize.apply_sgpr_swap_opsel)
|
||||
finish_opt_test();
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(optimize.combine_comparison_ordering)
|
||||
//>> v1: %a, v1: %b, v1: %c = p_startpgm
|
||||
if (!setup_cs("v1 v1 v1", GFX11))
|
||||
return;
|
||||
|
||||
Temp a = inputs[0];
|
||||
Temp b = inputs[1];
|
||||
Temp c = inputs[2];
|
||||
|
||||
Temp a_unordered = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), a, a);
|
||||
Temp b_unordered = bld.vopc(aco_opcode::v_cmp_neq_f32, bld.def(bld.lm), b, b);
|
||||
Temp unordered =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), a_unordered, b_unordered);
|
||||
|
||||
Temp a_lt_a = bld.vopc(aco_opcode::v_cmp_lt_f32, bld.def(bld.lm), a, a);
|
||||
Temp unordered_cmp =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), unordered, a_lt_a);
|
||||
|
||||
//! s2: %res0_unordered = v_cmp_u_f32 %a, %b
|
||||
//! s2: %res0_cmp = v_cmp_lt_f32 %a, %a
|
||||
//! s2: %res0, s2: %_:scc = s_or_b64 %res0_unordered, %res0_cmp
|
||||
//! p_unit_test 0, %res0
|
||||
writeout(0, unordered_cmp);
|
||||
|
||||
Temp c_hi = bld.pseudo(aco_opcode::p_extract_vector, bld.def(v2b), c, Operand::c32(1));
|
||||
|
||||
Temp c_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), c, c);
|
||||
Temp c_hi_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), c_hi, c_hi);
|
||||
unordered =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), c_unordered, c_hi_unordered);
|
||||
|
||||
Temp c_lt_c_hi = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), c, c_hi);
|
||||
unordered_cmp =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), unordered, c_lt_c_hi);
|
||||
|
||||
//! s2: %res1 = v_cmp_nge_f16 %c, hi(%c)
|
||||
//! p_unit_test 1, %res1
|
||||
writeout(1, unordered_cmp);
|
||||
|
||||
finish_opt_test();
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(optimize.combine_comparison_ordering_opsel)
|
||||
//>> v1: %a, v2b: %b = p_startpgm
|
||||
if (!setup_cs("v1 v2b", GFX11))
|
||||
return;
|
||||
|
||||
Temp a = inputs[0];
|
||||
Temp b = inputs[1];
|
||||
|
||||
Temp a_hi = bld.pseudo(aco_opcode::p_extract_vector, bld.def(v2b), a, Operand::c32(1));
|
||||
|
||||
Temp ahi_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), a_hi, a_hi);
|
||||
Temp b_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), b, b);
|
||||
Temp unordered =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), ahi_unordered, b_unordered);
|
||||
|
||||
Temp ahi_lt_b = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), a_hi, b);
|
||||
Temp unordered_cmp =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), unordered, ahi_lt_b);
|
||||
|
||||
//! s2: %res0 = v_cmp_nge_f16 hi(%a), %b
|
||||
//! p_unit_test 0, %res0
|
||||
writeout(0, unordered_cmp);
|
||||
|
||||
Temp ahi_cmp_const = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), a_hi,
|
||||
bld.copy(bld.def(v2b), Operand::c16(0x4400)));
|
||||
Temp ahi_ucmp_const =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), ahi_unordered, ahi_cmp_const);
|
||||
//! s2: %res1 = v_cmp_nle_f16 4.0, hi(%a)
|
||||
//! p_unit_test 1, %res1
|
||||
writeout(1, ahi_ucmp_const);
|
||||
|
||||
a_hi = bld.pseudo(aco_opcode::p_extract_vector, bld.def(v2b), a, Operand::c32(1));
|
||||
ahi_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), a_hi, a_hi);
|
||||
b_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), b, b);
|
||||
unordered =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), ahi_unordered, b_unordered);
|
||||
Temp alo_lt_b = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), a, b);
|
||||
Temp noopt = bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), unordered, alo_lt_b);
|
||||
//! s2: %u2 = v_cmp_u_f16 hi(%a), %b
|
||||
//! s2: %cmp2 = v_cmp_lt_f16 %a, %b
|
||||
//! s2: %res2, s2: %scc2:scc = s_or_b64 %u2, %cmp2
|
||||
//! p_unit_test 2, %res2
|
||||
writeout(2, noopt);
|
||||
|
||||
Temp hi_neq_lo = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), a, a_hi);
|
||||
Temp a_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), a, a);
|
||||
noopt = bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), hi_neq_lo, a_unordered);
|
||||
//! s2: %nan31 = v_cmp_neq_f16 %a, hi(%a)
|
||||
//! s2: %nan32 = v_cmp_neq_f16 %a, %a
|
||||
//! s2: %res3, s2: %scc3:scc = s_or_b64 %nan31, %nan32
|
||||
//! p_unit_test 3, %res3
|
||||
writeout(3, noopt);
|
||||
|
||||
ahi_cmp_const = bld.vopc(aco_opcode::v_cmp_lt_f16, bld.def(bld.lm), a_hi,
|
||||
bld.copy(bld.def(v2b), Operand::c16(0x4400)));
|
||||
a_unordered = bld.vopc(aco_opcode::v_cmp_neq_f16, bld.def(bld.lm), a, a);
|
||||
noopt =
|
||||
bld.sop2(Builder::s_or, bld.def(bld.lm), bld.def(bld.lm, scc), a_unordered, ahi_cmp_const);
|
||||
//! s2: %cmp4 = v_cmp_gt_f16 4.0, hi(%a)
|
||||
//! s2: %nan4 = v_cmp_neq_f16 %a, %a
|
||||
//! s2: %res4, s2: %scc4:scc = s_or_b64 %nan4, %cmp4
|
||||
//! p_unit_test 4, %res4
|
||||
writeout(4, noopt);
|
||||
|
||||
finish_opt_test();
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(optimize.max3_opsel)
|
||||
/* TODO make these work before GFX11 using SDWA. */
|
||||
for (unsigned i = GFX11; i <= GFX11; i++) {
|
||||
|
||||
Reference in New Issue
Block a user