diff --git a/bootstrap/bloat-buster/bb.c b/bootstrap/bloat-buster/bb.c
index b1f6977..f8fc78b 100644
--- a/bootstrap/bloat-buster/bb.c
+++ b/bootstrap/bloat-buster/bb.c
@@ -1524,7 +1524,7 @@ u32 encode_wide(u8* restrict buffer, const EncodingBatch* const restrict batch)
     __mmask64 has_base_register = _kor_mask64(_kor_mask64(is_rm_register, is_reg_register), is_implicit_register);
 
     __m512i rex_b = _mm512_maskz_set1_epi8(_mm512_test_epi8_mask(rm_register, _mm512_set1_epi8(0b1000)), 1 << 0);
-    __m512i rex_x = _mm512_set1_epi8(0); // TODO
+    __m512i rex_x = _mm512_setzero(); // TODO
     __m512i rex_r = _mm512_maskz_set1_epi8(_mm512_test_epi8_mask(reg_register, _mm512_set1_epi8(0b1000)), 1 << 2);
     __m512i rex_w = _mm512_maskz_set1_epi8(_cvtu64_mask64(batch->rex_w), 1 << 3);
     __m512i rex_byte = _mm512_or_epi32(_mm512_set1_epi32(0x40), _mm512_or_epi32(_mm512_or_epi32(rex_b, rex_x), _mm512_or_epi32(rex_r, rex_w)));
@@ -1588,7 +1588,7 @@ u32 encode_wide(u8* restrict buffer, const EncodingBatch* const restrict batch)
     _mm512_storeu_epi8(mod_rm_positions, mod_rm_position);
 
     __mmask64 sib_mask = _kand_mask64(_mm512_cmpneq_epi8_mask(mod, _mm512_set1_epi8(0b11)), _mm512_cmpeq_epi8_mask(rm, _mm512_set1_epi8(0b100)));
-    __m512i sib_scale = _mm512_set1_epi8(0);
+    __m512i sib_scale = _mm512_setzero();
     __m512i sib_index = _mm512_maskz_set1_epi8(sib_mask, 0b100 << 3);
     __m512i sib_base = _mm512_or_epi32(_mm512_and_si512(rm_register, _mm512_maskz_set1_epi8(is_rm_register, 0b111)), _mm512_maskz_set1_epi8(_knot_mask64(is_rm_register), 0b101));
     __m512i sib = _mm512_or_epi32(_mm512_or_epi32(sib_index, sib_base), sib_scale);
@@ -4865,7 +4865,7 @@ String assemble(String text)
         __mmask64 has_base_register = _kor_mask64(_kor_mask64(is_rm_register, is_reg_register), is_implicit_register);
 
         __m512i rex_b = _mm512_maskz_set1_epi8(_mm512_test_epi8_mask(rm_register, _mm512_set1_epi8(0b1000)), 1 << 0);
-        __m512i rex_x = _mm512_set1_epi8(0); // TODO
+        __m512i rex_x = _mm512_setzero(); // TODO
         __m512i rex_r = _mm512_maskz_set1_epi8(_mm512_test_epi8_mask(reg_register, _mm512_set1_epi8(0b1000)), 1 << 2);
         __m512i rex_w = _mm512_maskz_set1_epi8(is_rex_w, 1 << 3);
         __m512i rex_byte = _mm512_or_epi32(_mm512_set1_epi32(0x40), _mm512_or_epi32(_mm512_or_epi32(rex_b, rex_x), _mm512_or_epi32(rex_r, rex_w)));
@@ -4939,7 +4939,7 @@ String assemble(String text)
         _mm512_storeu_epi8(mod_rm_positions, mod_rm_position);
 
         __mmask64 sib_mask = _kand_mask64(_mm512_cmpneq_epi8_mask(mod, _mm512_set1_epi8(0b11)), _mm512_cmpeq_epi8_mask(rm, _mm512_set1_epi8(0b100)));
-        __m512i sib_scale = _mm512_set1_epi8(0);
+        __m512i sib_scale = _mm512_setzero();
         __m512i sib_index = _mm512_maskz_set1_epi8(sib_mask, 0b100 << 3);
         __m512i sib_base = _mm512_or_epi32(_mm512_and_si512(rm_register, _mm512_maskz_set1_epi8(is_rm_register, 0b111)), _mm512_maskz_set1_epi8(_knot_mask64(is_rm_register), 0b101));
         __m512i sib = _mm512_or_epi32(_mm512_or_epi32(sib_index, sib_base), sib_scale);
diff --git a/bootstrap/bloat-buster/data/instructions.dat b/bootstrap/bloat-buster/data/instructions.dat
index cee89a1..56f8254 100644
--- a/bootstrap/bloat-buster/data/instructions.dat
+++ b/bootstrap/bloat-buster/data/instructions.dat
@@ -4,13 +4,13 @@ add: class base_arithmetic(/0, 05, 01, 03)
 adox: class unsigned_add_flag(f3)
 and: class base_arithmetic(/4, 25, 21, 23)
 bsf:
-    r16, rm16 [rm: rex.r 0f bc /r]
-    r32, rm32 [rm: 0f bc /r]
-    r64, rm64 [rm: rex.w 0f bc /r]
+    r16, rm16 [rm: \66 rex.r \0f bc /r]
+    r32, rm32 [rm: \0f bc /r]
+    r64, rm64 [rm: rex.w \0f bc /r]
 bsr:
-    r16, rm16 [rm: rex.r 0f bd /r]
-    r32, rm32 [rm: 0f bd /r]
-    r64, rm64 [rm: rex.w 0f bd /r]
+    r16, rm16 [rm: \66 rex.r \0f bd /r]
+    r32, rm32 [rm: \0f bd /r]
+    r64, rm64 [rm: rex.w \0f bd /r]
 bswap:
     r32 [o: 0f c8+r]
     r64 [o: rex.w 0f c8+r]
diff --git a/build.c b/build.c
index 94bbd62..4ce90d8 100644
--- a/build.c
+++ b/build.c
@@ -1787,6 +1787,44 @@ fn x86_64_Register define_register(RegisterSpec spec)
     return reg;
 }
 
+STRUCT(BitsetComponent)
+{
+    String name;
+    u64 bit_count;
+};
+
+STRUCT(ByteComponent)
+{
+    String type_name;
+    String field_name;
+    u8 array_length;
+    u8 type_size;
+    u8 type_alignment;
+    u8 bit_count;
+};
+
+global_variable BitsetComponent bitset_components[] = {
+    { strlit("is_rm_register"), 1 },
+    { strlit("is_reg_register"), 1 },
+    { strlit("implicit_register"), 1 },
+    { strlit("is_immediate"), 1 },
+    { strlit("immediate_size"), 2 },
+    { strlit("is_displacement"), 1 },
+    { strlit("is_relative"), 1 },
+    { strlit("displacement_size"), 1 },
+    { strlit("rex_w"), 1 },
+    { strlit("opcode_plus_register"), 1 },
+    { strlit("opcode_extension"), 3 },
+    { strlit("prefix_0f"), 1 },
+};
+
+global_variable ByteComponent byte_components[] = {
+    // TODO: opcode, length -> 1 byte
+    { .type_name = strlit("u8"), .type_size = sizeof(u8), .type_alignment = alignof(u8), .field_name = strlit("opcode"), .array_length = 2, },
+};
+
+global_variable u8 bit_offsets[array_length(bitset_components)];
+
 fn void metaprogram(Arena* arena)
 {
     let(file, file_read(arena, strlit("bootstrap/bloat-buster/data/x86_mnemonic.dat")));
@@ -1803,45 +1841,6 @@ fn void metaprogram(Arena* arena)
     vb_copy_string(&generated_h, strlit("#endif\n\n"));
 
     {
-
-        STRUCT(BitsetComponent)
-        {
-            String name;
-            u64 bit_count;
-        };
-
-        STRUCT(ByteComponent)
-        {
-            String type_name;
-            String field_name;
-            u8 array_length;
-            u8 type_size;
-            u8 type_alignment;
-            u8 bit_count;
-        };
-
-        BitsetComponent bitset_components[] = {
-            { strlit("is_rm_register"), 1 },
-            { strlit("is_reg_register"), 1 },
-            { strlit("implicit_register"), 1 },
-            { strlit("is_immediate"), 1 },
-            { strlit("immediate_size"), 2 },
-            { strlit("is_displacement"), 1 },
-            { strlit("is_relative"), 1 },
-            { strlit("displacement_size"), 1 },
-            { strlit("rex_w"), 1 },
-            { strlit("opcode_plus_register"), 1 },
-            { strlit("opcode_extension"), 3 },
-            { strlit("prefix_0f"), 1 },
-        };
-
-        ByteComponent byte_components[] = {
-            // TODO: opcode, length -> 1 byte
-            { .type_name = strlit("u8"), .type_size = sizeof(u8), .type_alignment = alignof(u8), .field_name = strlit("opcode"), .array_length = 2, },
-        };
-
-        u8 bit_offsets[array_length(bitset_components)];
-
         u64 total_bit_count = 0;
         for (u64 i = 0; i < array_length(bitset_components); i += 1)
         {
@@ -2258,6 +2257,14 @@ fn u8 expect_decimal_digit(Parser* parser)
     }
 }
 
+fn u8 ascii_couple_to_hex(u8 high_ch, u8 low_ch)
+{
+    u8 high_int = hex_ch_to_int(high_ch);
+    u8 low_int = hex_ch_to_int(low_ch);
+    u8 byte = (high_int << 4) | low_int;
+    return byte;
+}
+
 fn u8 consume_hex_byte(Parser* parser, u8* hex_byte)
 {
     u32 i = parser->i;
@@ -2272,10 +2279,7 @@ fn u8 consume_hex_byte(Parser* parser, u8* hex_byte)
     u8 result = is_hex_byte;
     if (likely(result))
     {
-        u8 high_int = hex_ch_to_int(high_ch);
-        u8 low_int = hex_ch_to_int(low_ch);
-        u8 byte = (high_int << 4) | low_int;
-        *hex_byte = byte;
+        *hex_byte = ascii_couple_to_hex(high_ch, low_ch);
     }
 
     return result;
@@ -2351,25 +2355,40 @@ fn String parse_encoding_type(Parser* parser)
     return result;
 }
 
-fn void parse_encoding_details(Parser* parser)
+fn void parse_encoding_details(Parser* parser, VirtualBuffer(u8)* buffer)
 {
     expect_character(parser, '[');
     String encoding_type = parse_encoding_type(parser);
     expect_character(parser, ':');
     expect_character(parser, ' ');
 
+    u8 plus_register = 0;
+    u8 opcode_byte = 0;
+    u8 opcode_byte_is_set = 0;
+
+    u32 atom_count = 0;
+
     while (!consume_character(parser, ']'))
     {
         // Parser encoding atom
         u8 byte;
         if (consume_hex_byte(parser, &byte))
         {
+            assert(!opcode_byte_is_set);
+            opcode_byte = byte;
+            opcode_byte_is_set = 1;
+
             u8 ch = get_ch(parser);
-            u8 is_plus = ch == '+';
-            parser->i += is_plus;
-            if (unlikely(is_plus))
+            switch (ch)
             {
-                expect_character(parser, 'r');
+                case '+':
+                    {
+                        parser->i += 1;
+                        expect_character(parser, 'r');
+                        plus_register = 1;
+                    } break;
+                default:
+                    break;
             }
         }
         else
@@ -2388,6 +2407,25 @@ fn void parse_encoding_details(Parser* parser)
                         os_exit(1);
                     }
                 }
+                else if (string_starts_with(identifier, strlit("lp")))
+                {
+                    assert(identifier.length == 6);
+                    assert(identifier.pointer[2] == '(');
+                    assert(identifier.pointer[5] == ')');
+                    u8 high_ch = identifier.pointer[3];
+                    u8 low_ch = identifier.pointer[4];
+                    u8 legacy_prefix = ascii_couple_to_hex(high_ch, low_ch);
+
+                    switch (legacy_prefix)
+                    {
+                    }
+
+                    todo();
+                }
+                else if (identifier.pointer[0] == 'p')
+                {
+                    todo();
+                }
                 else if (s_equal(identifier, strlit("rex")))
                 {
                     expect_character(parser, '.');
@@ -2432,10 +2470,14 @@ fn void parse_encoding_details(Parser* parser)
         }
 
         consume_character(parser, ' ');
+
+        atom_count += 1;
     }
+
+    // TODO: serialize
 }
 
-fn void parse_encoding(Parser* parser)
+fn void parse_encoding(Parser* parser, VirtualBuffer(u8)* buffer)
 {
     u8 first_ch = get_ch(parser);
     u32 start = parser->i;
@@ -2459,7 +2501,7 @@ fn void parse_encoding(Parser* parser)
         expect_character(parser, ' ');
     }
 
-    parse_encoding_details(parser);
+    parse_encoding_details(parser, buffer);
 }
 
 fn void parse_instruction_table(Arena* arena)
@@ -2474,18 +2516,31 @@ fn void parse_instruction_table(Arena* arena)
     VirtualBuffer(u8) file_memory = {};
     VirtualBuffer(u8)* f = &file_memory;
 
+    VirtualBuffer(u8) isel_table = {};
+    VirtualBuffer(u8) encoding_table = {};
+
+    u16 mnemonic_count = 0;
+    u32 total_encoding_count = 0;
     let_cast(u32, file_length, file.length);
+
     while (parser->i < file_length)
     {
         String mnemonic = parse_mnemonic(parser);
+        u16 mnemonic_index = mnemonic_count;
+
+        u32 encoding_offset = total_encoding_count;
+        u16 encoding_count = 0;
+
+        mnemonic_count += 1;
         expect_character(parser, ':');
 
         if (consume_character(parser, '\n'))
         {
             while (consume_tab(parser))
             {
-                parse_encoding(parser);
+                parse_encoding(parser, &encoding_table);
                 expect_character(parser, '\n');
+                encoding_count += 1;
             }
         }
         else if (consume_character(parser, ' '))
@@ -2495,7 +2550,8 @@ fn void parse_instruction_table(Arena* arena)
             {
                 case '[':
                     {
-                        parse_encoding_details(parser);
+                        parse_encoding_details(parser, &encoding_table);
+                        encoding_count += 1;
                     } break;
                 default:
                     {
@@ -2616,7 +2672,7 @@ fn void parse_instruction_table(Arena* arena)
                         else
                         {
                             parser->i -= identifier.length;
-                            parse_encoding(parser);
+                            parse_encoding(parser, &encoding_table);
                         }
                     } break;
             }
@@ -2627,6 +2683,8 @@ fn void parse_instruction_table(Arena* arena)
         {
             todo();
         }
+
+        total_encoding_count += encoding_count;
     }
 }