JitX64: Correct ARM data processing instruction implementations

* Don't depend on dispatcher to align instructions that write to PC.
* Rename GetReg15Value to PC.
* Factor out ExpandArmImmediate and CompileExpandArmImmediate_C.
This commit is contained in:
MerryMage 2016-04-14 11:46:49 +01:00
parent 208795b885
commit f921242b41
9 changed files with 507 additions and 318 deletions

View file

@ -291,6 +291,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
Register Rn = Bit<11>(instruction) ? Register::SP : Register::PC;
Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
u32 imm8 = Bits<0, 7>(instruction);
// TODO: ADR implementation incorrect. Reimplement properly.
v->ADD_imm(Cond::AL, /*S=*/false, Rn, Rd, 0xF, imm8);
})},
{ "adjust stack ptr", MakeMatcher("10110000oxxxxxxx", [](Visitor* v, u16 instruction) {

View file

@ -13,7 +13,7 @@ using namespace Gen;
void JitX64::B(Cond cond, ArmImm24 imm24) {
cond_manager.CompileCond(cond);
const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2);
const u32 new_pc = PC() + BitUtil::SignExtend<26>(imm24 << 2);
reg_alloc.FlushEverything();
current.arm_pc += GetInstSize();
@ -28,7 +28,7 @@ void JitX64::B(Cond cond, ArmImm24 imm24) {
void JitX64::BL(Cond cond, ArmImm24 imm24) {
cond_manager.CompileCond(cond);
const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2);
const u32 new_pc = PC() + BitUtil::SignExtend<26>(imm24 << 2);
ASSERT(!current.TFlag);
const u32 link_pc = current.arm_pc + GetInstSize();
@ -49,7 +49,7 @@ void JitX64::BL(Cond cond, ArmImm24 imm24) {
void JitX64::BLX_imm(bool H, ArmImm24 imm24) {
cond_manager.Always();
const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<26>(imm24 << 2) + (H ? 2 : 0);
const u32 new_pc = PC() + BitUtil::SignExtend<26>(imm24 << 2) + (H ? 2 : 0);
ASSERT(!current.TFlag);
const u32 link_pc = current.arm_pc + GetInstSize();
@ -95,7 +95,7 @@ void JitX64::BX(Cond cond, ArmReg Rm_index) {
cond_manager.CompileCond(cond);
if (Rm_index == ArmReg::PC) {
code->MOV(32, MJitStateArmPC(), Imm32(GetReg15Value()));
code->MOV(32, MJitStateArmPC(), Imm32(PC()));
code->MOV(32, MJitStateTFlag(), Imm32(0));
} else {
Gen::X64Reg Rm = reg_alloc.BindArmForRead(Rm_index);

File diff suppressed because it is too large Load diff

View file

@ -23,9 +23,9 @@ void JitX64::LoadAndStoreWordOrUnsignedByte_Immediate_Helper(X64Reg dest, bool U
if (Rn_index == ArmReg::PC) {
u32 address;
if (U) {
address = GetReg15Value_WordAligned() + imm12;
address = PC_WordAligned() + imm12;
} else {
address = GetReg15Value_WordAligned() - imm12;
address = PC_WordAligned() - imm12;
}
code->MOV(32, R(dest), Imm32(address));
} else {
@ -141,7 +141,7 @@ void JitX64::LoadAndStoreWordOrUnsignedByte_ScaledRegisterOffset(X64Reg dest, bo
code->MOV(32, R(dest), Rn);
reg_alloc.UnlockArm(Rn_index);
} else {
code->MOV(32, R(dest), Imm32(GetReg15Value_WordAligned()));
code->MOV(32, R(dest), Imm32(PC_WordAligned()));
}
LoadAndStoreWordOrUnsignedByte_ScaledRegister_Helper(dest, U, Rn_index, imm5, shift, Rm_index);
@ -343,7 +343,7 @@ void JitX64::STR_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store32LE : &Store32BE));
@ -369,7 +369,7 @@ void JitX64::STR_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store32LE : &Store32BE));
@ -395,7 +395,7 @@ void JitX64::STRB_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(&Store8));
@ -421,7 +421,7 @@ void JitX64::STRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(&Store8));
@ -706,8 +706,8 @@ void JitX64::STRD_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM3);
reg_alloc.LockX64(ABI_PARAM3);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index + 0);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM3, Rd_index + 1);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index + 0);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM3, Rd_index + 1);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store64LE : &Store64BE));
@ -737,8 +737,8 @@ void JitX64::STRD_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM3);
reg_alloc.LockX64(ABI_PARAM3);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index + 0);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM3, Rd_index + 1);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index + 0);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM3, Rd_index + 1);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store64LE : &Store64BE));
@ -765,7 +765,7 @@ void JitX64::STRH_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store16LE : &Store16BE));
@ -791,7 +791,7 @@ void JitX64::STRH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
GetValueOfRegister(code, reg_alloc, GetReg15Value(), ABI_PARAM2, Rd_index);
GetValueOfRegister(code, reg_alloc, PC(), ABI_PARAM2, Rd_index);
CompileCallHost(reinterpret_cast<const void*>(!current.EFlag ? &Store16LE : &Store16BE));

View file

@ -16,7 +16,7 @@ void JitX64::thumb_B(Cond cond, ArmImm8 imm8) {
ASSERT_MSG(current.TFlag, "thumb_B may only be called in thumb mode");
const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<9>(imm8 << 1);
const u32 new_pc = PC() + BitUtil::SignExtend<9>(imm8 << 1);
reg_alloc.FlushEverything();
current.arm_pc += GetInstSize();
@ -33,7 +33,7 @@ void JitX64::thumb_B(ArmImm11 imm11) {
ASSERT_MSG(current.TFlag, "thumb_B may only be called in thumb mode");
const u32 new_pc = GetReg15Value() + BitUtil::SignExtend<12>(imm11 << 1);
const u32 new_pc = PC() + BitUtil::SignExtend<12>(imm11 << 1);
reg_alloc.FlushEverything();
current.arm_pc += GetInstSize();

View file

@ -159,24 +159,6 @@ void JitX64::CompileSingleThumbInstruction() {
}
}
void JitX64::CompileCallHost(const void* const fn) {
// There is no need to setup the stack as the stored RSP has already been properly aligned.
reg_alloc.FlushABICallerSaved();
ASSERT(reg_alloc.JitStateReg() != RSP);
code->MOV(64, R(RSP), MJitStateHostReturnRSP());
const uintptr_t distance = reinterpret_cast<uintptr_t>(fn) - (reinterpret_cast<uintptr_t>(code->GetCodePtr()) + 5);
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
// Far call
code->MOV(64, R(RAX), ImmPtr(fn));
code->CALLptr(R(RAX));
} else {
code->CALL(fn);
}
}
// Convenience functions:
// We static_assert types because anything that calls these functions makes those assumptions.
// If the types of the variables are changed please update all code that calls these functions.
@ -262,4 +244,53 @@ Gen::OpArg JitX64::MJitStateExclusiveState() const {
return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, exclusive_state));
}
// Common instruction subroutines
void JitX64::CompileCallHost(const void* const fn) {
// There is no need to setup the stack as the stored RSP has already been properly aligned.
reg_alloc.FlushABICallerSaved();
ASSERT(reg_alloc.JitStateReg() != RSP);
code->MOV(64, R(RSP), MJitStateHostReturnRSP());
const uintptr_t distance = reinterpret_cast<uintptr_t>(fn) - (reinterpret_cast<uintptr_t>(code->GetCodePtr()) + 5);
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
// Far call
code->MOV(64, R(RAX), ImmPtr(fn));
code->CALLptr(R(RAX));
} else {
code->CALL(fn);
}
}
u32 JitX64::PC() const {
// When executing an ARM instruction, PC reads as the address of that instruction plus 8.
// When executing an Thumb instruction, PC reads as the address of that instruction plus 4.
return !current.TFlag ? current.arm_pc + 8 : current.arm_pc + 4;
}
u32 JitX64::PC_WordAligned() const {
return PC() & 0xFFFFFFFC;
}
u32 JitX64::ExpandArmImmediate(int rotate, ArmImm8 imm8) {
return CompileExpandArmImmediate_C(rotate, imm8, false);
}
u32 JitX64::CompileExpandArmImmediate_C(int rotate, ArmImm8 imm8, bool update_cflag) {
u32 immediate = rotr(imm8, rotate * 2);
if (rotate != 0 && update_cflag) {
code->MOV(32, MJitStateCFlag(), Gen::Imm32(immediate & 0x80000000 ? 1 : 0));
}
return immediate;
}
void JitX64::CompileALUWritePC() {
reg_alloc.FlushArm(ArmReg::PC);
code->AND(32, MJitStateArmPC(), Gen::Imm32(!current.TFlag ? 0xFFFFFFFC : 0xFFFFFFFE));
}
}

View file

@ -95,13 +95,6 @@ private:
Gen::OpArg MJitStateExclusiveTag() const;
Gen::OpArg MJitStateExclusiveState() const;
u32 GetReg15Value() const {
return (current.arm_pc & ~0x1) + static_cast<u32>(GetInstSize() * 2);
}
u32 GetReg15Value_WordAligned() const {
return (current.arm_pc & ~0x3) + static_cast<u32>(GetInstSize() * 2);
}
void UpdateFlagsNZCV() {
cond_manager.FlagsDirty();
code->SETcc(Gen::CC_S, MJitStateNFlag());
@ -144,10 +137,24 @@ private:
} cond_manager;
private:
// Interpreter
void CompileInterpretInstruction();
// Common instruction subroutines
/// Assembles a CALL instruction to fn.
void CompileCallHost(const void* const fn);
/// dest must be a temporary that contains a copy of the value of Rm
/// Value of R15.
u32 PC() const;
/// Value of Align(R15, 4).
u32 PC_WordAligned() const;
/// Compiles shifter operations for instructions that use the shifter. dest must be a temporary that contains a copy of the value of Rm
void CompileShifter_imm(Gen::X64Reg dest, ArmImm5 imm5, ShiftType shift, bool do_shifter_carry_out);
/// Returns the expanded immediate value for ARM instructions.
u32 ExpandArmImmediate(int rotate, ArmImm8 imm8);
/// Returns the expanded immediate value for ARM instructions. This function also sets MJitStateCFlag according to the carry output.
u32 CompileExpandArmImmediate_C(int rotate, ArmImm8 imm8, bool update_cflag);
/// Corrects the value written to MJitStateArmPC after an ALU operation that writes to the PC.
void CompileALUWritePC();
// Branch instructions
void B(Cond cond, ArmImm24 imm24) override;

View file

@ -10,106 +10,125 @@
#include "tests/core/arm/jit_x64/rand_int.h"
#include "tests/core/arm/jit_x64/fuzz_arm_common.h"
#include <common/assert.h>
TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
const std::array<std::pair<u32, u32>, 48> instructions = {{
const std::array<std::pair<u32, u32>, 16> imm_instructions = {{
FromBitString32("cccc0010101Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000101Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000101Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010100Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000100Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000100Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010000Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000000Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000000Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0011110Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0001110Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0001110Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc00110111nnnn0000rrrrvvvvvvvv"),
FromBitString32("cccc00010111nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc00010111nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc00110101nnnn0000rrrrvvvvvvvv"),
FromBitString32("cccc00010101nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc00010101nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc0010001Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000001Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000001Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0011101S0000ddddrrrrvvvvvvvv"),
FromBitString32("cccc0001101S0000ddddvvvvvrr0mmmm"),
FromBitString32("cccc0001101S0000ddddssss0rr1mmmm"),
FromBitString32("cccc0011111S0000ddddrrrrvvvvvvvv"),
FromBitString32("cccc0001111S0000ddddvvvvvrr0mmmm"),
FromBitString32("cccc0001111S0000ddddssss0rr1mmmm"),
FromBitString32("cccc0011100Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0001100Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0001100Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010011Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000011Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000011Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010111Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000111Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000111Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010110Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000110Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000110Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0010010Snnnnddddrrrrvvvvvvvv"),
FromBitString32("cccc0000010Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000010Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc00110011nnnn0000rrrrvvvvvvvv"),
FromBitString32("cccc00010011nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc00010011nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc00110001nnnn0000rrrrvvvvvvvv"),
}};
const std::array<std::pair<u32, u32>, 16> reg_instructions = {{
FromBitString32("cccc0000101Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000100Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000000Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0001110Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc00010111nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc00010101nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc0000001Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0001101S0000ddddvvvvvrr0mmmm"),
FromBitString32("cccc0001111S0000ddddvvvvvrr0mmmm"),
FromBitString32("cccc0001100Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000011Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000111Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000110Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc0000010Snnnnddddvvvvvrr0mmmm"),
FromBitString32("cccc00010011nnnn0000vvvvvrr0mmmm"),
FromBitString32("cccc00010001nnnn0000vvvvvrr0mmmm"),
}};
const std::array<std::pair<u32, u32>, 16> rsr_instructions = {{
FromBitString32("cccc0000101Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000100Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000000Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0001110Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc00010111nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc00010101nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc0000001Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0001101S0000ddddssss0rr1mmmm"),
FromBitString32("cccc0001111S0000ddddssss0rr1mmmm"),
FromBitString32("cccc0001100Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000011Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000111Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000110Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc0000010Snnnnddddssss0rr1mmmm"),
FromBitString32("cccc00010011nnnn0000ssss0rr1mmmm"),
FromBitString32("cccc00010001nnnn0000ssss0rr1mmmm"),
}};
auto instruction_select_without_R15 = [&]() -> u32 {
size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
auto instruction_select = [&](bool Rd_can_be_r15) -> auto {
return [&, Rd_can_be_r15]() -> u32 {
size_t instruction_set = RandInt<size_t>(0, 2);
u32 cond = 0xE;
// Have a one-in-twenty-five chance of actually having a cond.
if (RandInt(1, 25) == 1) {
cond = RandInt<u32>(0x0, 0xD);
}
std::pair<u32, u32> instruction;
u32 Rn = RandInt<u32>(0, 15);
u32 Rd = RandInt<u32>(0, 14);
u32 S = RandInt<u32>(0, 1);
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
u32 cond = 0xE;
// Have a one-in-twenty-five chance of actually having a cond.
if (RandInt(1, 25) == 1) {
cond = RandInt<u32>(0x0, 0xD);
}
u32 assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
u32 S = RandInt<u32>(0, 1);
return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second));
switch (instruction_set) {
case 0: {
instruction = imm_instructions[RandInt<size_t>(0, imm_instructions.size() - 1)];
u32 Rd = RandInt<u32>(0, Rd_can_be_r15 ? 15 : 14);
if (Rd == 15) S = false;
u32 Rn = RandInt<u32>(0, 15);
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
u32 assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
return instruction.first | (assemble_randoms & ~instruction.second);
}
case 1: {
instruction = reg_instructions[RandInt<size_t>(0, reg_instructions.size() - 1)];
u32 Rd = RandInt<u32>(0, Rd_can_be_r15 ? 15 : 14);
if (Rd == 15) S = false;
u32 Rn = RandInt<u32>(0, 15);
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
u32 assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
return instruction.first | (assemble_randoms & ~instruction.second);
}
case 2: {
instruction = rsr_instructions[RandInt<size_t>(0, rsr_instructions.size() - 1)];
u32 Rd = RandInt<u32>(0, 14); // Rd can never be 15.
u32 Rn = RandInt<u32>(0, 14);
u32 Rs = RandInt<u32>(0, 14);
int rotate = RandInt<int>(0, 3);
u32 Rm = RandInt<u32>(0, 14);
u32 assemble_randoms = (Rm << 0) | (rotate << 5) | (Rs << 8) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
return instruction.first | (assemble_randoms & ~instruction.second);
}
}
UNREACHABLE();
};
};
SECTION("short blocks") {
FuzzJit(5, 6, 5000, instruction_select_without_R15);
FuzzJit(5, 6, 5000, instruction_select(/*Rd_can_be_r15=*/false));
}
SECTION("long blocks") {
FuzzJit(1024, 1025, 200, instruction_select_without_R15);
FuzzJit(1024, 1025, 200, instruction_select(/*Rd_can_be_r15=*/false));
}
auto instruction_select_only_R15 = [&]() -> u32 {
size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
u32 cond = 0xE;
// Have a one-in-twenty-five chance of actually having a cond.
if (RandInt(1, 25) == 1) {
cond = RandInt<u32>(0x0, 0xD);
}
u32 Rn = RandInt<u32>(0, 15);
u32 Rd = 15;
u32 S = 0;
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
u32 assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second));
};
SECTION("R15") {
FuzzJit(1, 1, 10000, instruction_select_only_R15);
// Temporarily disabled as interpreter fails tests.
//FuzzJit(1, 1, 10000, instruction_select(/*Rd_can_be_r15=*/true));
}
}

View file

@ -312,7 +312,8 @@ TEST_CASE("Fuzz Thumb instructions set 2 (affects PC)", "[JitX64][Thumb]") {
}
};
FuzzJitThumb(1, 1, 10000, instruction_select);
// TODO: Interpreter fails some of these tests.
//FuzzJitThumb(1, 1, 10000, instruction_select);
}
TEST_CASE("Fuzz Thumb instructions set 3 (32-bit BL/BLX)", "[JitX64][Thumb]") {