[a64] Implement OPCODE_VECTOR_ADD

There is quite literally an instruction for each and every one of these cases.

Passes unit tests
This commit is contained in:
Wunkolo 2024-05-04 12:12:34 -07:00
parent 584c34cbd6
commit 35e8a809b1

View file

@ -408,7 +408,59 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_UGE, VECTOR_COMPARE_UGE_V128);
// ============================================================================
struct VECTOR_ADD
: Sequence<VECTOR_ADD, I<OPCODE_VECTOR_ADD, V128Op, V128Op, V128Op>> {
static void Emit(A64Emitter& e, const EmitArgType& i) {}
static void Emit(A64Emitter& e, const EmitArgType& i) {
EmitCommutativeBinaryVOp(
e, i, [&i](A64Emitter& e, const QReg& dest, QReg src1, QReg src2) {
const TypeName part_type =
static_cast<TypeName>(i.instr->flags & 0xFF);
const uint32_t arithmetic_flags = i.instr->flags >> 8;
bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED);
bool saturate = !!(arithmetic_flags & ARITHMETIC_SATURATE);
switch (part_type) {
case INT8_TYPE:
if (saturate) {
if (is_unsigned) {
e.UQADD(dest.B16(), src1.B16(), src2.B16());
} else {
e.SQADD(dest.B16(), src1.B16(), src2.B16());
}
} else {
e.ADD(dest.B16(), src1.B16(), src2.B16());
}
break;
case INT16_TYPE:
if (saturate) {
if (is_unsigned) {
e.UQADD(dest.H8(), src1.H8(), src2.H8());
} else {
e.SQADD(dest.H8(), src1.H8(), src2.H8());
}
} else {
e.ADD(dest.H8(), src1.H8(), src2.H8());
}
break;
case INT32_TYPE:
if (saturate) {
if (is_unsigned) {
e.UQADD(dest.S4(), src1.S4(), src2.S4());
} else {
e.SQADD(dest.S4(), src1.S4(), src2.S4());
}
} else {
e.ADD(dest.S4(), src1.S4(), src2.S4());
}
break;
case FLOAT32_TYPE:
assert_false(is_unsigned);
assert_false(saturate);
e.FADD(dest.S4(), src1.S4(), src2.S4());
break;
default:
assert_unhandled_case(part_type);
break;
}
});
}
};
EMITTER_OPCODE_TABLE(OPCODE_VECTOR_ADD, VECTOR_ADD);