Skip to content

Commit 5e93bb9

Browse files
committed
temporary commit
1 parent 80832fc commit 5e93bb9

File tree

2 files changed

+78
-49
lines changed

2 files changed

+78
-49
lines changed

src/jit/decoder/arm32.cpp

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,7 @@ namespace pound::jit::decoder
1010
/* Increase value as more instructions get implemented */
1111
#define INSTRUCTION_ARRAY_CAPACITY 4
1212

13-
typedef struct
14-
{
15-
uint16_t* hash_table;
16-
uint8_t* collision_map;
17-
uint16_t hash_shift;
18-
uint16_t hash_mask;
19-
uint16_t table_size;
20-
} arm32_perfect_hash_t;
13+
#define HASH_TABLE_INVALID_INDEX 0xFFFF
2114

2215
/*
2316
* ============================================================================
@@ -30,6 +23,7 @@ void arm32_SUB_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruc
3023

3124
void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expected);
3225
void arm32_grow_instructions_array(arm32_decoder_t* decoder, size_t new_capacity);
26+
uint32_t arm32_generate_hash_seed(uint32_t mask, uint32_t expected);
3327

3428
/*
3529
* ============================================================================
@@ -47,7 +41,7 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder
4741
/* Setup Instructions array.*/
4842
size_t instructions_array_size = INSTRUCTION_ARRAY_CAPACITY * sizeof(arm32_instruction_info_t);
4943
PVM_ASSERT(instructions_array_size <= decoder->allocator.capacity);
50-
LOG_TRACE("Growing instructions array to %d bytes", instructions_array_size);
44+
LOG_TRACE("Allocated %d bytes to instructions array", instructions_array_size);
5145

5246
void* new_ptr = pound::host::memory::arena_allocate(&decoder->allocator, instructions_array_size);
5347
PVM_ASSERT(nullptr != new_ptr);
@@ -73,7 +67,7 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder
7367
size_t slots_used_size = table_size * sizeof(bool);
7468
bool* slots_used = (bool*)pound::host::memory::arena_allocate(&decoder->allocator, slots_used_size);
7569
PVM_ASSERT(nullptr != slots_used);
76-
LOG_TRACE("Growing hash slots used array to %d bytes", slots_used_size);
70+
LOG_TRACE("Allocated %d bytes to hash slots used array", slots_used_size);
7771

7872
uint16_t shift = 0;
7973
bool perfect_hash_generated = false;
@@ -85,33 +79,8 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder
8579
uint16_t hash;
8680
for (size_t i = 0; i < decoder->instruction_count; ++i)
8781
{
88-
/*
89-
* XOR combines the mask (which bits matter) and expected value (what those btis should be)
90-
* into a single 32-bit value that uniquely represents this instruction pattern.
91-
* Example: ADD instruction might have mask=0x0FF00000, expected=0x00200000
92-
* value = 0x0FF00000 ^ 0x00200000 = 0x0FD00000;
93-
*/
94-
uint32_t value = decoder->instructions[i].mask ^ decoder->instructions[i].expected;
95-
96-
/*
97-
* First bit mixing round - break up patterns in the value.
98-
* We need to eliminate patterns (like trailing zeroes) that cause collisions.
99-
* We do this by mixing the high bits (16-31) with the low bits (0-15).
100-
*
101-
* We then multiply a magic number to further scrambles the bits to ensure good distribution.
102-
*/
103-
value = ((value >> 16) ^ value) * 0x45d9f3b;
104-
105-
/*
106-
* Second bit mixing round to ensire thorough mixing
107-
*/
108-
value = ((value >> 16) ^ value) * 0x45d9f3b;
109-
110-
/*
111-
* Final mixing. The result is our hash seed - a 32-bit number that uniquely represents this instruction.
112-
*/
113-
value = (value >> 16) ^ value;
114-
uint32_t hash_seed = value;
82+
uint32_t hash_seed =
83+
arm32_generate_hash_seed(decoder->instructions[i].mask, decoder->instructions[i].expected);
11584

11685
/*
11786
* Now we need to convert the 32-bit hash seed into an index within our hash table.
@@ -121,12 +90,14 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder
12190
hash = ((hash_seed >> shift) & mask);
12291
if (true == slots_used[hash])
12392
{
124-
LOG_TRACE("Instruction %s: Collision detected at slot %u for shift %u", decoder->instructions[i].name, hash, shift);
93+
LOG_TRACE("Instruction %s: Collision detected at slot %u for shift %u", decoder->instructions[i].name,
94+
hash, shift);
12595
collision_free = false;
12696
break;
12797
}
12898
slots_used[hash] = true;
129-
LOG_TRACE("Instruction %s: Collision-free hash %u found for shift %u", decoder->instructions[i].name, hash, shift);
99+
LOG_TRACE("Instruction %s: Collision-free hash %u found for shift %u", decoder->instructions[i].name, hash,
100+
shift);
130101
}
131102
if (true == collision_free)
132103
{
@@ -138,7 +109,33 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder
138109
PVM_ASSERT_MSG(true == perfect_hash_generated, "Failed to generate perfect hash - no collision-free hash found");
139110
LOG_TRACE("Perfect hash parameters: shift=%u, mask=0x%04x, table_size=%u", shift, mask, table_size);
140111

141-
/* TODO(GloriousTacoo:jit): Generate hash table. */
112+
size_t hash_table_size = table_size * sizeof(uint16_t);
113+
uint16_t* hash_table = (uint16_t*)pound::host::memory::arena_allocate(&decoder->allocator, hash_table_size);
114+
PVM_ASSERT(nullptr != hash_table);
115+
LOG_TRACE("Allocated %zu bytes to hash table", hash_table_size);
116+
117+
/* Initialize hash table with invalid indices */
118+
for (size_t i = 0; i < table_size; ++i)
119+
{
120+
hash_table[i] = HASH_TABLE_INVALID_INDEX;
121+
}
122+
123+
for (size_t i = 0; i < decoder->instruction_count; ++i)
124+
{
125+
uint32_t hash_seed = arm32_generate_hash_seed(decoder->instructions[i].mask, decoder->instructions[i].expected);
126+
uint32_t hash = (hash_seed >> shift) & mask;
127+
PVM_ASSERT_MSG(HASH_TABLE_INVALID_INDEX == hash_table[hash], "Hash collision detected");
128+
129+
PVM_ASSERT(i < 0xFFFF);
130+
hash_table[hash] = (uint16_t)i;
131+
132+
LOG_TRACE("Instruction '%s' hashed to slot %u", decoder->instructions[i].name, hash);
133+
}
134+
135+
decoder->perfect_hash.hash_shift = shift;
136+
decoder->perfect_hash.hash_mask = mask;
137+
decoder->perfect_hash.table_size = table_size;
138+
decoder->perfect_hash.hash_table = hash_table;
142139
}
143140

144141
/*
@@ -166,16 +163,9 @@ void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, const cha
166163
info->handler = handler;
167164

168165
/* Calculate priority based on number of fixed bits. */
169-
info->priority = 0;
170-
for (int i = 0; i < 32; ++i)
171-
{
172-
if ((mask >> i) & 1)
173-
{
174-
++info->priority;
175-
}
176-
}
177-
166+
info->priority = (uint8_t)__builtin_popcount(mask);
178167
++decoder->instruction_count;
168+
179169
LOG_TRACE("Instruction Registered: %s", info->name);
180170
LOG_TRACE("Mask: 0x%08X", info->mask);
181171
LOG_TRACE("Expected: 0x%08X", info->expected);
@@ -220,4 +210,34 @@ void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expe
220210
}
221211
}
222212
}
213+
uint32_t arm32_generate_hash_seed(uint32_t mask, uint32_t expected)
214+
{
215+
/*
216+
* XOR combines the mask (which bits matter) and expected value (what those btis should be)
217+
* into a single 32-bit value that uniquely represents this instruction pattern.
218+
* Example: ADD instruction might have mask=0x0FF00000, expected=0x00200000
219+
* value = 0x0FF00000 ^ 0x00200000 = 0x0FD00000;
220+
*/
221+
uint32_t value = mask ^ expected;
222+
223+
/*
224+
* First bit mixing round - break up patterns in the value.
225+
* We need to eliminate patterns (like trailing zeroes) that cause collisions.
226+
* We do this by mixing the high bits (16-31) with the low bits (0-15).
227+
*
228+
* We then multiply a magic number to further scrambles the bits to ensure good distribution.
229+
*/
230+
value = ((value >> 16) ^ value) * 0x45d9f3b;
231+
232+
/*
233+
* Second bit mixing round to ensire thorough mixing
234+
*/
235+
value = ((value >> 16) ^ value) * 0x45d9f3b;
236+
237+
/*
238+
* Final mixing. The result is our hash seed - a 32-bit number that uniquely represents this instruction.
239+
*/
240+
value = (value >> 16) ^ value;
241+
return value;
242+
}
223243
} // namespace pound::jit::decoder

src/jit/decoder/arm32.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ typedef uint32_t arm32_instruction_t;
1313
typedef struct arm32_decoder arm32_decoder_t;
1414
typedef void (*arm32_handler_fn)(arm32_decoder_t* decoder, arm32_instruction_t instruction);
1515

16+
typedef struct
17+
{
18+
uint16_t* hash_table;
19+
uint16_t hash_shift;
20+
uint16_t hash_mask;
21+
uint16_t table_size;
22+
} arm32_perfect_hash_t;
23+
1624
typedef struct
1725
{
1826
const char* name;
@@ -27,6 +35,7 @@ typedef struct
2735

2836
struct arm32_decoder
2937
{
38+
arm32_perfect_hash_t perfect_hash;
3039
pound::host::memory::arena_t allocator;
3140
arm32_instruction_info_t* instructions;
3241
size_t instruction_count;

0 commit comments

Comments
 (0)