Commit 9b79b2d7 authored by Milad Fa's avatar Milad Fa Committed by V8 LUCI CQ

PPC: Introduce Power10 prefixed load instructions

This CL adds prefixed load scalar and floating point
instructions to the assembler and uses it during code generation
if the processor supports it. They have also been added to the disassembler and the simulator.

Drive-by: emit_prefix is now making sure a trampoline doesn't
get emitted in between prefix and suffix. Assembler needs to
block it using BlockTrampolinePoolScope.
Drive-by: more CHECKs are added to the assembler to make sure
immediate values have the correct length.

Change-Id: Ic5e38926c65364bc97aba0b7638dde5f365ec706
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3582479Reviewed-by: 's avatarJunliang Yan <junyan@redhat.com>
Reviewed-by: 's avatarMilad Farazmand <mfarazma@redhat.com>
Commit-Queue: Milad Farazmand <mfarazma@redhat.com>
Cr-Commit-Position: refs/heads/main@{#79970}
parent 7cb9c47b
......@@ -1142,22 +1142,29 @@ void Assembler::divdu(Register dst, Register src1, Register src2, OEBit o,
#endif
// Prefixed instructions.
#define GENERATE_PREFIX_SUFFIX_BITS(immediate, prefix, suffix) \
CHECK(is_int34(immediate)); \
int32_t prefix = \
SIGN_EXT_IMM18((immediate >> 16) & kImm18Mask); /* 18 bits.*/ \
int16_t suffix = immediate & kImm16Mask; /* 16 bits.*/ \
DCHECK(is_int18(prefix));
void Assembler::paddi(Register dst, Register src, const Operand& imm) {
CHECK(CpuFeatures::IsSupported(PPC_10_PLUS));
CHECK(is_int34(imm.immediate()));
DCHECK(src != r0); // use pli instead to show intent.
int32_t hi = (imm.immediate() >> 16) & kImm18Mask; // 18 bits.
int16_t lo = imm.immediate() & kImm16Mask; // 16 bits.
ppaddi(Operand(hi));
intptr_t immediate = imm.immediate();
GENERATE_PREFIX_SUFFIX_BITS(immediate, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
addi(dst, src, Operand(lo));
}
void Assembler::pli(Register dst, const Operand& imm) {
CHECK(CpuFeatures::IsSupported(PPC_10_PLUS));
CHECK(is_int34(imm.immediate()));
int32_t hi = (imm.immediate() >> 16) & kImm18Mask; // 18 bits.
int16_t lo = imm.immediate() & kImm16Mask; // 16 bits.
ppaddi(Operand(hi));
intptr_t immediate = imm.immediate();
GENERATE_PREFIX_SUFFIX_BITS(immediate, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
li(dst, Operand(lo));
}
......@@ -1165,6 +1172,79 @@ void Assembler::psubi(Register dst, Register src, const Operand& imm) {
paddi(dst, src, Operand(-(imm.immediate())));
}
void Assembler::plbz(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lbz(dst, MemOperand(src.ra(), lo));
}
void Assembler::plhz(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lhz(dst, MemOperand(src.ra(), lo));
}
void Assembler::plha(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lha(dst, MemOperand(src.ra(), lo));
}
void Assembler::plwz(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lwz(dst, MemOperand(src.ra(), lo));
}
void Assembler::plwa(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_8ls(Operand(hi));
emit(PPLWA | dst.code() * B21 | src.ra().code() * B16 | (lo & kImm16Mask));
}
void Assembler::pld(Register dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_8ls(Operand(hi));
emit(PPLD | dst.code() * B21 | src.ra().code() * B16 | (lo & kImm16Mask));
}
void Assembler::plfs(DoubleRegister dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lfs(dst, MemOperand(src.ra(), lo));
}
void Assembler::plfd(DoubleRegister dst, const MemOperand& src) {
DCHECK(src.ra_ != r0);
int64_t offset = src.offset();
GENERATE_PREFIX_SUFFIX_BITS(offset, hi, lo)
BlockTrampolinePoolScope block_trampoline_pool(this);
pload_store_mls(Operand(hi));
lfd(dst, MemOperand(src.ra(), lo));
}
#undef GENERATE_PREFIX_SUFFIX_BITS
int Assembler::instructions_required_for_mov(Register dst,
const Operand& src) const {
bool canOptimize =
......
......@@ -604,14 +604,20 @@ class Assembler : public AssemblerBase {
PPC_VC_OPCODE_LIST(DECLARE_PPC_VC_INSTRUCTIONS)
#undef DECLARE_PPC_VC_INSTRUCTIONS
#define DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_00(name, instr_name, instr_value) \
inline void name(const Operand& imm, const PRBit pr = LeavePR) { \
prefix_form(instr_name, imm, pr); \
}
#define DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_10(name, instr_name, instr_value) \
inline void name(const Operand& imm, const PRBit pr = LeavePR) { \
prefix_10_form(instr_name, imm, pr); \
prefix_form(instr_name, imm, pr); \
}
inline void prefix_10_form(Instr instr, const Operand& imm, int pr) {
inline void prefix_form(Instr instr, const Operand& imm, int pr) {
emit_prefix(instr | pr * B20 | (imm.immediate() & kImm18Mask));
}
PPC_PREFIX_OPCODE_TYPE_00_LIST(DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_00)
PPC_PREFIX_OPCODE_TYPE_10_LIST(DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_10)
#undef DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_00
#undef DECLARE_PPC_PREFIX_INSTRUCTIONS_TYPE_10
RegList* GetScratchRegisterList() { return &scratch_register_list_; }
......@@ -1133,6 +1139,14 @@ class Assembler : public AssemblerBase {
void paddi(Register dst, Register src, const Operand& imm);
void pli(Register dst, const Operand& imm);
void psubi(Register dst, Register src, const Operand& imm);
void plbz(Register dst, const MemOperand& src);
void plhz(Register dst, const MemOperand& src);
void plha(Register dst, const MemOperand& src);
void plwz(Register dst, const MemOperand& src);
void plwa(Register dst, const MemOperand& src);
void pld(Register dst, const MemOperand& src);
void plfs(DoubleRegister dst, const MemOperand& src);
void plfd(DoubleRegister dst, const MemOperand& src);
// Pseudo instructions
......@@ -1428,6 +1442,8 @@ class Assembler : public AssemblerBase {
if (((pc_offset() + sizeof(Instr)) & 63) == 0) {
nop();
}
// Do not emit trampoline pool in between prefix and suffix.
CHECK(is_trampoline_pool_blocked());
emit(x);
}
......
......@@ -92,6 +92,9 @@ constexpr int kRootRegisterBias = 128;
// sign-extend the least significant 16-bits of value <imm>
#define SIGN_EXT_IMM16(imm) ((static_cast<int>(imm) << 16) >> 16)
// sign-extend the least significant 14-bits of value <imm>
#define SIGN_EXT_IMM18(imm) ((static_cast<int>(imm) << 14) >> 14)
// sign-extend the least significant 22-bits of value <imm>
#define SIGN_EXT_IMM22(imm) ((static_cast<int>(imm) << 10) >> 10)
......@@ -2675,38 +2678,45 @@ immediate-specified index */ \
/* System Call */ \
V(sc, SC, 0x44000002)
#define PPC_PREFIX_OPCODE_TYPE_10_LIST(V) V(ppaddi, PPADDI, 0x6000000)
#define PPC_OPCODE_LIST(V) \
PPC_X_OPCODE_LIST(V) \
PPC_X_OPCODE_EH_S_FORM_LIST(V) \
PPC_XO_OPCODE_LIST(V) \
PPC_DS_OPCODE_LIST(V) \
PPC_DQ_OPCODE_LIST(V) \
PPC_MDS_OPCODE_LIST(V) \
PPC_MD_OPCODE_LIST(V) \
PPC_XS_OPCODE_LIST(V) \
PPC_D_OPCODE_LIST(V) \
PPC_I_OPCODE_LIST(V) \
PPC_B_OPCODE_LIST(V) \
PPC_XL_OPCODE_LIST(V) \
PPC_A_OPCODE_LIST(V) \
PPC_XFX_OPCODE_LIST(V) \
PPC_M_OPCODE_LIST(V) \
PPC_SC_OPCODE_LIST(V) \
PPC_Z23_OPCODE_LIST(V) \
PPC_Z22_OPCODE_LIST(V) \
PPC_EVX_OPCODE_LIST(V) \
PPC_XFL_OPCODE_LIST(V) \
PPC_EVS_OPCODE_LIST(V) \
PPC_VX_OPCODE_LIST(V) \
PPC_VA_OPCODE_LIST(V) \
PPC_VC_OPCODE_LIST(V) \
PPC_XX1_OPCODE_LIST(V) \
PPC_XX2_OPCODE_LIST(V) \
PPC_XX3_OPCODE_VECTOR_LIST(V) \
PPC_XX3_OPCODE_SCALAR_LIST(V) \
PPC_XX4_OPCODE_LIST(V) \
#define PPC_PREFIX_OPCODE_TYPE_00_LIST(V) \
V(pload_store_8ls, PLOAD_STORE_8LS, 0x4000000) \
V(pplwa, PPLWA, 0xA4000000) \
V(ppld, PPLD, 0xE4000000)
#define PPC_PREFIX_OPCODE_TYPE_10_LIST(V) \
V(pload_store_mls, PLOAD_STORE_MLS, 0x6000000)
#define PPC_OPCODE_LIST(V) \
PPC_X_OPCODE_LIST(V) \
PPC_X_OPCODE_EH_S_FORM_LIST(V) \
PPC_XO_OPCODE_LIST(V) \
PPC_DS_OPCODE_LIST(V) \
PPC_DQ_OPCODE_LIST(V) \
PPC_MDS_OPCODE_LIST(V) \
PPC_MD_OPCODE_LIST(V) \
PPC_XS_OPCODE_LIST(V) \
PPC_D_OPCODE_LIST(V) \
PPC_I_OPCODE_LIST(V) \
PPC_B_OPCODE_LIST(V) \
PPC_XL_OPCODE_LIST(V) \
PPC_A_OPCODE_LIST(V) \
PPC_XFX_OPCODE_LIST(V) \
PPC_M_OPCODE_LIST(V) \
PPC_SC_OPCODE_LIST(V) \
PPC_Z23_OPCODE_LIST(V) \
PPC_Z22_OPCODE_LIST(V) \
PPC_EVX_OPCODE_LIST(V) \
PPC_XFL_OPCODE_LIST(V) \
PPC_EVS_OPCODE_LIST(V) \
PPC_VX_OPCODE_LIST(V) \
PPC_VA_OPCODE_LIST(V) \
PPC_VC_OPCODE_LIST(V) \
PPC_XX1_OPCODE_LIST(V) \
PPC_XX2_OPCODE_LIST(V) \
PPC_XX3_OPCODE_VECTOR_LIST(V) \
PPC_XX3_OPCODE_SCALAR_LIST(V) \
PPC_XX4_OPCODE_LIST(V) \
PPC_PREFIX_OPCODE_TYPE_00_LIST(V) \
PPC_PREFIX_OPCODE_TYPE_10_LIST(V)
enum Opcode : uint32_t {
......@@ -2988,12 +2998,19 @@ class Instruction {
inline Opcode OpcodeBase() const {
uint32_t opcode = PrefixOpcodeField();
uint32_t extcode = PrefixOpcodeField();
// Check for prefix.
switch (opcode) {
PPC_PREFIX_OPCODE_TYPE_00_LIST(OPCODE_CASES)
PPC_PREFIX_OPCODE_TYPE_10_LIST(OPCODE_CASES)
return static_cast<Opcode>(opcode);
}
opcode = OpcodeField();
extcode = OpcodeField();
// Check for suffix.
switch (opcode) {
PPC_PREFIX_OPCODE_TYPE_00_LIST(OPCODE_CASES)
return static_cast<Opcode>(opcode);
}
switch (opcode) {
PPC_D_OPCODE_LIST(OPCODE_CASES)
PPC_I_OPCODE_LIST(OPCODE_CASES)
......
......@@ -97,7 +97,7 @@ class PPCOperandConverter final : public InstructionOperandConverter {
break;
case kMode_MRI:
*first_index += 2;
return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
return MemOperand(InputRegister(index + 0), InputInt64(index + 1));
case kMode_MRR:
*first_index += 2;
return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
......@@ -454,34 +454,42 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
} while (0)
#define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx) \
do { \
DoubleRegister result = i.OutputDoubleRegister(); \
AddressingMode mode = kMode_None; \
MemOperand operand = i.MemoryOperand(&mode); \
bool is_atomic = i.InputInt32(2); \
if (mode == kMode_MRI) { \
__ asm_instr(result, operand); \
} else { \
__ asm_instrx(result, operand); \
} \
if (is_atomic) __ lwsync(); \
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
#define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrp, asm_instrx) \
do { \
DoubleRegister result = i.OutputDoubleRegister(); \
AddressingMode mode = kMode_None; \
MemOperand operand = i.MemoryOperand(&mode); \
bool is_atomic = i.InputInt32(2); \
if (mode == kMode_MRI) { \
if (CpuFeatures::IsSupported(PPC_10_PLUS)) { \
__ asm_instrp(result, operand); \
} else { \
__ asm_instr(result, operand); \
} \
} else { \
__ asm_instrx(result, operand); \
} \
if (is_atomic) __ lwsync(); \
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
} while (0)
#define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrx) \
do { \
Register result = i.OutputRegister(); \
AddressingMode mode = kMode_None; \
MemOperand operand = i.MemoryOperand(&mode); \
bool is_atomic = i.InputInt32(2); \
if (mode == kMode_MRI) { \
__ asm_instr(result, operand); \
} else { \
__ asm_instrx(result, operand); \
} \
if (is_atomic) __ lwsync(); \
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
#define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrp, asm_instrx) \
do { \
Register result = i.OutputRegister(); \
AddressingMode mode = kMode_None; \
MemOperand operand = i.MemoryOperand(&mode); \
bool is_atomic = i.InputInt32(2); \
if (mode == kMode_MRI) { \
if (CpuFeatures::IsSupported(PPC_10_PLUS)) { \
__ asm_instrp(result, operand); \
} else { \
__ asm_instr(result, operand); \
} \
} else { \
__ asm_instrx(result, operand); \
} \
if (is_atomic) __ lwsync(); \
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
} while (0)
#define ASSEMBLE_LOAD_INTEGER_RR(asm_instr) \
......@@ -1951,34 +1959,34 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
#endif
case kPPC_LoadWordU8:
ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
ASSEMBLE_LOAD_INTEGER(lbz, plbz, lbzx);
break;
case kPPC_LoadWordS8:
ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
ASSEMBLE_LOAD_INTEGER(lbz, plbz, lbzx);
__ extsb(i.OutputRegister(), i.OutputRegister());
break;
case kPPC_LoadWordU16:
ASSEMBLE_LOAD_INTEGER(lhz, lhzx);
ASSEMBLE_LOAD_INTEGER(lhz, plhz, lhzx);
break;
case kPPC_LoadWordS16:
ASSEMBLE_LOAD_INTEGER(lha, lhax);
ASSEMBLE_LOAD_INTEGER(lha, plha, lhax);
break;
case kPPC_LoadWordU32:
ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx);
break;
case kPPC_LoadWordS32:
ASSEMBLE_LOAD_INTEGER(lwa, lwax);
ASSEMBLE_LOAD_INTEGER(lwa, plwa, lwax);
break;
#if V8_TARGET_ARCH_PPC64
case kPPC_LoadWord64:
ASSEMBLE_LOAD_INTEGER(ld, ldx);
ASSEMBLE_LOAD_INTEGER(ld, pld, ldx);
break;
#endif
case kPPC_LoadFloat32:
ASSEMBLE_LOAD_FLOAT(lfs, lfsx);
ASSEMBLE_LOAD_FLOAT(lfs, plfs, lfsx);
break;
case kPPC_LoadDouble:
ASSEMBLE_LOAD_FLOAT(lfd, lfdx);
ASSEMBLE_LOAD_FLOAT(lfd, plfd, lfdx);
break;
case kPPC_LoadSimd128: {
Simd128Register result = i.OutputSimd128Register();
......@@ -3774,18 +3782,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kPPC_LoadDecompressTaggedSigned: {
CHECK(instr->HasOutput());
ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx);
break;
}
case kPPC_LoadDecompressTaggedPointer: {
CHECK(instr->HasOutput());
ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx);
__ add(i.OutputRegister(), i.OutputRegister(), kRootRegister);
break;
}
case kPPC_LoadDecompressAnyTagged: {
CHECK(instr->HasOutput());
ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx);
__ add(i.OutputRegister(), i.OutputRegister(), kRootRegister);
break;
}
......
......@@ -18,6 +18,7 @@ enum ImmediateMode {
kInt16Imm_Negate,
kInt16Imm_4ByteAligned,
kShift32Imm,
kInt34Imm,
kShift64Imm,
kNoImmediate
};
......@@ -58,6 +59,8 @@ class PPCOperandGenerator final : public OperandGenerator {
return is_int16(value) && !(value & 3);
case kShift32Imm:
return 0 <= value && value < 32;
case kInt34Imm:
return is_int34(value);
case kShift64Imm:
return 0 <= value && value < 64;
case kNoImmediate:
......@@ -173,7 +176,12 @@ static void VisitLoadCommon(InstructionSelector* selector, Node* node,
Node* base = node->InputAt(0);
Node* offset = node->InputAt(1);
InstructionCode opcode = kArchNop;
ImmediateMode mode = kInt16Imm;
ImmediateMode mode;
if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
mode = kInt34Imm;
} else {
mode = kInt16Imm;
}
switch (load_rep.representation()) {
case MachineRepresentation::kFloat32:
opcode = kPPC_LoadFloat32;
......@@ -196,7 +204,7 @@ static void VisitLoadCommon(InstructionSelector* selector, Node* node,
case MachineRepresentation::kSandboxedPointer: // Fall through.
#ifdef V8_COMPRESS_POINTERS
opcode = kPPC_LoadWordS32;
mode = kInt16Imm_4ByteAligned;
if (mode != kInt34Imm) mode = kInt16Imm_4ByteAligned;
break;
#else
UNREACHABLE();
......@@ -218,7 +226,7 @@ static void VisitLoadCommon(InstructionSelector* selector, Node* node,
#endif
case MachineRepresentation::kWord64:
opcode = kPPC_LoadWord64;
mode = kInt16Imm_4ByteAligned;
if (mode != kInt34Imm) mode = kInt16Imm_4ByteAligned;
break;
case MachineRepresentation::kSimd128:
opcode = kPPC_LoadSimd128;
......
......@@ -286,13 +286,12 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
case 'i': { // int16
int64_t value;
uint32_t addi_value = instr->Bits(15, 0);
uint32_t imm_value = instr->Bits(15, 0);
if (IsPrefixed()) {
uint64_t prefix_value = GetPrefixValue();
value = SIGN_EXT_IMM34(
static_cast<int64_t>((prefix_value << 16) | addi_value));
value = SIGN_EXT_IMM34((prefix_value << 16) | imm_value);
} else {
value = (static_cast<int64_t>(addi_value) << 48) >> 48;
value = (static_cast<int64_t>(imm_value) << 48) >> 48;
}
out_buffer_pos_ +=
base::SNPrintF(out_buffer_ + out_buffer_pos_, "%ld", value);
......@@ -465,22 +464,71 @@ void Decoder::UnknownFormat(Instruction* instr, const char* name) {
void Decoder::DecodeExtP(Instruction* instr) {
switch (EXTP | (instr->BitField(25, 25))) {
case PPADDI: {
case PLOAD_STORE_8LS:
case PLOAD_STORE_MLS: {
// Read prefix.
SetAsPrefixed(instr->Bits(17, 0));
// Read suffix (next instruction).
Instruction* next_instr =
bit_cast<Instruction*>(bit_cast<intptr_t>(instr) + kInstrSize);
CHECK_EQ(ADDI, next_instr->OpcodeField());
if (next_instr->RAValue() == 0) {
// This is load immediate prefixed.
Format(instr, "pli");
Format(next_instr, " 'rt, ");
} else {
Format(instr, "paddi");
Format(next_instr, " 'rt, 'ra, ");
switch (next_instr->OpcodeBase()) {
// Prefixed ADDI.
case (ADDI): {
if (next_instr->RAValue() == 0) {
// This is load immediate prefixed.
Format(instr, "pli");
Format(next_instr, " 'rt, ");
} else {
Format(instr, "paddi");
Format(next_instr, " 'rt, 'ra, ");
}
Format(next_instr, "'int34");
break;
}
// Prefixed LBZ.
case LBZ: {
Format(next_instr, "plbz 'rt, 'int34('ra)");
break;
}
// Prefixed LHZ.
case LHZ: {
Format(next_instr, "plhz 'rt, 'int34('ra)");
break;
}
// Prefixed LHA.
case LHA: {
Format(next_instr, "plha 'rt, 'int34('ra)");
break;
}
// Prefixed LWZ.
case LWZ: {
Format(next_instr, "plwz 'rt, 'int34('ra)");
break;
}
// Prefixed LWA.
case PPLWA: {
Format(next_instr, "plwa 'rt, 'int34('ra)");
break;
}
// Prefixed LD.
case PPLD: {
Format(next_instr, "pld 'rt, 'int34('ra)");
break;
}
// Prefixed LFS.
case LFS: {
Format(next_instr, "plfs 'Dt, 'int34('ra)");
break;
}
// Prefixed LFD.
case LFD: {
Format(next_instr, "plfd 'Dt, 'int34('ra)");
break;
}
default: {
Unknown(instr);
}
}
Format(next_instr, "'int34");
break;
}
default: {
......
......@@ -1541,6 +1541,119 @@ float VMXFPMax(float x, float y) {
void Simulator::ExecuteGeneric(Instruction* instr) {
uint32_t opcode = instr->OpcodeBase();
switch (opcode) {
// Prefixed instructions.
case PLOAD_STORE_8LS:
case PLOAD_STORE_MLS: {
// Read prefix value.
uint64_t prefix_value = instr->Bits(17, 0);
// Read suffix (next instruction).
Instruction* next_instr = bit_cast<Instruction*>(get_pc() + kInstrSize);
uint16_t suffix_value = next_instr->Bits(15, 0);
int64_t im_val = SIGN_EXT_IMM34((prefix_value << 16) | suffix_value);
switch (next_instr->OpcodeBase()) {
// Prefixed ADDI.
case ADDI: {
int rt = next_instr->RTValue();
int ra = next_instr->RAValue();
intptr_t alu_out;
if (ra == 0) {
alu_out = im_val;
} else {
intptr_t ra_val = get_register(ra);
alu_out = ra_val + im_val;
}
set_register(rt, alu_out);
break;
}
// Prefixed LBZ.
case LBZ: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
set_register(rt, ReadB(ra_val + im_val) & 0xFF);
break;
}
// Prefixed LHZ.
case LHZ: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
uintptr_t result = ReadHU(ra_val + im_val) & 0xFFFF;
set_register(rt, result);
break;
}
// Prefixed LHA.
case LHA: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t result = ReadH(ra_val + im_val);
set_register(rt, result);
break;
}
// Prefixed LWZ.
case LWZ: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
set_register(rt, ReadWU(ra_val + im_val));
break;
}
// Prefixed LWA.
case PPLWA: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
int64_t ra_val = ra == 0 ? 0 : get_register(ra);
set_register(rt, ReadW(ra_val + im_val));
break;
}
// Prefixed LD.
case PPLD: {
int ra = next_instr->RAValue();
int rt = next_instr->RTValue();
int64_t ra_val = ra == 0 ? 0 : get_register(ra);
set_register(rt, ReadDW(ra_val + im_val));
break;
}
// Prefixed LFS.
case LFS: {
int frt = next_instr->RTValue();
int ra = next_instr->RAValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t val = ReadW(ra_val + im_val);
float* fptr = reinterpret_cast<float*>(&val);
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
// Conversion using double changes sNan to qNan on ia32/x64
if ((val & 0x7F800000) == 0x7F800000) {
int64_t dval = static_cast<int64_t>(val);
dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29) |
0x0;
set_d_register(frt, dval);
} else {
set_d_register_from_double(frt, static_cast<double>(*fptr));
}
#else
set_d_register_from_double(frt, static_cast<double>(*fptr));
#endif
break;
}
// Prefixed LFD.
case LFD: {
int frt = next_instr->RTValue();
int ra = next_instr->RAValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int64_t dptr = ReadDW(ra_val + im_val);
set_d_register(frt, dptr);
break;
}
default:
UNREACHABLE();
}
// We have now executed instructions at this as well as next pc.
set_pc(get_pc() + (2 * kInstrSize));
break;
}
case SUBFIC: {
int rt = instr->RTValue();
int ra = instr->RAValue();
......@@ -1644,42 +1757,21 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
set_register(rt, alu_out);
break;
}
#define SET_ADDI_RESULT() \
intptr_t alu_out; \
if (ra == 0) { \
alu_out = im_val; \
} else { \
intptr_t ra_val = get_register(ra); \
alu_out = ra_val + im_val; \
} \
set_register(rt, alu_out);
case ADDI: {
int rt = instr->RTValue();
int ra = instr->RAValue();
int32_t im_val = SIGN_EXT_IMM16(instr->Bits(15, 0));
SET_ADDI_RESULT();
intptr_t alu_out;
if (ra == 0) {
alu_out = im_val;
} else {
intptr_t ra_val = get_register(ra);
alu_out = ra_val + im_val;
}
set_register(rt, alu_out);
// todo - handle RC bit
break;
}
case PPADDI: {
// Read prefix.
uint64_t prefix_value = instr->Bits(17, 0);
// Read suffix (next instruction).
Instruction* next_instr = bit_cast<Instruction*>(get_pc() + kInstrSize);
CHECK_EQ(ADDI, next_instr->OpcodeBase());
// Execute as a single instruction.
int rt = next_instr->RTValue();
int ra = next_instr->RAValue();
int64_t im_val;
uint16_t addi_value = next_instr->Bits(15, 0);
im_val = SIGN_EXT_IMM34(
static_cast<int64_t>((prefix_value << 16) | addi_value));
SET_ADDI_RESULT();
// We have now executed instructions at this as well as next pc.
set_pc(get_pc() + (2 * kInstrSize));
break;
}
#undef SET_ADDI_RESULT
case ADDIS: {
int rt = instr->RTValue();
int ra = instr->RAValue();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment