Affix
view release on metacpan or search on metacpan
infix/src/arch/x64/abi_x64_emitters.c view on Meta::CPAN
mod = 0x00;
emit_modrm(buf, mod >> 6, src % 8, dest_base % 8);
if (dest_base % 8 == RSP_REG)
emit_byte(buf, 0x24);
if (mod == 0x40)
emit_byte(buf, (uint8_t)offset);
else if (mod == 0x80)
emit_int32(buf, offset);
}
/**
* @internal
* @brief Emits a VEX prefix for an AVX instruction.
* @details This helper centralizes the logic of choosing between 2-byte (C5) and 3-byte (C4) VEX encodings.
*/
INFIX_INTERNAL void emit_vex_prefix(
code_buffer * buf, bool r, bool x, bool b, uint8_t m, bool w, uint8_t v, bool l, uint8_t p) {
// VEX encoding inverts R, X, B bits.
// The 2-byte VEX prefix cannot encode the L bit for 256-bit operations.
// The condition must ensure we only use it for 128-bit operations (l=0).
if (!b && !x && m == 1 && w == 0 && !l) {
// Use 2-byte VEX prefix (C5) when possible.
emit_byte(buf, 0xC5);
uint8_t byte2 = ((!r) << 7) | ((~v & 0xF) << 3) | ((l & 1) << 2) | (p & 3);
emit_byte(buf, byte2);
}
else {
// Fall back to 3-byte VEX prefix (C4).
emit_byte(buf, 0xC4);
uint8_t byte2 = ((!r) << 7) | ((!x) << 6) | ((!b) << 5) | (m & 0x1F);
emit_byte(buf, byte2);
uint8_t byte3 = ((w & 1) << 7) | ((~v & 0xF) << 3) | ((l & 1) << 2) | (p & 3);
emit_byte(buf, byte3);
}
}
/**
* @internal
* @brief Emits a 4-byte EVEX prefix for an AVX-512 instruction, following the Intel SDM.
*/
INFIX_INTERNAL void emit_evex_prefix(code_buffer * buf,
uint8_t map, // 1 for 0F, 2 for 0F38, 3 for 0F3A
uint8_t pp, // 00=none, 01=66, 10=F3, 11=F2
bool W,
bool R,
bool X,
bool B,
bool R_prime, // Register bits
uint8_t vvvv, // Source register (inverted)
bool L,
bool L_prime,
bool z,
bool b,
uint8_t aaa) // Masking/control bits
{
emit_byte(buf, 0x62);
// Byte 2: P0 - R, X, B, R' bits are inverted. 0 means 1, 1 means 0.
uint8_t p0 = 0;
p0 |= (R ? 0 : 1) << 7; // Inverted R bit
p0 |= (X ? 0 : 1) << 6; // Inverted X bit
p0 |= (B ? 0 : 1) << 5; // Inverted B bit
p0 |= (R_prime ? 0 : 1) << 4; // Inverted R' bit
p0 |= (map & 0x0F); // Low 4 bits select the opcode map (0F, 0F38, 0F3A)
emit_byte(buf, p0);
// Byte 3: P1
uint8_t p1 = 0;
p1 |= (pp & 0b11);
p1 |= (1 << 2); // ' (marks EVEX), must be 1
p1 |= ((~vvvv & 0xF) << 3); // vvvv field is inverted
p1 |= W ? (1 << 7) : 0;
emit_byte(buf, p1);
// Byte 4: P2
uint8_t p2 = 0;
p2 |= (aaa & 0b111);
p2 |= b ? (1 << 4) : 0;
p2 |= L_prime ? (1 << 6) : 0;
p2 |= L ? (1 << 5) : 0;
p2 |= z ? (1 << 7) : 0;
// V' bit is the high bit of the 5-bit vvvv register specifier and is NOT inverted.
p2 |= (((vvvv >> 4) & 1) << 3);
emit_byte(buf, p2);
}
/**
* @internal
* @brief Emits `vmovupd ymm, [base + offset]` to load a 256-bit unaligned value (AVX).
* @details Instruction format: VEX.256.66.0F.WIG 10 /r
*/
INFIX_INTERNAL void emit_vmovupd_ymm_mem(code_buffer * buf, x64_xmm dest, x64_gpr src_base, int32_t offset) {
// VEX prefix fields for vmovupd ymm, m256:
// L=1 (256-bit), p=1 (from 66 prefix), m-mmmm=01 (from 0F map).
// The vvvv field is not used for a memory source and should be 0.
emit_vex_prefix(buf, dest >= XMM8_REG, 0, src_base >= R8_REG, 1, false, 0, true, 1);
emit_byte(buf, 0x10); // Opcode for MOVUPD
uint8_t mod = (offset >= -128 && offset <= 127) ? 0x40 : 0x80;
if (offset == 0 && (src_base % 8) != RBP_REG)
mod = 0x00;
emit_modrm(buf, mod >> 6, dest % 8, src_base % 8);
if (src_base % 8 == RSP_REG)
emit_byte(buf, 0x24);
if (mod == 0x40)
emit_byte(buf, (uint8_t)offset);
else if (mod == 0x80)
emit_int32(buf, offset);
}
/**
* @internal
* @brief Emits `vmovupd [base + offset], ymm` to store a 256-bit unaligned value (AVX).
* @details Instruction format: VEX.256.66.0F.WIG 11 /r
*/
INFIX_INTERNAL void emit_vmovupd_mem_ymm(code_buffer * buf, x64_gpr dest_base, int32_t offset, x64_xmm src) {
// For a store, the VEX.vvvv field is not used and should be 0.
emit_vex_prefix(buf, src >= XMM8_REG, 0, dest_base >= R8_REG, 1, false, 0, true, 1);
emit_byte(buf, 0x11); // Opcode for MOVUPD (store)
uint8_t mod = (offset >= -128 && offset <= 127) ? 0x40 : 0x80;
if (offset == 0 && (dest_base % 8) != RBP_REG)
mod = 0x00;
emit_modrm(buf, mod >> 6, src % 8, dest_base % 8);
if (dest_base % 8 == RSP_REG)
emit_byte(buf, 0x24);
if (mod == 0x40)
emit_byte(buf, (uint8_t)offset);
else if (mod == 0x80)
emit_int32(buf, offset);
( run in 2.542 seconds using v1.01-cache-2.11-cpan-ceb78f64989 )