2018-01-21 18:45:43 +01:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
|
* Copyright (c) 2018 MerryMage
|
|
|
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
|
|
|
* General Public License version 2 or any later version.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "frontend/A64/translate/impl/impl.h"
|
|
|
|
|
|
2018-01-26 14:51:48 +01:00
|
|
|
namespace Dynarmic::A64 {
|
2018-04-20 21:33:14 +02:00
|
|
|
namespace {
|
2018-08-13 20:50:29 +02:00
|
|
|
enum class Operation {
|
2018-04-20 21:33:14 +02:00
|
|
|
Add,
|
|
|
|
|
Subtract,
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-23 17:16:25 +02:00
|
|
|
enum class ExtraBehavior {
|
|
|
|
|
None,
|
|
|
|
|
Round
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-22 22:55:40 +02:00
|
|
|
bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
2018-08-13 20:50:29 +02:00
|
|
|
Operation op, ExtraBehavior behavior) {
|
2018-07-22 22:55:40 +02:00
|
|
|
if (size == 0b11) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 21:33:14 +02:00
|
|
|
const size_t part = Q;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
2018-04-23 17:16:25 +02:00
|
|
|
const size_t doubled_esize = 2 * esize;
|
2018-04-20 21:33:14 +02:00
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.ir.GetQ(Vn);
|
|
|
|
|
const IR::U128 operand2 = v.ir.GetQ(Vm);
|
2018-04-23 17:16:25 +02:00
|
|
|
IR::U128 wide = [&] {
|
2018-08-13 20:50:29 +02:00
|
|
|
if (op == Operation::Add) {
|
2018-04-23 17:16:25 +02:00
|
|
|
return v.ir.VectorAdd(doubled_esize, operand1, operand2);
|
2018-04-20 21:33:14 +02:00
|
|
|
}
|
2018-04-23 17:16:25 +02:00
|
|
|
return v.ir.VectorSub(doubled_esize, operand1, operand2);
|
2018-04-20 21:33:14 +02:00
|
|
|
}();
|
2018-04-23 17:16:25 +02:00
|
|
|
|
|
|
|
|
if (behavior == ExtraBehavior::Round) {
|
|
|
|
|
const u64 round_const = 1ULL << (esize - 1);
|
|
|
|
|
const IR::U128 round_operand = v.ir.VectorBroadcast(doubled_esize, v.I(doubled_esize, round_const));
|
|
|
|
|
wide = v.ir.VectorAdd(doubled_esize, wide, round_operand);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const IR::U128 result = v.ir.VectorNarrow(doubled_esize,
|
|
|
|
|
v.ir.VectorLogicalShiftRight(doubled_esize, wide, static_cast<u8>(esize)));
|
2018-04-20 21:33:14 +02:00
|
|
|
|
|
|
|
|
v.Vpart(64, Vd, part, result);
|
2018-07-22 22:55:40 +02:00
|
|
|
return true;
|
2018-04-20 21:33:14 +02:00
|
|
|
}
|
2018-05-08 22:42:59 +02:00
|
|
|
|
|
|
|
|
enum class AbsDiffExtraBehavior {
|
|
|
|
|
None,
|
|
|
|
|
Accumulate
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehavior behavior) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = [&] {
|
|
|
|
|
const IR::U128 tmp = v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
if (behavior == AbsDiffExtraBehavior::Accumulate) {
|
|
|
|
|
const IR::U128 d = v.V(datasize, Vd);
|
|
|
|
|
return v.ir.VectorAdd(esize, d, tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 23:35:30 +02:00
|
|
|
enum class Signedness {
|
|
|
|
|
Signed,
|
|
|
|
|
Unsigned
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 result = sign == Signedness::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2)
|
|
|
|
|
: v.ir.VectorRoundingHalvingAddUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-06-04 02:28:16 +02:00
|
|
|
|
2018-08-16 19:55:59 +02:00
|
|
|
bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = [&] {
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
return v.ir.VectorRoundingShiftLeftSigned(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.ir.VectorRoundingShiftLeftUnsigned(esize, operand1, operand2);
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-04 02:28:16 +02:00
|
|
|
enum class ComparisonType {
|
|
|
|
|
EQ,
|
|
|
|
|
GE,
|
2018-07-14 00:58:39 +02:00
|
|
|
AbsoluteGE,
|
|
|
|
|
GT,
|
|
|
|
|
AbsoluteGT
|
2018-06-04 02:28:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonType type) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = [&] {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case ComparisonType::EQ:
|
|
|
|
|
return v.ir.FPVectorEqual(esize, operand1, operand2);
|
|
|
|
|
case ComparisonType::GE:
|
|
|
|
|
return v.ir.FPVectorGreaterEqual(esize, operand1, operand2);
|
2018-07-14 00:58:39 +02:00
|
|
|
case ComparisonType::AbsoluteGE:
|
|
|
|
|
return v.ir.FPVectorGreaterEqual(esize,
|
|
|
|
|
v.ir.FPVectorAbs(esize, operand1),
|
|
|
|
|
v.ir.FPVectorAbs(esize, operand2));
|
2018-06-04 02:28:16 +02:00
|
|
|
case ComparisonType::GT:
|
|
|
|
|
return v.ir.FPVectorGreater(esize, operand1, operand2);
|
2018-07-14 00:58:39 +02:00
|
|
|
case ComparisonType::AbsoluteGT:
|
|
|
|
|
return v.ir.FPVectorGreater(esize,
|
|
|
|
|
v.ir.FPVectorAbs(esize, operand1),
|
|
|
|
|
v.ir.FPVectorAbs(esize, operand2));
|
2018-06-04 02:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
return IR::U128{};
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-07-07 21:38:18 +02:00
|
|
|
|
|
|
|
|
enum class MinMaxOperation {
|
|
|
|
|
Min,
|
|
|
|
|
Max,
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-29 23:43:10 +02:00
|
|
|
bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
|
|
|
|
MinMaxOperation operation, Signedness sign) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = [&] {
|
|
|
|
|
switch (operation) {
|
|
|
|
|
case MinMaxOperation::Max:
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
return v.ir.VectorMaxSigned(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
return v.ir.VectorMaxUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
case MinMaxOperation::Min:
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
return v.ir.VectorMinSigned(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
return v.ir.VectorMinUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
return IR::U128{};
|
|
|
|
|
}
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-07 21:38:18 +02:00
|
|
|
bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = [&] {
|
|
|
|
|
if (operation == MinMaxOperation::Min) {
|
|
|
|
|
return v.ir.FPVectorMin(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.ir.FPVectorMax(esize, operand1, operand2);
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 17:00:59 +02:00
|
|
|
bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd,
|
|
|
|
|
IR::U32U64 (IREmitter::* fn)(const IR::U32U64&, const IR::U32U64&, bool)) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t elements = datasize / esize;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
IR::U128 result = v.ir.ZeroVector();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < elements; i++) {
|
|
|
|
|
const IR::UAny elem1 = v.ir.VectorGetElement(esize, operand1, i);
|
|
|
|
|
const IR::UAny elem2 = v.ir.VectorGetElement(esize, operand2, i);
|
|
|
|
|
const IR::UAny result_elem = (v.ir.*fn)(elem1, elem2, true);
|
|
|
|
|
|
|
|
|
|
result = v.ir.VectorSetElement(esize, result, i, result_elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-29 23:35:11 +02:00
|
|
|
bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
|
|
|
|
MinMaxOperation operation, Signedness sign) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
IR::U128 result = [&] {
|
|
|
|
|
switch (operation) {
|
|
|
|
|
case MinMaxOperation::Max:
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
return v.ir.VectorPairedMaxSigned(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
return v.ir.VectorPairedMaxUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
case MinMaxOperation::Min:
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
return v.ir.VectorPairedMinSigned(esize, operand1, operand2);
|
|
|
|
|
}
|
|
|
|
|
return v.ir.VectorPairedMinUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
return IR::U128{};
|
|
|
|
|
}
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = v.ir.VectorShuffleWords(result, 0b11101000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 14:06:11 +02:00
|
|
|
bool FPPairedMinMax(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd,
|
|
|
|
|
IR::U32U64 (IREmitter::* fn)(const IR::U32U64&, const IR::U32U64&, bool)) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t elements = datasize / esize;
|
|
|
|
|
const size_t boundary = elements / 2;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
IR::U128 result = v.ir.ZeroVector();
|
|
|
|
|
|
|
|
|
|
const auto operation = [&](IR::U128 operand, size_t result_start_index) {
|
|
|
|
|
for (size_t i = 0; i < elements; i += 2, result_start_index++) {
|
|
|
|
|
const IR::UAny elem1 = v.ir.VectorGetElement(esize, operand, i);
|
|
|
|
|
const IR::UAny elem2 = v.ir.VectorGetElement(esize, operand, i + 1);
|
|
|
|
|
const IR::UAny result_elem = (v.ir.*fn)(elem1, elem2, true);
|
|
|
|
|
|
|
|
|
|
result = v.ir.VectorSetElement(esize, result, result_start_index, result_elem);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
operation(operand1, 0);
|
|
|
|
|
operation(operand2, boundary);
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-13 20:50:29 +02:00
|
|
|
bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
|
|
|
|
|
Operation op, Signedness sign) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return v.ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t elements = datasize / esize;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = v.V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = v.V(datasize, Vm);
|
|
|
|
|
IR::U128 result = v.ir.ZeroVector();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < elements; i++) {
|
|
|
|
|
const IR::UAny op1_elem = v.ir.VectorGetElement(esize, operand1, i);
|
|
|
|
|
const IR::UAny op2_elem = v.ir.VectorGetElement(esize, operand2, i);
|
|
|
|
|
const auto result_elem = [&] {
|
|
|
|
|
if (sign == Signedness::Signed) {
|
|
|
|
|
if (op == Operation::Add) {
|
|
|
|
|
return v.ir.SignedSaturatedAdd(op1_elem, op2_elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.ir.SignedSaturatedSub(op1_elem, op2_elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (op == Operation::Add) {
|
|
|
|
|
return v.ir.UnsignedSaturatedAdd(op1_elem, op2_elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.ir.UnsignedSaturatedSub(op1_elem, op2_elem);
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
v.ir.OrQC(result_elem.overflow);
|
|
|
|
|
|
|
|
|
|
result = v.ir.VectorSetElement(esize, result, i, result_elem.result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 21:33:14 +02:00
|
|
|
} // Anonymous namespace
|
2018-01-21 18:45:43 +01:00
|
|
|
|
2018-02-13 15:07:09 +01:00
|
|
|
bool TranslatorVisitor::CMGT_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorGreaterSigned(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 19:29:54 +01:00
|
|
|
bool TranslatorVisitor::CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
2018-02-13 20:01:47 +01:00
|
|
|
IR::U128 result = ir.VectorGreaterEqualSigned(esize, operand1, operand2);
|
|
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
2018-02-13 19:29:54 +01:00
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 22:42:59 +02:00
|
|
|
bool TranslatorVisitor::SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::Accumulate);
|
|
|
|
|
}
|
2018-05-08 22:33:28 +02:00
|
|
|
|
2018-05-08 22:42:59 +02:00
|
|
|
bool TranslatorVisitor::SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::None);
|
2018-05-08 22:33:28 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-13 18:57:07 +01:00
|
|
|
bool TranslatorVisitor::SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-29 23:43:10 +02:00
|
|
|
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
|
2018-02-13 18:57:07 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-29 23:35:11 +02:00
|
|
|
bool TranslatorVisitor::SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 18:57:07 +01:00
|
|
|
bool TranslatorVisitor::SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-29 23:43:10 +02:00
|
|
|
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
|
2018-02-13 18:57:07 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-29 23:35:11 +02:00
|
|
|
bool TranslatorVisitor::SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
|
|
|
|
|
}
|
2018-09-05 23:14:02 +02:00
|
|
|
|
|
|
|
|
bool TranslatorVisitor::SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b00 || size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
2018-09-15 10:04:19 +02:00
|
|
|
const IR::U128 result = ir.VectorSignedSaturatedDoublingMultiply(esize, operand1, operand2).upper;
|
2018-09-05 23:14:02 +02:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-15 14:57:50 +02:00
|
|
|
|
|
|
|
|
bool TranslatorVisitor::SQRDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b00 || size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::UpperAndLower multiply = ir.VectorSignedSaturatedDoublingMultiply(esize, operand1, operand2);
|
|
|
|
|
const IR::U128 result = ir.VectorAdd(esize, multiply.upper, ir.VectorLogicalShiftRight(esize, multiply.lower, static_cast<u8>(esize - 1)));
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-07-29 23:35:11 +02:00
|
|
|
|
2018-01-21 18:45:43 +01:00
|
|
|
bool TranslatorVisitor::ADD_vector(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
auto result = ir.VectorAdd(esize, operand1, operand2);
|
2018-01-21 18:45:43 +01:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-11 12:00:16 +01:00
|
|
|
bool TranslatorVisitor::MLA_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 operand3 = V(datasize, Vd);
|
|
|
|
|
|
|
|
|
|
const IR::U128 result = ir.VectorAdd(esize, ir.VectorMultiply(esize, operand1, operand2), operand3);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-11 11:18:47 +01:00
|
|
|
bool TranslatorVisitor::MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
const IR::U128 result = ir.VectorMultiply(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 21:33:14 +02:00
|
|
|
bool TranslatorVisitor::ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-08-13 20:50:29 +02:00
|
|
|
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::None);
|
2018-04-23 17:16:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-08-13 20:50:29 +02:00
|
|
|
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::Round);
|
2018-04-20 21:33:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-08-13 20:50:29 +02:00
|
|
|
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::None);
|
2018-04-20 21:33:14 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-23 17:32:44 +02:00
|
|
|
bool TranslatorVisitor::RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-08-13 20:50:29 +02:00
|
|
|
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::Round);
|
2018-04-23 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-04 15:06:01 +02:00
|
|
|
bool TranslatorVisitor::SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorHalvingAddSigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-07 18:50:03 +02:00
|
|
|
bool TranslatorVisitor::SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorHalvingSubSigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-13 20:50:29 +02:00
|
|
|
bool TranslatorVisitor::SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Signed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Signed);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 23:35:30 +02:00
|
|
|
bool TranslatorVisitor::SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-04 15:09:34 +02:00
|
|
|
bool TranslatorVisitor::UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorHalvingAddUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-07 18:50:47 +02:00
|
|
|
bool TranslatorVisitor::UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorHalvingSubUnsigned(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-13 20:50:29 +02:00
|
|
|
bool TranslatorVisitor::UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 23:35:30 +02:00
|
|
|
bool TranslatorVisitor::URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 18:44:34 +01:00
|
|
|
bool TranslatorVisitor::ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
const IR::U128 result = Q ? ir.VectorPairedAdd(esize, operand1, operand2) : ir.VectorPairedAddLower(esize, operand1, operand2);
|
2018-01-23 18:44:34 +01:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-09 02:06:46 +02:00
|
|
|
bool TranslatorVisitor::FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
2018-07-16 17:51:16 +02:00
|
|
|
const IR::U128 result = ir.FPVectorAbs(esize, ir.FPVectorSub(esize, operand1, operand2));
|
2018-06-09 02:06:46 +02:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-07 04:49:34 +02:00
|
|
|
bool TranslatorVisitor::FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-14 00:58:39 +02:00
|
|
|
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGE);
|
2018-07-07 04:49:34 +02:00
|
|
|
}
|
2018-07-07 04:35:33 +02:00
|
|
|
|
2018-07-07 04:49:34 +02:00
|
|
|
bool TranslatorVisitor::FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-14 00:58:39 +02:00
|
|
|
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGT);
|
2018-07-07 04:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-11 17:30:03 +01:00
|
|
|
bool TranslatorVisitor::FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.FPVectorAdd(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-25 14:20:07 +02:00
|
|
|
bool TranslatorVisitor::FMLA_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 operand3 = V(datasize, Vd);
|
|
|
|
|
const IR::U128 result = ir.FPVectorMulAdd(esize, operand3, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-25 14:45:02 +02:00
|
|
|
bool TranslatorVisitor::FMLS_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 operand3 = V(datasize, Vd);
|
|
|
|
|
const IR::U128 result = ir.FPVectorMulAdd(esize, operand3, ir.FPVectorNeg(esize, operand1), operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-02 22:17:15 +02:00
|
|
|
bool TranslatorVisitor::FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
2018-06-04 02:28:16 +02:00
|
|
|
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::EQ);
|
|
|
|
|
}
|
2018-06-02 22:17:15 +02:00
|
|
|
|
2018-06-04 02:28:16 +02:00
|
|
|
bool TranslatorVisitor::FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GE);
|
|
|
|
|
}
|
2018-06-02 22:17:15 +02:00
|
|
|
|
2018-06-04 02:28:16 +02:00
|
|
|
bool TranslatorVisitor::FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GT);
|
2018-06-02 22:17:15 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-21 19:27:06 +01:00
|
|
|
bool TranslatorVisitor::AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
auto result = ir.VectorAnd(operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 19:30:36 +01:00
|
|
|
bool TranslatorVisitor::BIC_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
IR::U128 result = ir.VectorAnd(operand1, ir.VectorNot(operand2));
|
2018-01-27 19:23:55 +01:00
|
|
|
|
2018-02-06 19:30:36 +01:00
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
2018-01-27 19:23:55 +01:00
|
|
|
|
2018-02-06 19:30:36 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 19:20:18 +01:00
|
|
|
bool TranslatorVisitor::CMHI_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorGreaterUnsigned(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::CMHS_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
2018-02-13 20:01:47 +01:00
|
|
|
IR::U128 result = ir.VectorGreaterEqualUnsigned(esize, operand1, operand2);
|
|
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
2018-02-13 19:20:18 +01:00
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-23 15:35:06 +02:00
|
|
|
bool TranslatorVisitor::CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 anded = ir.VectorAnd(operand1, operand2);
|
|
|
|
|
const IR::U128 result = ir.VectorNot(ir.VectorEqual(esize, anded, ir.ZeroVector()));
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 19:55:59 +02:00
|
|
|
bool TranslatorVisitor::SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-30 16:16:19 +02:00
|
|
|
bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorLogicalVShiftSigned(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 19:55:59 +02:00
|
|
|
bool TranslatorVisitor::URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-20 20:48:15 +01:00
|
|
|
bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
2018-04-30 16:01:57 +02:00
|
|
|
const IR::U128 result = ir.VectorLogicalVShiftUnsigned(esize, operand1, operand2);
|
2018-02-20 20:48:15 +01:00
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 18:57:07 +01:00
|
|
|
bool TranslatorVisitor::UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-29 23:43:10 +02:00
|
|
|
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
|
2018-02-13 18:57:07 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-29 23:35:11 +02:00
|
|
|
bool TranslatorVisitor::UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 17:39:40 +02:00
|
|
|
bool TranslatorVisitor::UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 initial_dest = V(datasize, Vd);
|
|
|
|
|
|
|
|
|
|
const IR::U128 result = ir.VectorAdd(esize, initial_dest,
|
|
|
|
|
ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2));
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 17:25:26 +02:00
|
|
|
bool TranslatorVisitor::UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend();
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 18:57:07 +01:00
|
|
|
bool TranslatorVisitor::UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
2018-07-29 23:43:10 +02:00
|
|
|
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
|
2018-02-13 18:57:07 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-29 23:35:11 +02:00
|
|
|
bool TranslatorVisitor::UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-11 13:18:05 +01:00
|
|
|
bool TranslatorVisitor::FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.FPVectorSub(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-25 20:11:43 +02:00
|
|
|
bool TranslatorVisitor::FRECPS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.FPVectorRecipStepFused(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-23 23:58:52 +02:00
|
|
|
bool TranslatorVisitor::FRSQRTS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.FPVectorRSqrtStepFused(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 01:57:56 +01:00
|
|
|
bool TranslatorVisitor::ORR_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
auto result = ir.VectorOr(operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::ORN_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
auto result = ir.VectorOr(operand1, ir.VectorNot(operand2));
|
|
|
|
|
|
2018-01-26 18:00:27 +01:00
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 01:57:56 +01:00
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-26 10:21:50 +02:00
|
|
|
bool TranslatorVisitor::PMUL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size != 0b00) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = ir.VectorPolynomialMultiply(operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-11 00:58:33 +01:00
|
|
|
bool TranslatorVisitor::SUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
auto result = ir.VectorSub(esize, operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 19:30:36 +01:00
|
|
|
bool TranslatorVisitor::CMEQ_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11 && !Q) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
IR::U128 result = ir.VectorEqual(esize, operand1, operand2);
|
2018-02-06 19:30:36 +01:00
|
|
|
|
|
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-11 12:04:46 +01:00
|
|
|
bool TranslatorVisitor::MLS_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (size == 0b11) return ReservedValue();
|
|
|
|
|
const size_t esize = 8 << size.ZeroExtend<size_t>();
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 operand3 = V(datasize, Vd);
|
|
|
|
|
|
|
|
|
|
const IR::U128 result = ir.VectorSub(esize, operand3, ir.VectorMultiply(esize, operand1, operand2));
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 01:57:56 +01:00
|
|
|
bool TranslatorVisitor::EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vn);
|
|
|
|
|
auto operand2 = V(datasize, Vm);
|
|
|
|
|
|
|
|
|
|
auto result = ir.VectorEor(operand1, operand2);
|
|
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
2018-07-15 23:41:10 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-07 21:38:18 +02:00
|
|
|
bool TranslatorVisitor::FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max);
|
|
|
|
|
}
|
2018-07-07 21:29:53 +02:00
|
|
|
|
2018-08-16 17:00:59 +02:00
|
|
|
bool TranslatorVisitor::FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMaxNumeric);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 14:06:11 +02:00
|
|
|
bool TranslatorVisitor::FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPPairedMinMax(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMaxNumeric);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPPairedMinMax(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMax);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-07 21:38:18 +02:00
|
|
|
bool TranslatorVisitor::FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min);
|
2018-07-07 21:29:53 +02:00
|
|
|
}
|
|
|
|
|
|
2018-08-16 17:00:59 +02:00
|
|
|
bool TranslatorVisitor::FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMinNumeric);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 14:06:11 +02:00
|
|
|
bool TranslatorVisitor::FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPPairedMinMax(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMinNumeric);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::FMINP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
return FPPairedMinMax(*this, Q, sz, Vm, Vn, Vd, &IREmitter::FPMin);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-15 23:41:10 +02:00
|
|
|
bool TranslatorVisitor::FADDP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
const IR::U128 result = Q ? ir.FPVectorPairedAdd(esize, operand1, operand2) : ir.FPVectorPairedAddLower(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
2018-01-26 01:57:56 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-02 22:02:57 +02:00
|
|
|
bool TranslatorVisitor::FMUL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
IR::U128 result = ir.FPVectorMul(esize, operand1, operand2);
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-21 15:07:31 +01:00
|
|
|
bool TranslatorVisitor::FDIV_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
if (sz && !Q) {
|
|
|
|
|
return ReservedValue();
|
|
|
|
|
}
|
|
|
|
|
const size_t esize = sz ? 64 : 32;
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
const IR::U128 operand1 = V(datasize, Vn);
|
|
|
|
|
const IR::U128 operand2 = V(datasize, Vm);
|
|
|
|
|
IR::U128 result = ir.FPVectorDiv(esize, operand1, operand2);
|
|
|
|
|
if (datasize == 64) {
|
|
|
|
|
result = ir.VectorZeroUpper(result);
|
|
|
|
|
}
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-27 19:23:55 +01:00
|
|
|
bool TranslatorVisitor::BIF(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vd);
|
|
|
|
|
auto operand4 = V(datasize, Vn);
|
|
|
|
|
auto operand3 = ir.VectorNot(V(datasize, Vm));
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
auto result = ir.VectorEor(operand1, ir.VectorAnd(ir.VectorEor(operand1, operand4), operand3));
|
2018-01-27 19:23:55 +01:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::BIT(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand1 = V(datasize, Vd);
|
|
|
|
|
auto operand4 = V(datasize, Vn);
|
|
|
|
|
auto operand3 = V(datasize, Vm);
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
auto result = ir.VectorEor(operand1, ir.VectorAnd(ir.VectorEor(operand1, operand4), operand3));
|
2018-01-27 19:23:55 +01:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TranslatorVisitor::BSL(bool Q, Vec Vm, Vec Vn, Vec Vd) {
|
|
|
|
|
const size_t datasize = Q ? 128 : 64;
|
|
|
|
|
|
|
|
|
|
auto operand4 = V(datasize, Vn);
|
|
|
|
|
auto operand1 = V(datasize, Vm);
|
|
|
|
|
auto operand3 = V(datasize, Vd);
|
|
|
|
|
|
2018-02-10 11:18:10 +01:00
|
|
|
auto result = ir.VectorEor(operand1, ir.VectorAnd(ir.VectorEor(operand1, operand4), operand3));
|
2018-01-27 19:23:55 +01:00
|
|
|
|
|
|
|
|
V(datasize, Vd, result);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 14:51:48 +01:00
|
|
|
} // namespace Dynarmic::A64
|