#ifndef V8_EXECUTION_ARM64_SIMULATOR_ARM64_H_
#define V8_EXECUTION_ARM64_SIMULATOR_ARM64_H_
#include "src/common/globals.h"
#if defined(USE_SIMULATOR)
#include <stdarg.h>
#include <vector>
#include "src/base/compiler-specific.h"
#include "src/codegen/arm64/assembler-arm64.h"
#include "src/codegen/arm64/decoder-arm64.h"
#include "src/codegen/assembler.h"
#include "src/diagnostics/arm64/disasm-arm64.h"
#include "src/execution/simulator-base.h"
#include "src/utils/allocation.h"
#include "src/utils/utils.h"
namespace v8 {
namespace internal {
template <class T, int ebits, int mbits>
T FPRound(int64_t sign, int64_t exponent, uint64_t mantissa,
FPRounding round_mode) {
static_assert((sizeof(T) * 8) >= (1 + ebits + mbits),
"destination type T not large enough");
static_assert(sizeof(T) <= sizeof(uint64_t),
"maximum size of destination type T is 64 bits");
static_assert(std::is_unsigned_v<T>, "destination type T must be unsigned");
DCHECK((sign == 0) || (sign == 1));
DCHECK((round_mode == FPTieEven) || (round_mode == FPRoundOdd));
const int mantissa_offset = 0;
const int exponent_offset = mantissa_offset + mbits;
const int sign_offset = exponent_offset + ebits;
DCHECK_EQ(sign_offset, static_cast<int>(sizeof(T) * 8 - 1));
if (mantissa == 0) {
return static_cast<T>(sign << sign_offset);
}
const int infinite_exponent = (1 << ebits) - 1;
const int max_normal_exponent = infinite_exponent - 1;
exponent += max_normal_exponent >> 1;
if (exponent > max_normal_exponent) {
if (round_mode == FPTieEven) {
exponent = infinite_exponent;
mantissa = 0;
} else {
DCHECK_EQ(round_mode, FPRoundOdd);
exponent = max_normal_exponent;
mantissa = (UINT64_C(1) << exponent_offset) - 1;
}
return static_cast<T>((sign << sign_offset) |
(exponent << exponent_offset) |
(mantissa << mantissa_offset));
}
const int highest_significant_bit = 63 - CountLeadingZeros(mantissa, 64);
int shift = highest_significant_bit - mbits;
if (exponent <= 0) {
shift += -exponent + 1;
if (shift > (highest_significant_bit + 1)) {
if (round_mode == FPTieEven) {
return static_cast<T>(sign << sign_offset);
} else {
DCHECK_EQ(round_mode, FPRoundOdd);
DCHECK_NE(mantissa, 0U);
return static_cast<T>((sign << sign_offset) | 1);
}
}
exponent = 0;
} else {
mantissa &= ~(UINT64_C(1) << highest_significant_bit);
}
if (shift > 0) {
if (round_mode == FPTieEven) {
uint64_t onebit_mantissa = (mantissa >> (shift)) & 1;
uint64_t halfbit_mantissa = (mantissa >> (shift - 1)) & 1;
uint64_t adjustment = (halfbit_mantissa & ~onebit_mantissa);
uint64_t adjusted = mantissa - adjustment;
T halfbit_adjusted = (adjusted >> (shift - 1)) & 1;
T result =
static_cast<T>((sign << sign_offset) | (exponent << exponent_offset) |
((mantissa >> shift) << mantissa_offset));
return result + halfbit_adjusted;
} else {
DCHECK_EQ(round_mode, FPRoundOdd);
uint64_t fractional_bits = mantissa & ((UINT64_C(1) << shift) - 1);
if (fractional_bits != 0) {
mantissa |= UINT64_C(1) << shift;
}
return static_cast<T>((sign << sign_offset) |
(exponent << exponent_offset) |
((mantissa >> shift) << mantissa_offset));
}
} else {
return static_cast<T>((sign << sign_offset) |
(exponent << exponent_offset) |
((mantissa << -shift) << mantissa_offset));
}
}
class CachePage {
};
class SimMemory {
public:
template <typename T>
static T AddressUntag(T address) {
uint64_t bits = (uint64_t)address;
return (T)(bits & ~kAddressTagMask);
}
template <typename T, typename A>
static T Read(A address) {
T value;
address = AddressUntag(address);
DCHECK((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
memcpy(&value, reinterpret_cast<const char*>(address), sizeof(value));
return value;
}
template <typename T, typename A>
static void Write(A address, T value) {
address = AddressUntag(address);
DCHECK((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
memcpy(reinterpret_cast<char*>(address), &value, sizeof(value));
}
};
class SimSystemRegister {
public:
SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) {}
uint32_t RawValue() const { return value_; }
void SetRawValue(uint32_t new_value) {
value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
}
uint32_t Bits(int msb, int lsb) const {
return unsigned_bitextract_32(msb, lsb, value_);
}
int32_t SignedBits(int msb, int lsb) const {
return signed_bitextract_32(msb, lsb, value_);
}
void SetBits(int msb, int lsb, uint32_t bits);
static SimSystemRegister DefaultValueFor(SystemRegister id);
#define DEFINE_GETTER(Name, HighBit, LowBit, Func, Type) \
Type Name() const { return static_cast<Type>(Func(HighBit, LowBit)); } \
void Set##Name(Type bits) { \
SetBits(HighBit, LowBit, static_cast<Type>(bits)); \
}
#define DEFINE_WRITE_IGNORE_MASK(Name, Mask) \
static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK)
#undef DEFINE_ZERO_BITS
#undef DEFINE_GETTER
protected:
SimSystemRegister(uint32_t value, uint32_t write_ignore_mask)
: value_(value), write_ignore_mask_(write_ignore_mask) {}
uint32_t value_;
uint32_t write_ignore_mask_;
};
template <int kSizeInBytes>
class SimRegisterBase {
public:
template <typename T>
void Set(T new_value) {
static_assert(sizeof(new_value) <= kSizeInBytes,
"Size of new_value must be <= size of template type.");
if (sizeof(new_value) < kSizeInBytes) {
memset(value_ + sizeof(new_value), 0, kSizeInBytes - sizeof(new_value));
}
memcpy(&value_, &new_value, sizeof(T));
NotifyRegisterWrite();
}
template <typename T>
void Insert(int lane, T new_value) {
DCHECK_GE(lane, 0);
DCHECK_LE(sizeof(new_value) + (lane * sizeof(new_value)),
static_cast<unsigned>(kSizeInBytes));
memcpy(&value_[lane * sizeof(new_value)], &new_value, sizeof(new_value));
NotifyRegisterWrite();
}
template <typename T>
T Get(int lane = 0) const {
T result;
DCHECK_GE(lane, 0);
DCHECK_LE(sizeof(result) + (lane * sizeof(result)),
static_cast<unsigned>(kSizeInBytes));
memcpy(&result, &value_[lane * sizeof(result)], sizeof(result));
return result;
}
bool WrittenSinceLastLog() const { return written_since_last_log_; }
void NotifyRegisterLogged() { written_since_last_log_ = false; }
protected:
uint8_t value_[kSizeInBytes];
bool written_since_last_log_;
void NotifyRegisterWrite() { written_since_last_log_ = true; }
};
using SimRegister = SimRegisterBase<kXRegSize>;
using SimVRegister = SimRegisterBase<kQRegSize>;
using sim_uint128_t = std::pair<uint64_t, uint64_t>;
class LogicVRegister {
public:
inline LogicVRegister(SimVRegister& other)
: register_(other) {
for (unsigned i = 0; i < arraysize(saturated_); i++) {
saturated_[i] = kNotSaturated;
}
for (unsigned i = 0; i < arraysize(round_); i++) {
round_[i] = false;
}
}
int64_t Int(VectorFormat vform, int index) const {
int64_t element;
switch (LaneSizeInBitsFromFormat(vform)) {
case 8:
element = register_.Get<int8_t>(index);
break;
case 16:
element = register_.Get<int16_t>(index);
break;
case 32:
element = register_.Get<int32_t>(index);
break;
case 64:
element = register_.Get<int64_t>(index);
break;
default:
UNREACHABLE();
return 0;
}
return element;
}
uint64_t Uint(VectorFormat vform, int index) const {
uint64_t element;
switch (LaneSizeInBitsFromFormat(vform)) {
case 8:
element = register_.Get<uint8_t>(index);
break;
case 16:
element = register_.Get<uint16_t>(index);
break;
case 32:
element = register_.Get<uint32_t>(index);
break;
case 64:
element = register_.Get<uint64_t>(index);
break;
default:
UNREACHABLE();
return 0;
}
return element;
}
uint64_t UintLeftJustified(VectorFormat vform, int index) const {
return Uint(vform, index) << (64 - LaneSizeInBitsFromFormat(vform));
}
int64_t IntLeftJustified(VectorFormat vform, int index) const {
uint64_t value = UintLeftJustified(vform, index);
int64_t result;
memcpy(&result, &value, sizeof(result));
return result;
}
void SetInt(VectorFormat vform, int index, int64_t value) const {
switch (LaneSizeInBitsFromFormat(vform)) {
case 8:
register_.Insert(index, static_cast<int8_t>(value));
break;
case 16:
register_.Insert(index, static_cast<int16_t>(value));
break;
case 32:
register_.Insert(index, static_cast<int32_t>(value));
break;
case 64:
register_.Insert(index, static_cast<int64_t>(value));
break;
default:
UNREACHABLE();
return;
}
}
void SetIntArray(VectorFormat vform, const int64_t* src) const {
ClearForWrite(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
SetInt(vform, i, src[i]);
}
}
void SetUint(VectorFormat vform, int index, uint64_t value) const {
switch (LaneSizeInBitsFromFormat(vform)) {
case 8:
register_.Insert(index, static_cast<uint8_t>(value));
break;
case 16:
register_.Insert(index, static_cast<uint16_t>(value));
break;
case 32:
register_.Insert(index, static_cast<uint32_t>(value));
break;
case 64:
register_.Insert(index, static_cast<uint64_t>(value));
break;
default:
UNREACHABLE();
return;
}
}
void SetUint(VectorFormat vform, int index, sim_uint128_t value) const {
if (LaneSizeInBitsFromFormat(vform) <= 64) {
SetUint(vform, index, value.second);
return;
}
DCHECK((vform == kFormat1Q) && (index == 0));
SetUint(kFormat2D, 0, value.second);
SetUint(kFormat2D, 1, value.first);
}
void SetUintArray(VectorFormat vform, const uint64_t* src) const {
ClearForWrite(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
SetUint(vform, i, src[i]);
}
}
void ReadUintFromMem(VectorFormat vform, int index, uint64_t addr) const;
void WriteUintToMem(VectorFormat vform, int index, uint64_t addr) const;
template <typename T>
T Float(int index) const {
return register_.Get<T>(index);
}
template <typename T>
void SetFloat(int index, T value) const {
register_.Insert(index, value);
}
void ClearForWrite(VectorFormat vform) const {
unsigned size = RegisterSizeInBytesFromFormat(vform);
for (unsigned i = size; i < kQRegSize; i++) {
SetUint(kFormat16B, i, 0);
}
}
enum Saturation {
kNotSaturated = 0,
kSignedSatPositive = 1 << 0,
kSignedSatNegative = 1 << 1,
kSignedSatMask = kSignedSatPositive | kSignedSatNegative,
kSignedSatUndefined = kSignedSatMask,
kUnsignedSatPositive = 1 << 2,
kUnsignedSatNegative = 1 << 3,
kUnsignedSatMask = kUnsignedSatPositive | kUnsignedSatNegative,
kUnsignedSatUndefined = kUnsignedSatMask
};
Saturation GetSignedSaturation(int index) {
return static_cast<Saturation>(saturated_[index] & kSignedSatMask);
}
Saturation GetUnsignedSaturation(int index) {
return static_cast<Saturation>(saturated_[index] & kUnsignedSatMask);
}
void ClearSat(int index) { saturated_[index] = kNotSaturated; }
void SetSignedSat(int index, bool positive) {
SetSatFlag(index, positive ? kSignedSatPositive : kSignedSatNegative);
}
void SetUnsignedSat(int index, bool positive) {
SetSatFlag(index, positive ? kUnsignedSatPositive : kUnsignedSatNegative);
}
void SetSatFlag(int index, Saturation sat) {
saturated_[index] = static_cast<Saturation>(saturated_[index] | sat);
DCHECK_NE(sat & kUnsignedSatMask, kUnsignedSatUndefined);
DCHECK_NE(sat & kSignedSatMask, kSignedSatUndefined);
}
LogicVRegister& SignedSaturate(VectorFormat vform) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
Saturation sat = GetSignedSaturation(i);
if (sat == kSignedSatPositive) {
SetInt(vform, i, MaxIntFromFormat(vform));
} else if (sat == kSignedSatNegative) {
SetInt(vform, i, MinIntFromFormat(vform));
}
}
return *this;
}
LogicVRegister& UnsignedSaturate(VectorFormat vform) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
Saturation sat = GetUnsignedSaturation(i);
if (sat == kUnsignedSatPositive) {
SetUint(vform, i, MaxUintFromFormat(vform));
} else if (sat == kUnsignedSatNegative) {
SetUint(vform, i, 0);
}
}
return *this;
}
bool GetRounding(int index) { return round_[index]; }
void SetRounding(int index, bool round) { round_[index] = round; }
LogicVRegister& Round(VectorFormat vform) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
SetUint(vform, i, Uint(vform, i) + (GetRounding(i) ? 1 : 0));
}
return *this;
}
LogicVRegister& Uhalve(VectorFormat vform) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
uint64_t val = Uint(vform, i);
SetRounding(i, (val & 1) == 1);
val >>= 1;
if (GetUnsignedSaturation(i) != kNotSaturated) {
val |= (MaxUintFromFormat(vform) >> 1) + 1;
}
SetInt(vform, i, val);
}
return *this;
}
LogicVRegister& Halve(VectorFormat vform) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
int64_t val = Int(vform, i);
SetRounding(i, (val & 1) == 1);
val >>= 1;
if (GetSignedSaturation(i) != kNotSaturated) {
val ^= (MaxUintFromFormat(vform) >> 1) + 1;
}
SetInt(vform, i, val);
}
return *this;
}
bool Is(const LogicVRegister& r) const { return ®ister_ == &r.register_; }
private:
SimVRegister& register_;
Saturation saturated_[kQRegSize];
bool round_[kQRegSize];
};
class Simulator : public DecoderVisitor, public SimulatorBase {
public:
static void SetRedirectInstruction(Instruction* instruction);
static bool ICacheMatch(void* one, void* two) { return false; }
static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
size_t size) {
USE(i_cache);
USE(start);
USE(size);
}
V8_EXPORT_PRIVATE explicit Simulator(
Decoder<DispatchingDecoderVisitor>* decoder, Isolate* isolate = nullptr,
FILE* stream = stderr);
Simulator();
V8_EXPORT_PRIVATE ~Simulator();
V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate);
class CallArgument {
public:
template <typename T>
explicit CallArgument(T argument) {
bits_ = 0;
DCHECK(sizeof(argument) <= sizeof(bits_));
memcpy(&bits_, &argument, sizeof(argument));
type_ = X_ARG;
}
explicit CallArgument(double argument) {
DCHECK(sizeof(argument) == sizeof(bits_));
memcpy(&bits_, &argument, sizeof(argument));
type_ = D_ARG;
}
explicit CallArgument(float argument) {
DCHECK(sizeof(kFP64SignallingNaN) == sizeof(bits_));
memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN));
DCHECK(sizeof(argument) <= sizeof(bits_));
memcpy(&bits_, &argument, sizeof(argument));
type_ = D_ARG;
}
static CallArgument End() { return CallArgument(); }
int64_t bits() const { return bits_; }
bool IsEnd() const { return type_ == NO_ARG; }
bool IsX() const { return type_ == X_ARG; }
bool IsD() const { return type_ == D_ARG; }
private:
enum CallArgumentType { X_ARG, D_ARG, NO_ARG };
int64_t bits_;
CallArgumentType type_;
CallArgument() { type_ = NO_ARG; }
};
template <typename Return, typename... Args>
Return Call(Address entry, Args... args) {
CallArgument call_args[] = {CallArgument(args)..., CallArgument::End()};
CallImpl(entry, call_args);
return ReadReturn<Return>();
}
void Debug();
bool ExecDebugCommand(ArrayUniquePtr<char> command);
bool GetValue(const char* desc, int64_t* value);
bool PrintValue(const char* desc);
V8_EXPORT_PRIVATE uintptr_t PushAddress(uintptr_t address);
V8_EXPORT_PRIVATE uintptr_t PopAddress();
uintptr_t StackLimit(uintptr_t c_limit) const;
uintptr_t StackBase() const;
void SetStackLimit(uintptr_t limit);
base::Vector<uint8_t> GetCentralStackView() const;
static constexpr int JSStackLimitMargin() { return kAdditionalStackMargin; }
void IterateRegistersAndStack(::heap::base::StackVisitor* visitor);
V8_EXPORT_PRIVATE void ResetState();
void DoRuntimeCall(Instruction* instr);
static const Instruction* kEndOfSimAddress;
void DecodeInstruction();
void Run();
V8_EXPORT_PRIVATE void RunFrom(Instruction* start);
template <typename T>
void set_pc(T new_pc) {
static_assert(sizeof(T) == sizeof(pc_));
memcpy(&pc_, &new_pc, sizeof(T));
pc_modified_ = true;
}
Instruction* pc() { return pc_; }
Instruction* last_instr() { return last_instr_; }
void increment_pc() {
if (!pc_modified_) {
pc_ = pc_->following();
}
pc_modified_ = false;
}
virtual void Decode(Instruction* instr) { decoder_->Decode(instr); }
enum BType {
DefaultBType = 0,
BranchFromUnguardedOrToIP = 1,
BranchAndLink = 2,
BranchFromGuardedNotToIP = 3
};
BType btype() const { return btype_; }
void ResetBType() { btype_ = DefaultBType; }
void set_btype(BType btype) { btype_ = btype; }
BType GetBTypeFromInstruction(const Instruction* instr) const;
bool PcIsInGuardedPage() const { return guard_pages_; }
void SetGuardedPages(bool guard_pages) { guard_pages_ = guard_pages; }
void CheckBTypeForPAuth() {
DCHECK(pc_->IsPAuth());
Instr instr = pc_->Mask(SystemPAuthMask);
CHECK(instr == PACIBSP);
switch (btype()) {
case BranchFromGuardedNotToIP:
FATAL("Executing PACIBSP with wrong BType.");
case BranchFromUnguardedOrToIP:
case BranchAndLink:
break;
case DefaultBType:
UNREACHABLE();
}
}
void CheckBTypeForBti() {
DCHECK(pc_->IsBti());
switch (pc_->ImmHint()) {
case BTI_jc:
break;
case BTI: {
DCHECK(btype() != DefaultBType);
FATAL("Executing BTI with wrong BType (expected 0, got %d).", btype());
break;
}
case BTI_c:
if (btype() == BranchFromGuardedNotToIP) {
FATAL("Executing BTI c with wrong BType (3).");
}
break;
case BTI_j:
if (btype() == BranchAndLink) {
FATAL("Executing BTI j with wrong BType (2).");
}
break;
default:
UNIMPLEMENTED();
}
}
void CheckBType() {
if (PcIsInGuardedPage() && (btype() != DefaultBType)) {
if (pc_->IsPAuth()) {
CheckBTypeForPAuth();
} else if (pc_->IsBti()) {
CheckBTypeForBti();
} else if (!pc_->IsException()) {
FATAL("Executing non-BTI instruction with wrong BType.");
}
}
}
void VisitCpyP(Instruction* instr);
void VisitCpyM(Instruction* instr);
void VisitCpyE(Instruction* instr);
void VisitSetP(Instruction* instr);
void VisitSetM(Instruction* instr);
void VisitSetE(Instruction* instr);
template <Instruction::MemOp mem_op>
void MOPSPHelper(Instruction* instr) {
DCHECK(instr->IsConsistentMOPSTriplet<mem_op>());
int d = instr->Rd();
int n = instr->Rn();
int s = instr->Rs();
if ((d == n) || (d == s) || (n == s) || (d == 31) || (n == 31)) {
VisitUnallocated(instr);
}
if (mem_op == Instruction::MemOp::kCPY && s == 31) {
VisitUnallocated(instr);
}
if (instr->Bits(31, 30) != 0) {
VisitUnallocated(instr);
}
uint64_t xn = xreg(n);
constexpr int saturation_bits =
mem_op == Instruction::MemOp::kCPY ? 55 : 63;
if ((xn >> saturation_bits) != 0) {
xn = (UINT64_C(1) << saturation_bits) - 1;
set_xreg(n, xn);
}
nzcv().SetN(0);
nzcv().SetZ(0);
nzcv().SetC(1);
nzcv().SetV(0);
}
void ExecuteInstruction() {
DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstrSize));
CheckBType();
ResetBType();
CheckBreakNext();
Decode(pc_);
last_instr_ = pc_;
increment_pc();
LogAllWrittenRegisters();
CheckBreakpoints();
}
#define DECLARE(A) void Visit##A(Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
void VisitNEON3SameFP(NEON3SameOp op, VectorFormat vf, SimVRegister& rd,
SimVRegister& rn, SimVRegister& rm);
bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const {
return ((code == 31) && (r31mode == Reg31IsZeroRegister));
}
template <typename T>
T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
if (IsZeroRegister(code, r31mode)) {
return 0;
}
return registers_[code].Get<T>();
}
int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<int32_t>(code, r31mode);
}
int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<int64_t>(code, r31mode);
}
enum RegLogMode { LogRegWrites, NoRegLog };
template <typename T>
void set_reg(unsigned code, T value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg_no_log(code, value, r31mode);
LogRegister(code, r31mode);
}
void set_wreg(unsigned code, int32_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg(code, value, r31mode);
}
void set_xreg(unsigned code, int64_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg(code, value, r31mode);
}
template <typename T>
void set_reg_no_log(unsigned code, T value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
if (!IsZeroRegister(code, r31mode)) {
registers_[code].Set(value);
}
}
void set_wreg_no_log(unsigned code, int32_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg_no_log(code, value, r31mode);
}
void set_xreg_no_log(unsigned code, int64_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg_no_log(code, value, r31mode);
}
template <typename T>
void set_lr(T value) {
DCHECK_EQ(sizeof(T), static_cast<unsigned>(kSystemPointerSize));
set_reg(kLinkRegCode, value);
}
template <typename T>
void set_sp(T value) {
DCHECK_EQ(sizeof(T), static_cast<unsigned>(kSystemPointerSize));
set_reg(31, value, Reg31IsStackPointer);
}
struct qreg_t {
uint8_t val[kQRegSize];
};
template <typename T>
T vreg(unsigned code) const {
static_assert((sizeof(T) == kBRegSize) || (sizeof(T) == kHRegSize) ||
(sizeof(T) == kSRegSize) || (sizeof(T) == kDRegSize) ||
(sizeof(T) == kQRegSize),
"Template type must match size of register.");
DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
return vregisters_[code].Get<T>();
}
inline SimVRegister& vreg(unsigned code) { return vregisters_[code]; }
int64_t sp() { return xreg(31, Reg31IsStackPointer); }
int64_t fp() { return xreg(kFramePointerRegCode, Reg31IsStackPointer); }
Instruction* lr() { return reg<Instruction*>(kLinkRegCode); }
Address get_sp() const { return reg<Address>(31, Reg31IsStackPointer); }
uint8_t breg(unsigned code) const { return vreg<uint8_t>(code); }
float hreg(unsigned code) const { return vreg<uint16_t>(code); }
float sreg(unsigned code) const { return vreg<float>(code); }
uint32_t sreg_bits(unsigned code) const { return vreg<uint32_t>(code); }
double dreg(unsigned code) const { return vreg<double>(code); }
uint64_t dreg_bits(unsigned code) const { return vreg<uint64_t>(code); }
qreg_t qreg(unsigned code) const { return vreg<qreg_t>(code); }
template <typename T>
T vreg(unsigned size, unsigned code) const {
uint64_t raw = 0;
T result;
switch (size) {
case kSRegSize:
raw = vreg<uint32_t>(code);
break;
case kDRegSize:
raw = vreg<uint64_t>(code);
break;
default:
UNREACHABLE();
}
static_assert(sizeof(result) <= sizeof(raw),
"Template type must be <= 64 bits.");
memcpy(&result, &raw, sizeof(result));
return result;
}
template <typename T>
void set_vreg(unsigned code, T value, RegLogMode log_mode = LogRegWrites) {
static_assert(
(sizeof(value) == kBRegSize) || (sizeof(value) == kHRegSize) ||
(sizeof(value) == kSRegSize) || (sizeof(value) == kDRegSize) ||
(sizeof(value) == kQRegSize),
"Template type must match size of register.");
DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
vregisters_[code].Set(value);
if (log_mode == LogRegWrites) {
LogVRegister(code, GetPrintRegisterFormat(value));
}
}
void set_breg(unsigned code, int8_t value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_hreg(unsigned code, int16_t value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_sreg(unsigned code, float value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_sreg_bits(unsigned code, uint32_t value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_dreg(unsigned code, double value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_dreg_bits(unsigned code, uint64_t value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
void set_qreg(unsigned code, qreg_t value,
RegLogMode log_mode = LogRegWrites) {
set_vreg(code, value, log_mode);
}
template <typename T>
void set_vreg_no_log(unsigned code, T value) {
static_assert((sizeof(value) == kBRegSize) ||
(sizeof(value) == kHRegSize) ||
(sizeof(value) == kSRegSize) ||
(sizeof(value) == kDRegSize) || (sizeof(value) == kQRegSize));
DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
vregisters_[code].Set(value);
}
void set_breg_no_log(unsigned code, uint8_t value) {
set_vreg_no_log(code, value);
}
void set_hreg_no_log(unsigned code, uint16_t value) {
set_vreg_no_log(code, value);
}
void set_sreg_no_log(unsigned code, float value) {
set_vreg_no_log(code, value);
}
void set_dreg_no_log(unsigned code, double value) {
set_vreg_no_log(code, value);
}
void set_qreg_no_log(unsigned code, qreg_t value) {
set_vreg_no_log(code, value);
}
SimSystemRegister& nzcv() { return nzcv_; }
SimSystemRegister& fpcr() { return fpcr_; }
FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
bool DN() { return fpcr_.DN() != 0; }
struct Breakpoint {
Instruction* location;
bool enabled;
};
std::vector<Breakpoint> breakpoints_;
void SetBreakpoint(Instruction* breakpoint);
void ListBreakpoints();
void CheckBreakpoints();
bool break_on_next_;
void CheckBreakNext();
void PrintInstructionsAt(Instruction* pc, uint64_t count);
void PrintRegisters();
void PrintVRegisters();
void PrintSystemRegisters();
void PrintWrittenRegisters();
void PrintWrittenVRegisters();
void LogWrittenRegisters() {
if (log_parameters() & LOG_REGS) PrintWrittenRegisters();
}
void LogWrittenVRegisters() {
if (log_parameters() & LOG_VREGS) PrintWrittenVRegisters();
}
void LogAllWrittenRegisters() {
LogWrittenRegisters();
LogWrittenVRegisters();
}
enum PrintRegisterFormat {
kPrintRegLaneSizeB = 0 << 0,
kPrintRegLaneSizeH = 1 << 0,
kPrintRegLaneSizeS = 2 << 0,
kPrintRegLaneSizeW = kPrintRegLaneSizeS,
kPrintRegLaneSizeD = 3 << 0,
kPrintRegLaneSizeX = kPrintRegLaneSizeD,
kPrintRegLaneSizeQ = 4 << 0,
kPrintRegLaneSizeOffset = 0,
kPrintRegLaneSizeMask = 7 << 0,
kPrintRegAsScalar = 0,
kPrintRegAsDVector = 1 << 3,
kPrintRegAsQVector = 2 << 3,
kPrintRegAsVectorMask = 3 << 3,
kPrintRegAsFP = 1 << 5,
kPrintXReg = kPrintRegLaneSizeX | kPrintRegAsScalar,
kPrintWReg = kPrintRegLaneSizeW | kPrintRegAsScalar,
kPrintSReg = kPrintRegLaneSizeS | kPrintRegAsScalar | kPrintRegAsFP,
kPrintDReg = kPrintRegLaneSizeD | kPrintRegAsScalar | kPrintRegAsFP,
kPrintReg1B = kPrintRegLaneSizeB | kPrintRegAsScalar,
kPrintReg8B = kPrintRegLaneSizeB | kPrintRegAsDVector,
kPrintReg16B = kPrintRegLaneSizeB | kPrintRegAsQVector,
kPrintReg1H = kPrintRegLaneSizeH | kPrintRegAsScalar,
kPrintReg4H = kPrintRegLaneSizeH | kPrintRegAsDVector,
kPrintReg8H = kPrintRegLaneSizeH | kPrintRegAsQVector,
kPrintReg1S = kPrintRegLaneSizeS | kPrintRegAsScalar,
kPrintReg2S = kPrintRegLaneSizeS | kPrintRegAsDVector,
kPrintReg4S = kPrintRegLaneSizeS | kPrintRegAsQVector,
kPrintReg1SFP = kPrintRegLaneSizeS | kPrintRegAsScalar | kPrintRegAsFP,
kPrintReg2SFP = kPrintRegLaneSizeS | kPrintRegAsDVector | kPrintRegAsFP,
kPrintReg4SFP = kPrintRegLaneSizeS | kPrintRegAsQVector | kPrintRegAsFP,
kPrintReg1D = kPrintRegLaneSizeD | kPrintRegAsScalar,
kPrintReg2D = kPrintRegLaneSizeD | kPrintRegAsQVector,
kPrintReg1DFP = kPrintRegLaneSizeD | kPrintRegAsScalar | kPrintRegAsFP,
kPrintReg2DFP = kPrintRegLaneSizeD | kPrintRegAsQVector | kPrintRegAsFP,
kPrintReg1Q = kPrintRegLaneSizeQ | kPrintRegAsScalar
};
unsigned GetPrintRegLaneSizeInBytesLog2(PrintRegisterFormat format) {
return (format & kPrintRegLaneSizeMask) >> kPrintRegLaneSizeOffset;
}
unsigned GetPrintRegLaneSizeInBytes(PrintRegisterFormat format) {
return 1 << GetPrintRegLaneSizeInBytesLog2(format);
}
unsigned GetPrintRegSizeInBytesLog2(PrintRegisterFormat format) {
if (format & kPrintRegAsDVector) return kDRegSizeLog2;
if (format & kPrintRegAsQVector) return kQRegSizeLog2;
return GetPrintRegLaneSizeInBytesLog2(format);
}
unsigned GetPrintRegSizeInBytes(PrintRegisterFormat format) {
return 1 << GetPrintRegSizeInBytesLog2(format);
}
unsigned GetPrintRegLaneCount(PrintRegisterFormat format) {
unsigned reg_size_log2 = GetPrintRegSizeInBytesLog2(format);
unsigned lane_size_log2 = GetPrintRegLaneSizeInBytesLog2(format);
DCHECK_GE(reg_size_log2, lane_size_log2);
return 1 << (reg_size_log2 - lane_size_log2);
}
template <typename T>
PrintRegisterFormat GetPrintRegisterFormat(T value) {
return GetPrintRegisterFormatForSize(sizeof(value));
}
PrintRegisterFormat GetPrintRegisterFormat(double value) {
static_assert(sizeof(value) == kDRegSize,
"D register must be size of double.");
return GetPrintRegisterFormatForSizeFP(sizeof(value));
}
PrintRegisterFormat GetPrintRegisterFormat(float value) {
static_assert(sizeof(value) == kSRegSize,
"S register must be size of float.");
return GetPrintRegisterFormatForSizeFP(sizeof(value));
}
PrintRegisterFormat GetPrintRegisterFormat(VectorFormat vform);
PrintRegisterFormat GetPrintRegisterFormatFP(VectorFormat vform);
PrintRegisterFormat GetPrintRegisterFormatForSize(size_t reg_size,
size_t lane_size);
PrintRegisterFormat GetPrintRegisterFormatForSize(size_t size) {
return GetPrintRegisterFormatForSize(size, size);
}
PrintRegisterFormat GetPrintRegisterFormatForSizeFP(size_t size) {
switch (size) {
default:
UNREACHABLE();
case kDRegSize:
return kPrintDReg;
case kSRegSize:
return kPrintSReg;
}
}
PrintRegisterFormat GetPrintRegisterFormatTryFP(PrintRegisterFormat format) {
if ((GetPrintRegLaneSizeInBytes(format) == kSRegSize) ||
(GetPrintRegLaneSizeInBytes(format) == kDRegSize)) {
return static_cast<PrintRegisterFormat>(format | kPrintRegAsFP);
}
return format;
}
void PrintRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer);
void PrintVRegister(unsigned code, PrintRegisterFormat sizes);
void PrintSystemRegister(SystemRegister id);
void LogRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer) {
if (log_parameters() & LOG_REGS) PrintRegister(code, r31mode);
}
void LogVRegister(unsigned code, PrintRegisterFormat format) {
if (log_parameters() & LOG_VREGS) PrintVRegister(code, format);
}
void LogSystemRegister(SystemRegister id) {
if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id);
}
void PrintRead(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format);
void PrintWrite(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format);
void PrintVRead(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format, unsigned lane);
void PrintVWrite(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format, unsigned lane);
void LogRead(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format) {
if (log_parameters() & LOG_REGS) PrintRead(address, reg_code, format);
}
void LogWrite(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format) {
if (log_parameters() & LOG_WRITE) PrintWrite(address, reg_code, format);
}
void LogVRead(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format, unsigned lane = 0) {
if (log_parameters() & LOG_VREGS) {
PrintVRead(address, reg_code, format, lane);
}
}
void LogVWrite(uintptr_t address, unsigned reg_code,
PrintRegisterFormat format, unsigned lane = 0) {
if (log_parameters() & LOG_WRITE) {
PrintVWrite(address, reg_code, format, lane);
}
}
int log_parameters() { return log_parameters_; }
void set_log_parameters(int new_parameters) {
log_parameters_ = new_parameters;
if (!decoder_) {
if (new_parameters & LOG_DISASM) {
PrintF("Run --debug-sim to dynamically turn on disassembler\n");
}
return;
}
if (new_parameters & LOG_DISASM) {
decoder_->InsertVisitorBefore(print_disasm_, this);
} else {
decoder_->RemoveVisitor(print_disasm_);
}
}
void PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode,
int size_in_bytes = kXRegSize);
void PrintVRegisterRawHelper(unsigned code, int bytes = kQRegSize,
int lsb = 0);
void PrintVRegisterFPHelper(unsigned code, unsigned lane_size_in_bytes,
int lane_count = 1, int rightmost_lane = 0);
static inline const char* WRegNameForCode(
unsigned code, Reg31Mode mode = Reg31IsZeroRegister);
static inline const char* XRegNameForCode(
unsigned code, Reg31Mode mode = Reg31IsZeroRegister);
static inline const char* SRegNameForCode(unsigned code);
static inline const char* DRegNameForCode(unsigned code);
static inline const char* VRegNameForCode(unsigned code);
static inline int CodeFromName(const char* name);
enum PointerType { kDataPointer, kInstructionPointer };
struct PACKey {
uint64_t high;
uint64_t low;
int number;
};
static V8_EXPORT_PRIVATE const PACKey kPACKeyIB;
static bool HasTBI(uint64_t ptr, PointerType type) {
USE(ptr, type);
return true;
}
static int GetBottomPACBit(uint64_t ptr, int ttbr) {
USE(ptr, ttbr);
DCHECK((ttbr == 0) || (ttbr == 1));
return 48;
}
static int GetTopPACBit(uint64_t ptr, PointerType type) {
return HasTBI(ptr, type) ? 55 : 63;
}
V8_EXPORT_PRIVATE static uint64_t CalculatePACMask(uint64_t ptr,
PointerType type,
int ext_bit);
V8_EXPORT_PRIVATE static uint64_t ComputePAC(uint64_t data, uint64_t context,
PACKey key);
V8_EXPORT_PRIVATE static uint64_t AuthPAC(uint64_t ptr, uint64_t context,
PACKey key, PointerType type);
V8_EXPORT_PRIVATE static uint64_t AddPAC(uint64_t ptr, uint64_t context,
PACKey key, PointerType type);
V8_EXPORT_PRIVATE static uint64_t StripPAC(uint64_t ptr, PointerType type);
protected:
bool ConditionPassed(Condition cond) {
SimSystemRegister& flags = nzcv();
switch (cond) {
case eq:
return flags.Z();
case ne:
return !flags.Z();
case hs:
return flags.C();
case lo:
return !flags.C();
case mi:
return flags.N();
case pl:
return !flags.N();
case vs:
return flags.V();
case vc:
return !flags.V();
case hi:
return flags.C() && !flags.Z();
case ls:
return !(flags.C() && !flags.Z());
case ge:
return flags.N() == flags.V();
case lt:
return flags.N() != flags.V();
case gt:
return !flags.Z() && (flags.N() == flags.V());
case le:
return !(!flags.Z() && (flags.N() == flags.V()));
case nv:
case al:
return true;
default:
UNREACHABLE();
}
}
bool ConditionFailed(Condition cond) { return !ConditionPassed(cond); }
template <typename T>
void AddSubHelper(Instruction* instr, T op2);
template <typename T>
T AddWithCarry(bool set_flags, T left, T right, int carry_in = 0);
template <typename T>
void AddSubWithCarry(Instruction* instr);
template <typename T>
void LogicalHelper(Instruction* instr, T op2);
template <typename T>
void ConditionalCompareHelper(Instruction* instr, T op2);
void LoadStoreHelper(Instruction* instr, int64_t offset, AddrMode addrmode);
void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
template <typename T>
void CompareAndSwapHelper(const Instruction* instr);
template <typename T>
void CompareAndSwapPairHelper(const Instruction* instr);
template <typename T>
void AtomicMemorySimpleHelper(const Instruction* instr);
template <typename T>
void AtomicMemorySwapHelper(const Instruction* instr);
uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset,
AddrMode addrmode);
void LoadStoreWriteBack(unsigned addr_reg, int64_t offset, AddrMode addrmode);
void NEONLoadStoreMultiStructHelper(const Instruction* instr,
AddrMode addr_mode);
void NEONLoadStoreSingleStructHelper(const Instruction* instr,
AddrMode addr_mode);
void CheckMemoryAccess(uintptr_t address, uintptr_t stack);
bool ProbeMemory(uintptr_t address, uintptr_t access_size);
template <typename T, typename A>
T MemoryRead(A address) {
T value;
static_assert((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
memcpy(&value, reinterpret_cast<const void*>(address), sizeof(value));
return value;
}
template <typename T, typename A>
void MemoryWrite(A address, T value) {
static_assert((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
memcpy(reinterpret_cast<void*>(address), &value, sizeof(value));
}
template <typename T>
T ShiftOperand(T value, Shift shift_type, unsigned amount);
template <typename T>
T ExtendValue(T value, Extend extend_type, unsigned left_shift = 0);
template <typename T>
void Extract(Instruction* instr);
template <typename T>
void DataProcessing2Source(Instruction* instr);
template <typename T>
void BitfieldHelper(Instruction* instr);
uint16_t PolynomialMult(uint8_t op1, uint8_t op2);
sim_uint128_t PolynomialMult128(uint64_t op1, uint64_t op2,
int lane_size_in_bits) const;
sim_uint128_t Lsl128(sim_uint128_t x, unsigned shift) const;
sim_uint128_t Eor128(sim_uint128_t x, sim_uint128_t y) const;
void SimulateSignedMinMax(const Instruction* instr);
void SimulateUnsignedMinMax(const Instruction* instr);
void ld1(VectorFormat vform, LogicVRegister dst, uint64_t addr);
void ld1(VectorFormat vform, LogicVRegister dst, int index, uint64_t addr);
void ld1r(VectorFormat vform, LogicVRegister dst, uint64_t addr);
void ld2(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
uint64_t addr);
void ld2(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
int index, uint64_t addr);
void ld2r(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
uint64_t addr);
void ld3(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, uint64_t addr);
void ld3(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, int index, uint64_t addr);
void ld3r(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, uint64_t addr);
void ld4(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, LogicVRegister dst4, uint64_t addr);
void ld4(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, LogicVRegister dst4, int index, uint64_t addr);
void ld4r(VectorFormat vform, LogicVRegister dst1, LogicVRegister dst2,
LogicVRegister dst3, LogicVRegister dst4, uint64_t addr);
void st1(VectorFormat vform, LogicVRegister src, uint64_t addr);
void st1(VectorFormat vform, LogicVRegister src, int index, uint64_t addr);
void st2(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
uint64_t addr);
void st2(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
int index, uint64_t addr);
void st3(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
LogicVRegister src3, uint64_t addr);
void st3(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
LogicVRegister src3, int index, uint64_t addr);
void st4(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
LogicVRegister src3, LogicVRegister src4, uint64_t addr);
void st4(VectorFormat vform, LogicVRegister src, LogicVRegister src2,
LogicVRegister src3, LogicVRegister src4, int index, uint64_t addr);
LogicVRegister cmp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
Condition cond);
LogicVRegister cmp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, int imm, Condition cond);
LogicVRegister cmptst(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister add(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister addp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister mla(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister mls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister mul(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister mul(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister mla(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister mls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister pmul(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
using ByElementOp = LogicVRegister (Simulator::*)(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2,
int index);
LogicVRegister fmul(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister fmla(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister fmls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister fmulx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smull(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smull2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umull(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umull2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smlal(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smlal2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umlal(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umlal2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smlsl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister smlsl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umlsl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister umlsl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister sqdmull(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister sqdmull2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, int index);
LogicVRegister sqdmlal(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister sqdmlal2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, int index);
LogicVRegister sqdmlsl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister sqdmlsl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, int index);
LogicVRegister sqdmulh(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister sqrdmulh(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, int index);
LogicVRegister sub(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister and_(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister orr(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister orn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister eor(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister bic(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister bic(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, uint64_t imm);
LogicVRegister bif(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister bit(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister bsl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister cls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister clz(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister cnt(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister not_(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister rbit(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister rev(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int revSize);
LogicVRegister rev16(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister rev32(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister rev64(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister addlp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, bool is_signed,
bool do_accumulate);
LogicVRegister saddlp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uaddlp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sadalp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uadalp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister ext(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
int index);
LogicVRegister ins_element(VectorFormat vform, LogicVRegister dst,
int dst_index, const LogicVRegister& src,
int src_index);
LogicVRegister ins_immediate(VectorFormat vform, LogicVRegister dst,
int dst_index, uint64_t imm);
LogicVRegister dup_element(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int src_index);
LogicVRegister dup_immediate(VectorFormat vform, LogicVRegister dst,
uint64_t imm);
LogicVRegister movi(VectorFormat vform, LogicVRegister dst, uint64_t imm);
LogicVRegister mvni(VectorFormat vform, LogicVRegister dst, uint64_t imm);
LogicVRegister orr(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, uint64_t imm);
LogicVRegister sshl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister ushl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister SMinMax(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
bool max);
LogicVRegister smax(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister smin(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister SMinMaxP(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, bool max);
LogicVRegister smaxp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister sminp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister addp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister addv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uaddlv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister saddlv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister SMinMaxV(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, bool max);
LogicVRegister smaxv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sminv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uxtl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uxtl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sxtl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sxtl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister Table(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& ind, bool zero_out_of_bounds,
const LogicVRegister* tab1,
const LogicVRegister* tab2 = nullptr,
const LogicVRegister* tab3 = nullptr,
const LogicVRegister* tab4 = nullptr);
LogicVRegister tbl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& ind);
LogicVRegister tbl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& ind);
LogicVRegister tbl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& tab3, const LogicVRegister& ind);
LogicVRegister tbl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& tab3, const LogicVRegister& tab4,
const LogicVRegister& ind);
LogicVRegister tbx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& ind);
LogicVRegister tbx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& ind);
LogicVRegister tbx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& tab3, const LogicVRegister& ind);
LogicVRegister tbx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& tab, const LogicVRegister& tab2,
const LogicVRegister& tab3, const LogicVRegister& tab4,
const LogicVRegister& ind);
LogicVRegister uaddl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uaddl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uaddw(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uaddw2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister saddl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister saddl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister saddw(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister saddw2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister usubl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister usubl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister usubw(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister usubw2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister ssubl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister ssubl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister ssubw(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister ssubw2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister UMinMax(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
bool max);
LogicVRegister umax(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister umin(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister UMinMaxP(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, bool max);
LogicVRegister umaxp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uminp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister UMinMaxV(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, bool max);
LogicVRegister umaxv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uminv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister trn1(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister trn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister zip1(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister zip2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uzp1(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uzp2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister shl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister scvtf(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int fbits,
FPRounding rounding_mode);
LogicVRegister ucvtf(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int fbits,
FPRounding rounding_mode);
LogicVRegister sshll(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sshll2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister shll(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister shll2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister ushll(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister ushll2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sli(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sri(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sshr(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister ushr(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister ssra(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister usra(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister srsra(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister ursra(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister suqadd(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister usqadd(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sqshl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister uqshl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqshlu(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister abs(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister neg(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister ExtractNarrow(VectorFormat vform, LogicVRegister dst,
bool dstIsSigned, const LogicVRegister& src,
bool srcIsSigned);
LogicVRegister xtn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sqxtn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister uqxtn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister sqxtun(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister AbsDiff(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
bool issigned);
LogicVRegister saba(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister uaba(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister shrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister shrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister rshrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister rshrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister uqshrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister uqshrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister uqrshrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister uqrshrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqshrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqshrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqrshrn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqrshrn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqshrun(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqshrun2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqrshrun(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqrshrun2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, int shift);
LogicVRegister sqrdmulh(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2, bool round = true);
LogicVRegister dot(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
bool is_src1_signed, bool is_src2_signed);
LogicVRegister sdot(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister sqdmulh(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2);
#define NEON_3VREG_LOGIC_LIST(V) \
V(addhn) \
V(addhn2) \
V(raddhn) \
V(raddhn2) \
V(subhn) \
V(subhn2) \
V(rsubhn) \
V(rsubhn2) \
V(pmull) \
V(pmull2) \
V(sabal) \
V(sabal2) \
V(uabal) \
V(uabal2) \
V(sabdl) \
V(sabdl2) \
V(uabdl) \
V(uabdl2) \
V(smull) \
V(smull2) \
V(umull) \
V(umull2) \
V(smlal) \
V(smlal2) \
V(umlal) \
V(umlal2) \
V(smlsl) \
V(smlsl2) \
V(umlsl) \
V(umlsl2) \
V(sqdmlal) \
V(sqdmlal2) \
V(sqdmlsl) \
V(sqdmlsl2) \
V(sqdmull) \
V(sqdmull2)
#define DEFINE_LOGIC_FUNC(FXN) \
LogicVRegister FXN(VectorFormat vform, LogicVRegister dst, \
const LogicVRegister& src1, const LogicVRegister& src2);
NEON_3VREG_LOGIC_LIST(DEFINE_LOGIC_FUNC)
#undef DEFINE_LOGIC_FUNC
#define NEON_FP3SAME_LIST(V) \
V(fadd, FPAdd, false) \
V(fsub, FPSub, true) \
V(fmul, FPMul, true) \
V(fmulx, FPMulx, true) \
V(fdiv, FPDiv, true) \
V(fmax, FPMax, false) \
V(fmin, FPMin, false) \
V(fmaxnm, FPMaxNM, false) \
V(fminnm, FPMinNM, false)
#define DECLARE_NEON_FP_VECTOR_OP(FN, OP, PROCNAN) \
template <typename T> \
LogicVRegister FN(VectorFormat vform, LogicVRegister dst, \
const LogicVRegister& src1, const LogicVRegister& src2); \
LogicVRegister FN(VectorFormat vform, LogicVRegister dst, \
const LogicVRegister& src1, const LogicVRegister& src2);
NEON_FP3SAME_LIST(DECLARE_NEON_FP_VECTOR_OP)
#undef DECLARE_NEON_FP_VECTOR_OP
#define NEON_FPPAIRWISE_LIST(V) \
V(faddp, fadd, FPAdd) \
V(fmaxp, fmax, FPMax) \
V(fmaxnmp, fmaxnm, FPMaxNM) \
V(fminp, fmin, FPMin) \
V(fminnmp, fminnm, FPMinNM)
#define DECLARE_NEON_FP_PAIR_OP(FNP, FN, OP) \
LogicVRegister FNP(VectorFormat vform, LogicVRegister dst, \
const LogicVRegister& src1, const LogicVRegister& src2); \
LogicVRegister FNP(VectorFormat vform, LogicVRegister dst, \
const LogicVRegister& src);
NEON_FPPAIRWISE_LIST(DECLARE_NEON_FP_PAIR_OP)
#undef DECLARE_NEON_FP_PAIR_OP
template <typename T>
LogicVRegister frecps(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister frecps(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
template <typename T>
LogicVRegister frsqrts(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2);
LogicVRegister frsqrts(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2);
template <typename T>
LogicVRegister fmla(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister fmla(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
template <typename T>
LogicVRegister fmls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister fmls(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister fnmul(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
template <typename T>
LogicVRegister fcmp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
Condition cond);
LogicVRegister fcmp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
Condition cond);
LogicVRegister fabscmp(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2,
Condition cond);
LogicVRegister fcmp_zero(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, Condition cond);
template <typename T>
LogicVRegister fneg(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fneg(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
template <typename T>
LogicVRegister frecpx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister frecpx(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
template <typename T>
LogicVRegister fabs_(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fabs_(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fabd(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src1, const LogicVRegister& src2);
LogicVRegister frint(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, FPRounding rounding_mode,
bool inexact_exception = false);
LogicVRegister fcvts(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, FPRounding rounding_mode,
int fbits = 0);
LogicVRegister fcvtu(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, FPRounding rounding_mode,
int fbits = 0);
LogicVRegister fcvtl(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fcvtl2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fcvtn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fcvtn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fcvtxn(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fcvtxn2(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fsqrt(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister frsqrte(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister frecpe(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, FPRounding rounding);
LogicVRegister ursqrte(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister urecpe(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
using FPMinMaxOp = float (Simulator::*)(float a, float b);
LogicVRegister FMinMaxV(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src, FPMinMaxOp Op);
LogicVRegister fminv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fmaxv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fminnmv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fmaxnmv(VectorFormat vform, LogicVRegister dst,
const LogicVRegister& src);
template <typename T>
T FPRecipSqrtEstimate(T op);
template <typename T>
T FPRecipEstimate(T op, FPRounding rounding);
template <typename T, typename R>
R FPToFixed(T op, int fbits, bool is_signed, FPRounding rounding);
void FPCompare(double val0, double val1);
double FPRoundInt(double value, FPRounding round_mode);
double FPToDouble(float value);
float FPToFloat(double value, FPRounding round_mode);
float FPToFloat(float16 value);
float16 FPToFloat16(float value, FPRounding round_mode);
float16 FPToFloat16(double value, FPRounding round_mode);
double recip_sqrt_estimate(double a);
double recip_estimate(double a);
double FPRecipSqrtEstimate(double a);
double FPRecipEstimate(double a);
double FixedToDouble(int64_t src, int fbits, FPRounding round_mode);
double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode);
float FixedToFloat(int64_t src, int fbits, FPRounding round_mode);
float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode);
float16 FixedToFloat16(int64_t src, int fbits, FPRounding round_mode);
float16 UFixedToFloat16(uint64_t src, int fbits, FPRounding round_mode);
int16_t FPToInt16(double value, FPRounding rmode);
int32_t FPToInt32(double value, FPRounding rmode);
int64_t FPToInt64(double value, FPRounding rmode);
uint16_t FPToUInt16(double value, FPRounding rmode);
uint32_t FPToUInt32(double value, FPRounding rmode);
uint64_t FPToUInt64(double value, FPRounding rmode);
int32_t FPToFixedJS(double value);
template <typename T>
T FPAdd(T op1, T op2);
template <typename T>
T FPDiv(T op1, T op2);
template <typename T>
T FPMax(T a, T b);
template <typename T>
T FPMaxNM(T a, T b);
template <typename T>
T FPMin(T a, T b);
template <typename T>
T FPMinNM(T a, T b);
template <typename T>
T FPMul(T op1, T op2);
template <typename T>
T FPMulx(T op1, T op2);
template <typename T>
T FPMulAdd(T a, T op1, T op2);
template <typename T>
T FPSqrt(T op);
template <typename T>
T FPSub(T op1, T op2);
template <typename T>
T FPRecipStepFused(T op1, T op2);
template <typename T>
T FPRSqrtStepFused(T op1, T op2);
void FPProcessException() {}
bool FPProcessNaNs(Instruction* instr);
void CheckStackAlignment();
inline void CheckPCSComplianceAndRun();
#ifdef DEBUG
static const uint64_t kCallerSavedRegisterCorruptionValue =
0xca11edc0de000000UL;
static const uint64_t kCallerSavedVRegisterCorruptionValue =
0x7ff000007f801000UL;
static const uint64_t kDefaultCPURegisterCorruptionValue =
0x7ffbad007f8bad00UL;
void CorruptRegisters(CPURegList* list,
uint64_t value = kDefaultCPURegisterCorruptionValue);
void CorruptAllCallerSavedCPURegisters();
#endif
void DoPrintf(Instruction* instr);
void DoSwitchStackLimit(Instruction* instr);
FILE* stream_;
PrintDisassembler* print_disasm_;
void PRINTF_FORMAT(2, 3) TraceSim(const char* format, ...);
SimRegister registers_[kNumberOfRegisters];
SimVRegister vregisters_[kNumberOfVRegisters];
SimSystemRegister nzcv_;
SimSystemRegister fpcr_;
void AssertSupportedFPCR() {
DCHECK_EQ(fpcr().FZ(), 0);
DCHECK(fpcr().RMode() == FPTieEven);
}
template <typename T>
static int CalcNFlag(T result) {
return (result >> (sizeof(T) * 8 - 1)) & 1;
}
static int CalcZFlag(uint64_t result) { return result == 0; }
static const uint32_t kConditionFlagsMask = 0xf0000000;
uintptr_t stack_;
static const size_t kStackProtectionSize = KB;
static size_t AllocatedStackSize() {
return (v8_flags.sim_stack_size * KB) + (2 * kStackProtectionSize);
}
static size_t UsableStackSize() { return v8_flags.sim_stack_size * KB; }
uintptr_t stack_limit_;
static const int kAdditionalStackMargin = 20 * KB;
Decoder<DispatchingDecoderVisitor>* decoder_;
Decoder<DispatchingDecoderVisitor>* disassembler_decoder_;
bool pc_modified_;
Instruction* pc_;
Instruction* last_instr_ = nullptr;
BType btype_;
bool guard_pages_;
static const char* xreg_names[];
static const char* wreg_names[];
static const char* sreg_names[];
static const char* dreg_names[];
static const char* vreg_names[];
void set_last_debugger_input(ArrayUniquePtr<char> input) {
last_debugger_input_ = std::move(input);
}
const char* last_debugger_input() { return last_debugger_input_.get(); }
ArrayUniquePtr<char> last_debugger_input_;
enum class MonitorAccess {
Open,
Exclusive,
};
enum class TransactionSize {
None = 0,
Byte = 1,
HalfWord = 2,
Word = 4,
DoubleWord = 8,
};
TransactionSize get_transaction_size(unsigned size);
static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 11) - 1);
class LocalMonitor {
public:
LocalMonitor();
void NotifyLoad();
void NotifyLoadExcl(uintptr_t addr, TransactionSize size);
void NotifyStore();
bool NotifyStoreExcl(uintptr_t addr, TransactionSize size);
private:
void Clear();
MonitorAccess access_state_;
uintptr_t tagged_addr_;
TransactionSize size_;
};
class GlobalMonitor {
public:
class SimulatorMutex final {
public:
explicit SimulatorMutex(GlobalMonitor* global_monitor) {
if (!global_monitor->IsSingleThreaded()) {
guard.emplace(global_monitor->mutex_);
}
}
private:
std::optional<base::MutexGuard> guard;
};
class Processor {
public:
Processor();
private:
friend class GlobalMonitor;
void Clear_Locked();
void NotifyLoadExcl_Locked(uintptr_t addr);
void NotifyStore_Locked(bool is_requesting_processor);
bool NotifyStoreExcl_Locked(uintptr_t addr, bool is_requesting_processor);
MonitorAccess access_state_;
uintptr_t tagged_addr_;
Processor* next_;
Processor* prev_;
static const int kMaxFailureCounter = 5;
int failure_counter_;
};
void NotifyLoadExcl_Locked(uintptr_t addr, Processor* processor);
void NotifyStore_Locked(Processor* processor);
bool NotifyStoreExcl_Locked(uintptr_t addr, Processor* processor);
void PrependProcessor(Processor* processor);
void RemoveProcessor(Processor* processor);
static GlobalMonitor* Get();
private:
bool IsSingleThreaded() const { return num_processors_ == 1; }
GlobalMonitor() = default;
friend class base::LeakyObject<GlobalMonitor>;
Processor* head_ = nullptr;
std::atomic<uint32_t> num_processors_ = 0;
base::Mutex mutex_;
};
LocalMonitor local_monitor_;
GlobalMonitor::Processor global_monitor_processor_;
GlobalMonitor* global_monitor_;
private:
void Init(FILE* stream);
V8_EXPORT_PRIVATE void CallImpl(Address entry, CallArgument* args);
void CallAnyCTypeFunction(Address target_address,
const EncodedCSignature& signature);
template <typename T>
T ReadReturn()
requires std::is_floating_point_v<T>
{
return static_cast<T>(dreg(0));
}
template <typename T>
T ReadReturn()
requires(!std::is_floating_point_v<T>)
{
return ConvertReturn<T>(xreg(0));
}
template <typename T>
static T FPDefaultNaN();
template <typename T>
T FPProcessNaN(T op) {
DCHECK(std::isnan(op));
return fpcr().DN() ? FPDefaultNaN<T>() : ToQuietNaN(op);
}
template <typename T>
T FPProcessNaNs(T op1, T op2) {
if (IsSignallingNaN(op1)) {
return FPProcessNaN(op1);
} else if (IsSignallingNaN(op2)) {
return FPProcessNaN(op2);
} else if (std::isnan(op1)) {
DCHECK(IsQuietNaN(op1));
return FPProcessNaN(op1);
} else if (std::isnan(op2)) {
DCHECK(IsQuietNaN(op2));
return FPProcessNaN(op2);
} else {
return 0.0;
}
}
template <typename T>
T FPProcessNaNs3(T op1, T op2, T op3) {
if (IsSignallingNaN(op1)) {
return FPProcessNaN(op1);
} else if (IsSignallingNaN(op2)) {
return FPProcessNaN(op2);
} else if (IsSignallingNaN(op3)) {
return FPProcessNaN(op3);
} else if (std::isnan(op1)) {
DCHECK(IsQuietNaN(op1));
return FPProcessNaN(op1);
} else if (std::isnan(op2)) {
DCHECK(IsQuietNaN(op2));
return FPProcessNaN(op2);
} else if (std::isnan(op3)) {
DCHECK(IsQuietNaN(op3));
return FPProcessNaN(op3);
} else {
return 0.0;
}
}
int log_parameters_;
int icount_for_stop_sim_at_;
Isolate* isolate_;
};
template <>
inline double Simulator::FPDefaultNaN<double>() {
return kFP64DefaultNaN;
}
template <>
inline float Simulator::FPDefaultNaN<float>() {
return kFP32DefaultNaN;
}
template <>
inline float16 Simulator::FPDefaultNaN<float16>() {
return kFP16DefaultNaN;
}
}
}
#endif
#endif