fixup! BitUtil: Correct error messages, independent impl of Bit, correct SignExtend logic

This commit is contained in:
MerryMage 2016-04-07 08:41:46 +01:00
parent 9abe861152
commit 208795b885
3 changed files with 29 additions and 25 deletions

View File

@ -13,29 +13,31 @@ constexpr size_t BitSize() {
return sizeof(T) * CHAR_BIT; return sizeof(T) * CHAR_BIT;
} }
/// Extract bits [begin_bit, end_bit] inclusive from val of type T. /// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<size_t begin_bit, size_t end_bit, typename T> template<size_t begin_bit, size_t end_bit, typename T>
constexpr T Bits(const T value) { constexpr T Bits(const T value) {
static_assert(begin_bit <= end_bit, "bit range must begin before it ends"); static_assert(begin_bit < end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
static_assert(begin_bit < BitSize<T>(), "begin_bit must be smaller than size of T"); static_assert(begin_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
static_assert(end_bit < BitSize<T>(), "begin_bit must be smaller than size of T"); static_assert(end_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
return (value >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1); return (value >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1);
} }
/// Extracts a single bit at bit_position from val of type T. /// Extracts a single bit at bit_position from value of type T.
template<size_t bit_position, typename T> template<size_t bit_position, typename T>
constexpr T Bit(const T value) { constexpr T Bit(const T value) {
return Bits<bit_position, bit_position, T>(value); static_assert(bit_position < BitSize<T>(), "bit_position must be smaller than size of T");
return (value >> bit_position) & 1;
} }
/// Sign-extends a val that has NBits bits to the full bitwidth of type T. /// Sign-extends a value that has NBits bits to the full bitwidth of type T.
template<size_t NBits, typename T> template<size_t NBits, typename T>
inline T SignExtend(const T value) { inline T SignExtend(const T value) {
static_assert(NBits <= BitSize<T>(), "NBits larger that bitsize of T"); static_assert(NBits <= BitSize<T>(), "NBits larger than bitsize of T");
constexpr T mask = static_cast<T>(1ULL << NBits) - 1; constexpr T mask = static_cast<T>(1ULL << NBits) - 1;
const T signbit = (value >> NBits) & 1; const T signbit = Bit<NBits - 1>(value);
if (signbit != 0) { if (signbit != 0) {
return value | ~mask; return value | ~mask;
} }

View File

@ -43,6 +43,7 @@ ThumbMatcher MakeMatcher(const char* const str, std::function<void(Visitor* v, u
return { mask, expect, fn }; return { mask, expect, fn };
} }
using BitUtil::Bit;
using BitUtil::Bits; using BitUtil::Bits;
static const std::array<ThumbInstruction, 27> thumb_instruction_table = { { static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
@ -66,7 +67,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "ADD/SUB_reg", MakeMatcher("000110oxxxxxxxxx", [](Visitor* v, u16 instruction) { { "ADD/SUB_reg", MakeMatcher("000110oxxxxxxxxx", [](Visitor* v, u16 instruction) {
u32 opcode = Bits<9, 9>(instruction); u32 opcode = Bit<9>(instruction);
Register Rm = static_cast<Register>(Bits<6, 8>(instruction)); Register Rm = static_cast<Register>(Bits<6, 8>(instruction));
Register Rn = static_cast<Register>(Bits<3, 5>(instruction)); Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
Register Rd = static_cast<Register>(Bits<0, 2>(instruction)); Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
@ -82,7 +83,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "ADD/SUB_imm", MakeMatcher("000111oxxxxxxxxx", [](Visitor* v, u16 instruction) { { "ADD/SUB_imm", MakeMatcher("000111oxxxxxxxxx", [](Visitor* v, u16 instruction) {
u32 opcode = Bits<9, 9>(instruction); u32 opcode = Bit<9>(instruction);
u32 imm3 = Bits<6, 8>(instruction); u32 imm3 = Bits<6, 8>(instruction);
Register Rn = static_cast<Register>(Bits<3, 5>(instruction)); Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
Register Rd = static_cast<Register>(Bits<0, 2>(instruction)); Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
@ -178,7 +179,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
{ "special data processing", MakeMatcher("010001ooxxxxxxxx", [](Visitor* v, u16 instruction) { { "special data processing", MakeMatcher("010001ooxxxxxxxx", [](Visitor* v, u16 instruction) {
u32 opcode = Bits<8, 9>(instruction); u32 opcode = Bits<8, 9>(instruction);
Register Rm = static_cast<Register>(Bits<3, 6>(instruction)); Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
Register Rd = static_cast<Register>(Bits<0, 2>(instruction) | (Bits<7, 7>(instruction) << 3)); Register Rd = static_cast<Register>(Bits<0, 2>(instruction) | (Bit<7>(instruction) << 3));
switch (opcode) { switch (opcode) {
case 0: // ADD Rd, Rm case 0: // ADD Rd, Rm
v->ADD_reg(Cond::AL, /*S=*/false, Rd, Rd, 0, ShiftType::LSL, Rm); v->ADD_reg(Cond::AL, /*S=*/false, Rd, Rd, 0, ShiftType::LSL, Rm);
@ -194,7 +195,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "BLX/BX", MakeMatcher("01000111xxxxx000", [](Visitor* v, u16 instruction) { { "BLX/BX", MakeMatcher("01000111xxxxx000", [](Visitor* v, u16 instruction) {
bool L = Bits<7, 7>(instruction); bool L = Bit<7>(instruction);
Register Rm = static_cast<Register>(Bits<3, 6>(instruction)); Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
if (!L) { // BX Rm if (!L) { // BX Rm
v->BX(Cond::AL, Rm); v->BX(Cond::AL, Rm);
@ -265,7 +266,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "STRH/LDRH_imm", MakeMatcher("1000xxxxxxxxxxxx", [](Visitor* v, u16 instruction) { { "STRH/LDRH_imm", MakeMatcher("1000xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
bool L = Bits<11, 11>(instruction); bool L = Bit<11>(instruction);
u32 offset = Bits<6, 10>(instruction); u32 offset = Bits<6, 10>(instruction);
Register Rn = static_cast<Register>(Bits<3, 5>(instruction)); Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
Register Rd = static_cast<Register>(Bits<0, 2>(instruction)); Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
@ -276,7 +277,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "load/store stack", MakeMatcher("1001xxxxxxxxxxxx", [](Visitor* v, u16 instruction) { { "load/store stack", MakeMatcher("1001xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
bool L = Bits<11, 11>(instruction); bool L = Bit<11>(instruction);
Register Rd = static_cast<Register>(Bits<8, 10>(instruction)); Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
u32 offset = Bits<0, 7>(instruction); u32 offset = Bits<0, 7>(instruction);
if (!L) { // STR Rd, [SP, #offset] if (!L) { // STR Rd, [SP, #offset]
@ -287,14 +288,14 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
})}, })},
{ "add to sp/pc", MakeMatcher("1010oxxxxxxxxxxx", [](Visitor* v, u16 instruction) { { "add to sp/pc", MakeMatcher("1010oxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
// ADD Rd, PC/SP, #imm8 // ADD Rd, PC/SP, #imm8
Register Rn = Bits<11, 11>(instruction) ? Register::SP : Register::PC; Register Rn = Bit<11>(instruction) ? Register::SP : Register::PC;
Register Rd = static_cast<Register>(Bits<8, 10>(instruction)); Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
u32 imm8 = Bits<0, 7>(instruction); u32 imm8 = Bits<0, 7>(instruction);
v->ADD_imm(Cond::AL, /*S=*/false, Rn, Rd, 0xF, imm8); v->ADD_imm(Cond::AL, /*S=*/false, Rn, Rd, 0xF, imm8);
})}, })},
{ "adjust stack ptr", MakeMatcher("10110000oxxxxxxx", [](Visitor* v, u16 instruction) { { "adjust stack ptr", MakeMatcher("10110000oxxxxxxx", [](Visitor* v, u16 instruction) {
// SUB SP, SP, #<imm7*4> // SUB SP, SP, #<imm7*4>
u32 opc = Bits<7, 7>(instruction); u32 opc = Bit<7>(instruction);
u32 imm7 = Bits<0, 6>(instruction); u32 imm7 = Bits<0, 6>(instruction);
switch (opc) { switch (opc) {
case 0: case 0:
@ -329,8 +330,8 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "PUSH/POP_reglist", MakeMatcher("1011x10xxxxxxxxx", [](Visitor* v, u16 instruction) { { "PUSH/POP_reglist", MakeMatcher("1011x10xxxxxxxxx", [](Visitor* v, u16 instruction) {
bool L = Bits<11, 11>(instruction); bool L = Bit<11>(instruction);
u32 R = Bits<8, 8>(instruction); u32 R = Bit<8>(instruction);
u32 reglist = Bits<0, 7>(instruction); u32 reglist = Bits<0, 7>(instruction);
if (!L) { // PUSH {reglist, <R>=LR} if (!L) { // PUSH {reglist, <R>=LR}
reglist |= R << 14; reglist |= R << 14;
@ -343,14 +344,14 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
} }
})}, })},
{ "SETEND", MakeMatcher("101101100101x000", [](Visitor* v, u16 instruction) { { "SETEND", MakeMatcher("101101100101x000", [](Visitor* v, u16 instruction) {
bool E = Bits<3, 3>(instruction); u16 E = Bit<3>(instruction);
v->SETEND(E); v->SETEND(E);
})}, })},
{ "change processor state", MakeMatcher("10110110011x0xxx", [](Visitor* v, u16 instruction) { { "change processor state", MakeMatcher("10110110011x0xxx", [](Visitor* v, u16 instruction) {
bool imod = Bits<4, 4>(instruction); u16 imod = Bit<4>(instruction);
bool A = Bits<2, 2>(instruction); u16 A = Bit<2>(instruction);
bool I = Bits<1, 1>(instruction); u16 I = Bit<1>(instruction);
bool F = Bits<0, 0>(instruction); u16 F = Bit<0>(instruction);
v->CPS(); v->CPS();
})}, })},
{ "reverse bytes", MakeMatcher("10111010ooxxxxxx", [](Visitor* v, u16 instruction) { { "reverse bytes", MakeMatcher("10111010ooxxxxxx", [](Visitor* v, u16 instruction) {
@ -380,7 +381,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
v->BKPT(Cond::AL, imm8 >> 4, imm8 & 0xF); v->BKPT(Cond::AL, imm8 >> 4, imm8 & 0xF);
})}, })},
{ "STMIA/LDMIA", MakeMatcher("1100xxxxxxxxxxxx", [](Visitor* v, u16 instruction) { { "STMIA/LDMIA", MakeMatcher("1100xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
bool L = Bits<11, 11>(instruction); bool L = Bit<11>(instruction);
Register Rn = static_cast<Register>(Bits<8, 10>(instruction)); Register Rn = static_cast<Register>(Bits<8, 10>(instruction));
u32 reglist = Bits<0, 7>(instruction); u32 reglist = Bits<0, 7>(instruction);
if (!L) { // STMIA Rn!, { reglist } if (!L) { // STMIA Rn!, { reglist }

View File

@ -24,10 +24,11 @@ TEST_CASE("Fuzz ARM branch instructions", "[JitX64]") {
auto instruction_select = [&]() -> u32 { auto instruction_select = [&]() -> u32 {
size_t inst_index = RandInt<size_t>(0, instructions.size() - 1); size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
u32 random = RandInt<u32>(0, 0xFFFFFFF); u32 cond = RandInt<u32>(0, 0xE);
u32 random = RandInt<u32>(0, 0xFFFFFF);
u32 Rm = RandInt<u32>(0, 14); u32 Rm = RandInt<u32>(0, 14);
u32 assemble_randoms = (random << 4) | Rm; u32 assemble_randoms = (cond << 28) | (random << 4) | Rm;
return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second)); return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second));
}; };