-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FEXCore/JIT: Encode the JITRIPReconstructionEntries using variable le…
…ngth integer When #2722 implemented this initially and #4271 switched over to signed int16_t there was assumptions made that int16_t was a reasonable trade-off in encoding size versus needing to deal with 8-bit values being too small in some cases. In the common case we are almost always encoding 8-bit values because instructions are typically linear (and less than 15-bytes in size), but 16-bit was chosen because optimizing JIT and multiple instructions that don't cause exceptions can add up to larger than 8-bit. Instead of hardcoding 16-bit values, implement a variable length integer class where ~96.8% of values are 8-bit encoded, and the remaining 3.19% are encoded using 16-bit. Due to some constraints that #4271 put in place, we can basically guarantee currently that branch targets are within 16-bit. The VL class does support 32-bit and 64-bit as well so if we change behaviour then nothing needs to change. Some stats when running Sonic Mania with multiblock enabled. Encoded integers: 3,504,907 Encoded 8-bit: 3,393,095 (96.8%) Encoded 16-bit: 111,812 (3.19%) Encoded 32/64-bit: 0 Encoded Size: 3,615,181 bytes (3.44MiB) Fixed encoded size: 7,007,604 bytes (6.68MiB) Definitely worth using and saves the headache of large RIP/PC offsets causing problems.
- Loading branch information
1 parent
8d6a43d
commit 0fa2f9c
Showing
6 changed files
with
315 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// SPDX-License-Identifier: MIT | ||
#pragma once | ||
|
||
#include <FEXCore/Utils/CompilerDefs.h> | ||
|
||
#include <cstdio> | ||
#include <cstdint> | ||
#include <cstddef> | ||
#include <limits> | ||
|
||
namespace FEXCore::Utils { | ||
// Variable length signed integer | ||
// The most common encoded size is 8-bit positive, but other values can occur | ||
// | ||
// 8-bit: | ||
// bit[7] = 0 - 8-bit | ||
// bit[6:0] = 7-bit encoding | ||
// | ||
// 16-bit: | ||
// byte1[7:6] = 0b10 - 16-bit | ||
// byte1[5:0] = top 6-bits | ||
// byte2[7:0] = Bottom 8-bits bits | ||
// | ||
// 32-bit | ||
// byte1[7:5] = 0b110 - 32-bit | ||
// byte1[4:0] = <reserved> | ||
// word[31:0] = signed word | ||
// | ||
// 64-bit | ||
// byte1[7:5] = 0b111 - 64-bit | ||
// byte1[4:0] = <reserved> | ||
// dword[63:0] = signed dword | ||
struct vl64 final { | ||
static size_t EncodedSize(int64_t Data) { | ||
if (Data >= vl8_min && Data <= vl8_max) { | ||
return sizeof(vl8_enc); | ||
} else if (Data >= vl16_min && Data <= vl16_max) { | ||
return sizeof(vl16_enc); | ||
} else if (Data >= vl32_min && Data <= vl32_max) { | ||
return sizeof(vl32_enc); | ||
} | ||
return sizeof(vl64_enc); | ||
} | ||
|
||
struct Decoded { | ||
int64_t Integer; | ||
size_t Size; | ||
}; | ||
|
||
static Decoded Decode(const uint8_t* data) { | ||
auto vl8_type = reinterpret_cast<const vl8_enc*>(data); | ||
auto vl16_type = reinterpret_cast<const vl16_enc*>(data); | ||
auto vl32_type = reinterpret_cast<const vl32_enc*>(data); | ||
auto vl64_type = reinterpret_cast<const vl64_enc*>(data); | ||
|
||
if (vl8_type->Type == vl8_type_header) { | ||
return {vl8_type->Integer, sizeof(vl8_enc)}; | ||
} else if (vl16_type->Type == vl16_type_header) { | ||
return {vl16_type->Integer, sizeof(vl16_enc)}; | ||
} else if (vl32_type->Type == vl32_type_header) { | ||
return {vl32_type->Integer, sizeof(vl32_enc)}; | ||
} | ||
return {vl64_type->Integer, sizeof(vl64_enc)}; | ||
} | ||
|
||
static size_t Encode(uint8_t* dst, int64_t Data) { | ||
auto vl8_type = reinterpret_cast<vl8_enc*>(dst); | ||
auto vl16_type = reinterpret_cast<vl16_enc*>(dst); | ||
auto vl32_type = reinterpret_cast<vl32_enc*>(dst); | ||
auto vl64_type = reinterpret_cast<vl64_enc*>(dst); | ||
|
||
if (Data >= vl8_min && Data <= vl8_max) { | ||
*vl8_type = { | ||
.Integer = static_cast<int8_t>(Data), | ||
.Type = vl8_type_header, | ||
}; | ||
return sizeof(vl8_enc); | ||
} else if (Data >= vl16_min && Data <= vl16_max) { | ||
*vl16_type = { | ||
.Integer = static_cast<int16_t>(Data), | ||
.Type = vl16_type_header, | ||
}; | ||
return sizeof(vl16_enc); | ||
} else if (Data >= vl32_min && Data <= vl32_max) { | ||
*vl32_type = { | ||
.Type = vl32_type_header, | ||
.Integer = static_cast<int32_t>(Data), | ||
}; | ||
return sizeof(vl32_enc); | ||
} | ||
|
||
*vl64_type = { | ||
.Type = vl64_type_header, | ||
.Integer = Data, | ||
}; | ||
return sizeof(vl64_enc); | ||
} | ||
|
||
private: | ||
|
||
struct vl8_enc { | ||
int8_t Integer : 7; | ||
uint8_t Type : 1; | ||
}; | ||
static_assert(sizeof(vl8_enc) == 1); | ||
|
||
struct vl16_enc { | ||
int16_t Integer : 14; | ||
uint16_t Type : 2; | ||
}; | ||
static_assert(sizeof(vl16_enc) == 2); | ||
|
||
struct FEX_PACKED vl32_enc { | ||
uint8_t Type; | ||
int32_t Integer; | ||
}; | ||
static_assert(sizeof(vl32_enc) == 5); | ||
|
||
struct FEX_PACKED vl64_enc { | ||
uint8_t Type; | ||
int64_t Integer; | ||
}; | ||
static_assert(sizeof(vl64_enc) == 9); | ||
|
||
// Maximum ranges for encodings. | ||
|
||
// vl8 can hold a signed 7-bit integer. | ||
// Encoded in one 8-bit value. | ||
constexpr static int64_t vl8_encoded_bits = 7; | ||
constexpr static int64_t vl8_type_header = 0; | ||
constexpr static int64_t vl8_min = std::numeric_limits<int64_t>::min() >> ((sizeof(int64_t) * 8) - vl8_encoded_bits); | ||
constexpr static int64_t vl8_max = std::numeric_limits<int64_t>::max() >> ((sizeof(int64_t) * 8) - vl8_encoded_bits); | ||
|
||
// vl16 can hold a signed 14-bit integer. | ||
// Encoded in one 16-bit value. | ||
constexpr static int64_t vl16_encoded_bits = 14; | ||
constexpr static int64_t vl16_type_header = 0b10; | ||
constexpr static int64_t vl16_min = std::numeric_limits<int64_t>::min() >> ((sizeof(int64_t) * 8) - vl16_encoded_bits); | ||
constexpr static int64_t vl16_max = std::numeric_limits<int64_t>::max() >> ((sizeof(int64_t) * 8) - vl16_encoded_bits); | ||
|
||
// vl32 can hold a signed 32-bit integer. | ||
// Encoded in 8-bit and 32-bit value; | ||
constexpr static int64_t vl32_encoded_bits = 32; | ||
constexpr static int64_t vl32_type_header = 0b1100'0000; | ||
constexpr static int64_t vl32_min = std::numeric_limits<int32_t>::min(); | ||
constexpr static int64_t vl32_max = std::numeric_limits<int32_t>::max(); | ||
|
||
// vl64 can hold a signed 32-bit integer. | ||
// Encoded in 8-bit and 64-bit value. | ||
constexpr static int64_t vl64_encoded_bits = 64; | ||
constexpr static int64_t vl64_type_header = 0b1110'0000; | ||
constexpr static int64_t vl64_min = std::numeric_limits<int64_t>::min(); | ||
constexpr static int64_t vl64_max = std::numeric_limits<int64_t>::max(); | ||
}; | ||
|
||
} // namespace FEXCore::Utils |
Oops, something went wrong.