simd_three_different: Deduplicate common implementations
Generally, the only difference between the signed variants and the unsigned variants is whether or not we use a sign-extension or zero-extension, so we can simply use common functions to implement both cases without totally duplicating code twice here.
This commit is contained in:
parent
9c0d5cf15c
commit
fcae4e2418
1 changed files with 104 additions and 168 deletions
|
@ -18,8 +18,12 @@ enum class Signedness {
|
||||||
Unsigned
|
Unsigned
|
||||||
};
|
};
|
||||||
|
|
||||||
void AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
||||||
AbsoluteDifferenceBehavior behavior, Signedness sign) {
|
AbsoluteDifferenceBehavior behavior, Signedness sign) {
|
||||||
|
if (size == 0b11) {
|
||||||
|
return v.ReservedValue();
|
||||||
|
}
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
const size_t esize = 8 << size.ZeroExtend();
|
||||||
const size_t datasize = 64;
|
const size_t datasize = 64;
|
||||||
|
|
||||||
|
@ -34,6 +38,7 @@ void AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
|
||||||
}
|
}
|
||||||
|
|
||||||
v.V(2 * datasize, Vd, result);
|
v.V(2 * datasize, Vd, result);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MultiplyLongBehavior {
|
enum class MultiplyLongBehavior {
|
||||||
|
@ -42,8 +47,12 @@ enum class MultiplyLongBehavior {
|
||||||
Subtract
|
Subtract
|
||||||
};
|
};
|
||||||
|
|
||||||
void MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
||||||
MultiplyLongBehavior behavior, Signedness sign) {
|
MultiplyLongBehavior behavior, Signedness sign) {
|
||||||
|
if (size == 0b11) {
|
||||||
|
return v.ReservedValue();
|
||||||
|
}
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
const size_t esize = 8 << size.ZeroExtend();
|
||||||
const size_t doubled_esize = 2 * esize;
|
const size_t doubled_esize = 2 * esize;
|
||||||
const size_t datasize = 64;
|
const size_t datasize = 64;
|
||||||
|
@ -74,227 +83,154 @@ void MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec
|
||||||
}
|
}
|
||||||
|
|
||||||
v.V(doubled_datasize, Vd, result);
|
v.V(doubled_datasize, Vd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class LongOperationBehavior {
|
||||||
|
Addition,
|
||||||
|
Subtraction
|
||||||
|
};
|
||||||
|
|
||||||
|
bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
||||||
|
LongOperationBehavior behavior, Signedness sign) {
|
||||||
|
if (size == 0b11) {
|
||||||
|
return v.ReservedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t esize = 8 << size.ZeroExtend();
|
||||||
|
const size_t part = Q ? 1 : 0;
|
||||||
|
|
||||||
|
const auto get_operand = [&](Vec vec) {
|
||||||
|
const IR::U128 tmp = v.Vpart(64, vec, part);
|
||||||
|
|
||||||
|
if (sign == Signedness::Signed) {
|
||||||
|
return v.ir.VectorSignExtend(esize, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.ir.VectorZeroExtend(esize, tmp);
|
||||||
|
};
|
||||||
|
|
||||||
|
const IR::U128 operand1 = get_operand(Vn);
|
||||||
|
const IR::U128 operand2 = get_operand(Vm);
|
||||||
|
const IR::U128 result = [&] {
|
||||||
|
if (behavior == LongOperationBehavior::Addition) {
|
||||||
|
return v.ir.VectorAdd(esize * 2, operand1, operand2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.ir.VectorSub(esize * 2, operand1, operand2);
|
||||||
|
}();
|
||||||
|
|
||||||
|
v.V(128, Vd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WideOperationBehavior {
|
||||||
|
Addition,
|
||||||
|
Subtraction
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
||||||
|
WideOperationBehavior behavior, Signedness sign) {
|
||||||
|
if (size == 0b11) {
|
||||||
|
return v.ReservedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t esize = 8 << size.ZeroExtend();
|
||||||
|
const size_t part = Q ? 1 : 0;
|
||||||
|
|
||||||
|
const IR::U128 operand1 = v.V(128, Vn);
|
||||||
|
const IR::U128 operand2 = [&] {
|
||||||
|
const IR::U128 tmp = v.Vpart(64, Vm, part);
|
||||||
|
|
||||||
|
if (sign == Signedness::Signed) {
|
||||||
|
return v.ir.VectorSignExtend(esize, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.ir.VectorZeroExtend(esize, tmp);
|
||||||
|
}();
|
||||||
|
const IR::U128 result = [&] {
|
||||||
|
if (behavior == WideOperationBehavior::Addition) {
|
||||||
|
return v.ir.VectorAdd(esize * 2, operand1, operand2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.ir.VectorSub(esize * 2, operand1, operand2);
|
||||||
|
}();
|
||||||
|
|
||||||
|
v.V(128, Vd, result);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = ir.VectorSignExtend(esize, Vpart(64, Vn, part));
|
|
||||||
const IR::U128 operand2 = ir.VectorSignExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorAdd(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = V(128, Vn);
|
|
||||||
const IR::U128 operand2 = ir.VectorSignExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorAdd(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = V(128, Vn);
|
|
||||||
const IR::U128 operand2 = ir.VectorSignExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorSub(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Signed);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = ir.VectorSignExtend(esize, Vpart(64, Vn, part));
|
|
||||||
const IR::U128 operand2 = ir.VectorSignExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorSub(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = ir.VectorZeroExtend(esize, Vpart(64, Vn, part));
|
|
||||||
const IR::U128 operand2 = ir.VectorZeroExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorAdd(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = V(128, Vn);
|
|
||||||
const IR::U128 operand2 = ir.VectorZeroExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorAdd(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = V(128, Vn);
|
|
||||||
const IR::U128 operand2 = ir.VectorZeroExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorSub(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
if (size == 0b11) {
|
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Unsigned);
|
||||||
return ReservedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8 << size.ZeroExtend();
|
|
||||||
const size_t part = Q ? 1 : 0;
|
|
||||||
|
|
||||||
const IR::U128 operand1 = ir.VectorZeroExtend(esize, Vpart(64, Vn, part));
|
|
||||||
const IR::U128 operand2 = ir.VectorZeroExtend(esize, Vpart(64, Vm, part));
|
|
||||||
const IR::U128 result = ir.VectorSub(esize * 2, operand1, operand2);
|
|
||||||
|
|
||||||
V(128, Vd, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
|
Loading…
Reference in a new issue