// This is the core 'emit' function for instructions that reference memory.
//
// For an instruction that has as operands a register |encG| and a memory
// address |memE|, create and emit, first the REX prefix, then caller-supplied
// opcode byte(s) (|opcodes| and |numOpcodes|), then the MOD/RM byte, then
// optionally, a SIB byte, and finally optionally an immediate that will be
// derived from the |memE| operand.  For most instructions up to and including
// SSE4.2, that will be the whole instruction.
//
// The opcodes are written bigendianly for the convenience of callers.  For
// example, if the opcode bytes to be emitted are, in this order, F3 0F 27,
// then the caller should pass |opcodes| == 0xF3_0F_27 and |numOpcodes| == 3.
//
// The register operand is represented here not as a |Reg| but as its hardware
// encoding, |encG|.  |flags| can specify special handling for the REX prefix.
// By default, the REX prefix will indicate a 64-bit operation and will be
// deleted if it is redundant (0x40).  Note that for a 64-bit operation, the
// REX prefix will normally never be redundant, since REX.W must be 1 to
// indicate a 64-bit operation.
This is the core 'emit' function for instructions that reference memory.

The opcodes are written bigendianly for the convenience of callers.  For
example, if the opcode bytes to be emitted are, in this order, F3 0F 27,
then the caller should pass |opcodes| == 0xF3_0F_27 and |numOpcodes| == 3.

The register operand is represented here not as a |Reg| but as its hardware
encoding, |encG|.  |flags| can specify special handling for the REX prefix.
By default, the REX prefix will indicate a 64-bit operation and will be
deleted if it is redundant (0x40).  Note that for a 64-bit operation, the
REX prefix will normally never be redundant, since REX.W must be 1 to
indicate a 64-bit operation.
This is the core ' emit ' function for instructions that reference memory . The opcodes are written bigendianly for the convenience of callers . For example if the opcode bytes to be emitted are in this order F3 0F 27 then the caller should pass |opcodes| == 0xF3_0F_27 and |numOpcodes| == 3 . The register operand is represented here not as a |Reg| but as its hardware encoding |encG| . |flags| can specify special handling for the REX prefix . By default the REX prefix will indicate a 64 - bit operation and will be deleted if it is redundant ( 0x40 ) . Note that for a 64 - bit operation the REX prefix will normally never be redundant since REX . W must be 1 to indicate a 64 - bit operation .
fn emit_REX_OPCODES_MODRM_SIB_IMM_encG_memE<O: MachSectionOutput>(
    sink: &mut O,
    opcodes: u32,
    mut numOpcodes: usize,
    encG: u8,
    memE: &Addr,
    flags: u32,
) {
    // General comment for this function: the registers in |memE| must be
    // 64-bit integer registers, because they are part of an address
    // expression.  But |encG| can be derived from a register of any class.
    let prefix66 = (flags & F_PREFIX_66) != 0;
    let clearRexW = (flags & F_CLEAR_REX_W) != 0;
    let retainRedundant = (flags & F_RETAIN_REDUNDANT_REX) != 0;
    // The operand-size override, if requested.  This indicates a 16-bit
    // operation.
    if prefix66 {
        sink.put1(0x66);
    }
    match memE {
        Addr::IR { simm32, base: regE } => {
            // First, cook up the REX byte.  This is easy.
            let encE = iregEnc(*regE);
            let w = if clearRexW { 0 } else { 1 };
            let r = (encG >> 3) & 1;
            let x = 0;
            let b = (encE >> 3) & 1;
            let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
            if rex != 0x40 || retainRedundant {
                sink.put1(rex);
            }
            // Now the opcode(s).  These include any other prefixes the caller
            // hands to us.
            while numOpcodes > 0 {
                numOpcodes -= 1;
                sink.put1(((opcodes >> (numOpcodes << 3)) & 0xFF) as u8);
            }
            // Now the mod/rm and associated immediates.  This is
            // significantly complicated due to the multiple special cases.
            if *simm32 == 0
                && encE != ENC_RSP
                && encE != ENC_RBP
                && encE != ENC_R12
                && encE != ENC_R13
            {
                // FIXME JRS 2020Feb11: those four tests can surely be
                // replaced by a single mask-and-compare check.  We should do
                // that because this routine is likely to be hot.
                sink.put1(mkModRegRM(0, encG & 7, encE & 7));
            } else if *simm32 == 0 && (encE == ENC_RSP || encE == ENC_R12) {
                sink.put1(mkModRegRM(0, encG & 7, 4));
                sink.put1(0x24);
            } else if low8willSXto32(*simm32) && encE != ENC_RSP && encE != ENC_R12 {
                sink.put1(mkModRegRM(1, encG & 7, encE & 7));
                sink.put1((simm32 & 0xFF) as u8);
            } else if encE != ENC_RSP && encE != ENC_R12 {
                sink.put1(mkModRegRM(2, encG & 7, encE & 7));
                sink.put4(*simm32);
            } else if (encE == ENC_RSP || encE == ENC_R12) && low8willSXto32(*simm32) {
                // REX.B distinguishes RSP from R12
                sink.put1(mkModRegRM(1, encG & 7, 4));
                sink.put1(0x24);
                sink.put1((simm32 & 0xFF) as u8);
            } else if encE == ENC_R12 || encE == ENC_RSP {
                //.. wait for test case for RSP case
                // REX.B distinguishes RSP from R12
                sink.put1(mkModRegRM(2, encG & 7, 4));
                sink.put1(0x24);
                sink.put4(*simm32);
            } else {
                panic!("emit_REX_OPCODES_MODRM_SIB_IMM_encG_memE: IR");
            }
        }
        // Bizarrely, the IRRS case is much simpler.
        Addr::IRRS {
            simm32,
            base: regBase,
            index: regIndex,
            shift,
        } => {
            let encBase = iregEnc(*regBase);
            let encIndex = iregEnc(*regIndex);
            // The rex byte
            let w = if clearRexW { 0 } else { 1 };
            let r = (encG >> 3) & 1;
            let x = (encIndex >> 3) & 1;
            let b = (encBase >> 3) & 1;
            let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
            if rex != 0x40 || retainRedundant {
                sink.put1(rex);
            }
            // All other prefixes and opcodes
            while numOpcodes > 0 {
                numOpcodes -= 1;
                sink.put1(((opcodes >> (numOpcodes << 3)) & 0xFF) as u8);
            }
            // modrm, SIB, immediates
            if low8willSXto32(*simm32) && encIndex != ENC_RSP {
                sink.put1(mkModRegRM(1, encG & 7, 4));
                sink.put1(mkSIB(*shift, encIndex & 7, encBase & 7));
                sink.put1(*simm32 as u8);
            } else if encIndex != ENC_RSP {
                sink.put1(mkModRegRM(2, encG & 7, 4));
                sink.put1(mkSIB(*shift, encIndex & 7, encBase & 7));
                sink.put4(*simm32);
            } else {
                panic!("emit_REX_OPCODES_MODRM_SIB_IMM_encG_memE: IRRS");
            }
        }
    }
}
fn emit_REX_OPCODES_MODRM_SIB_IMM_encG_memE < O : MachSectionOutput > ( sink : & mut O , opcodes : u32 , mut numOpcodes : usize , encG : u8 , memE : & Addr , flags : u32 , ) { // General comment for this function: the registers in |memE| must be // 64-bit integer registers, because they are part of an address // expression.  But |encG| can be derived from a register of any class. let prefix66 = ( flags & F_PREFIX_66 ) != 0 ; let clearRexW = ( flags & F_CLEAR_REX_W ) != 0 ; let retainRedundant = ( flags & F_RETAIN_REDUNDANT_REX ) != 0 ; // The operand-size override, if requested.  This indicates a 16-bit // operation. if prefix66 { sink . put1 ( 0x66 ) ; } match memE { Addr :: IR { simm32 , base : regE } => { // First, cook up the REX byte.  This is easy. let encE = iregEnc ( * regE ) ; let w = if clearRexW { 0 } else { 1 } ; let r = ( encG >> 3 ) & 1 ; let x = 0 ; let b = ( encE >> 3 ) & 1 ; let rex = 0x40 | ( w << 3 ) | ( r << 2 ) | ( x << 1 ) | b ; if rex != 0x40 || retainRedundant { sink . put1 ( rex ) ; } // Now the opcode(s).  These include any other prefixes the caller // hands to us. while numOpcodes > 0 { numOpcodes -= 1 ; sink . put1 ( ( ( opcodes >> ( numOpcodes << 3 ) ) & 0xFF ) as u8 ) ; } // Now the mod/rm and associated immediates.  This is // significantly complicated due to the multiple special cases. if * simm32 == 0 && encE != ENC_RSP && encE != ENC_RBP && encE != ENC_R12 && encE != ENC_R13 { // FIXME JRS 2020Feb11: those four tests can surely be // replaced by a single mask-and-compare check.  We should do // that because this routine is likely to be hot. sink . put1 ( mkModRegRM ( 0 , encG & 7 , encE & 7 ) ) ; } else if * simm32 == 0 && ( encE == ENC_RSP || encE == ENC_R12 ) { sink . put1 ( mkModRegRM ( 0 , encG & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; } else if low8willSXto32 ( * simm32 ) && encE != ENC_RSP && encE != ENC_R12 { sink . put1 ( mkModRegRM ( 1 , encG & 7 , encE & 7 ) ) ; sink . put1 ( ( simm32 & 0xFF ) as u8 ) ; } else if encE != ENC_RSP && encE != ENC_R12 { sink . put1 ( mkModRegRM ( 2 , encG & 7 , encE & 7 ) ) ; sink . put4 ( * simm32 ) ; } else if ( encE == ENC_RSP || encE == ENC_R12 ) && low8willSXto32 ( * simm32 ) { // REX.B distinguishes RSP from R12 sink . put1 ( mkModRegRM ( 1 , encG & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; sink . put1 ( ( simm32 & 0xFF ) as u8 ) ; } else if encE == ENC_R12 || encE == ENC_RSP { //.. wait for test case for RSP case // REX.B distinguishes RSP from R12 sink . put1 ( mkModRegRM ( 2 , encG & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; sink . put4 ( * simm32 ) ; } else { panic ! ( " " ) ; } } // Bizarrely, the IRRS case is much simpler. Addr :: IRRS { simm32 , base : regBase , index : regIndex , shift , } => { let encBase = iregEnc ( * regBase ) ; let encIndex = iregEnc ( * regIndex ) ; // The rex byte let w = if clearRexW { 0 } else { 1 } ; let r = ( encG >> 3 ) & 1 ; let x = ( encIndex >> 3 ) & 1 ; let b = ( encBase >> 3 ) & 1 ; let rex = 0x40 | ( w << 3 ) | ( r << 2 ) | ( x << 1 ) | b ; if rex != 0x40 || retainRedundant { sink . put1 ( rex ) ; } // All other prefixes and opcodes while numOpcodes > 0 { numOpcodes -= 1 ; sink . put1 ( ( ( opcodes >> ( numOpcodes << 3 ) ) & 0xFF ) as u8 ) ; } // modrm, SIB, immediates if low8willSXto32 ( * simm32 ) && encIndex != ENC_RSP { sink . put1 ( mkModRegRM ( 1 , encG & 7 , 4 ) ) ; sink . put1 ( mkSIB ( * shift , encIndex & 7 , encBase & 7 ) ) ; sink . put1 ( * simm32 as u8 ) ; } else if encIndex != ENC_RSP { sink . put1 ( mkModRegRM ( 2 , encG & 7 , 4 ) ) ; sink . put1 ( mkSIB ( * shift , encIndex & 7 , encBase & 7 ) ) ; sink . put4 ( * simm32 ) ; } else { panic ! ( " " ) ; } } } }
This is the core 'emit' function for instructions that reference memory.
This is the core ' emit ' function for instructions that reference memory .
sink
&mut O
opcodes
u32
numOpcodes
usize
encG
u8
memE
&Addr
flags
u32