fn emit_std_enc_mem(
    sink: &mut MachBuffer<Inst>,
    state: &EmitState,
    info: &EmitInfo,
    prefixes: LegacyPrefixes,
    opcodes: u32,
    mut num_opcodes: usize,
    enc_g: u8,
    mem_e: &Amode,
    rex: RexFlags,
) {
    // General comment for this function: the registers in `mem_e` must be
    // 64-bit integer registers, because they are part of an address
    // expression.  But `enc_g` can be derived from a register of any class.

    let srcloc = state.cur_srcloc();
    let can_trap = mem_e.can_trap();
    if srcloc != SourceLoc::default() && can_trap {
        sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
    }

    prefixes.emit(sink);

    match mem_e {
        Amode::ImmReg { simm32, base, .. } => {
            // If this is an access based off of RSP, it may trap with a stack overflow if it's the
            // first touch of a new stack page.
            if *base == regs::rsp() && !can_trap && info.flags().enable_probestack() {
                sink.add_trap(srcloc, TrapCode::StackOverflow);
            }

            // First, the REX byte.
            let enc_e = int_reg_enc(*base);
            rex.emit_two_op(sink, enc_g, enc_e);

            // Now the opcode(s).  These include any other prefixes the caller
            // hands to us.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }

            // Now the mod/rm and associated immediates.  This is
            // significantly complicated due to the multiple special cases.
            if *simm32 == 0
                && enc_e != regs::ENC_RSP
                && enc_e != regs::ENC_RBP
                && enc_e != regs::ENC_R12
                && enc_e != regs::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(encode_modrm(0, enc_g & 7, enc_e & 7));
            } else if *simm32 == 0 && (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12) {
                sink.put1(encode_modrm(0, enc_g & 7, 4));
                sink.put1(0x24);
            } else if low8_will_sign_extend_to_32(*simm32)
                && enc_e != regs::ENC_RSP
                && enc_e != regs::ENC_R12
            {
                sink.put1(encode_modrm(1, enc_g & 7, enc_e & 7));
                sink.put1((simm32 & 0xFF) as u8);
            } else if enc_e != regs::ENC_RSP && enc_e != regs::ENC_R12 {
                sink.put1(encode_modrm(2, enc_g & 7, enc_e & 7));
                sink.put4(*simm32);
            } else if (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12)
                && low8_will_sign_extend_to_32(*simm32)
            {
                // REX.B distinguishes RSP from R12
                sink.put1(encode_modrm(1, enc_g & 7, 4));
                sink.put1(0x24);
                sink.put1((simm32 & 0xFF) as u8);
            } else if enc_e == regs::ENC_R12 || enc_e == regs::ENC_RSP {
                //.. wait for test case for RSP case
                // REX.B distinguishes RSP from R12
                sink.put1(encode_modrm(2, enc_g & 7, 4));
                sink.put1(0x24);
                sink.put4(*simm32);
            } else {
                unreachable!("ImmReg");
            }
        }

        Amode::ImmRegRegShift {
            simm32,
            base: reg_base,
            index: reg_index,
            shift,
            ..
        } => {
            // If this is an access based off of RSP, it may trap with a stack overflow if it's the
            // first touch of a new stack page.
            if *reg_base == regs::rsp() && !can_trap && info.flags().enable_probestack() {
                sink.add_trap(srcloc, TrapCode::StackOverflow);
            }

            let enc_base = int_reg_enc(*reg_base);
            let enc_index = int_reg_enc(*reg_index);

            // The rex byte.
            rex.emit_three_op(sink, enc_g, enc_index, enc_base);

            // All other prefixes and opcodes.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }

            // modrm, SIB, immediates.
            if low8_will_sign_extend_to_32(*simm32) && enc_index != regs::ENC_RSP {
                sink.put1(encode_modrm(1, enc_g & 7, 4));
                sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
                sink.put1(*simm32 as u8);
            } else if enc_index != regs::ENC_RSP {
                sink.put1(encode_modrm(2, enc_g & 7, 4));
                sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
                sink.put4(*simm32);
            } else {
                panic!("ImmRegRegShift");
            }
        }

        Amode::RipRelative { ref target } => {
            // First, the REX byte, with REX.B = 0.
            rex.emit_two_op(sink, enc_g, 0);

            // Now the opcode(s).  These include any other prefixes the caller
            // hands to us.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }

            // RIP-relative is mod=00, rm=101.
            sink.put1(encode_modrm(0, enc_g & 7, 0b101));

            let offset = sink.cur_offset();
            sink.use_label_at_offset(offset, *target, LabelUse::JmpRel32);
            sink.put4(0);
        }
    }
}
/// This is the core 'emit' function for instructions that reference memory.
///
/// For an instruction that has as operands a reg encoding `enc_g` and a memory address `mem_e`,
/// create and emit:
/// - first the legacy prefixes, if any
/// - then the REX prefix, if needed
/// - then caller-supplied opcode byte(s) (`opcodes` and `num_opcodes`),
/// - then the MOD/RM byte,
/// - then optionally, a SIB byte,
/// - and finally optionally an immediate that will be derived from the `mem_e` operand.
///
/// For most instructions up to and including SSE4.2, that will be the whole instruction: this is
/// what we call "standard" instructions, and abbreviate "std" in the name here. VEX-prefixed
/// instructions will require their own emitter functions.
///
/// This will also work for 32-bits x86 instructions, assuming no REX prefix is provided.
///
/// 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 `num_opcodes` == 3.
///
/// The register operand is represented here not as a `Reg` but as its hardware encoding, `enc_g`.
/// `rex` 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.

For most instructions up to and including SSE4.2, that will be the whole instruction: this is
what we call "standard" instructions, and abbreviate "std" in the name here. VEX-prefixed
instructions will require their own emitter functions.

This will also work for 32-bits x86 instructions, assuming no REX prefix is provided.

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 `num_opcodes` == 3.

The register operand is represented here not as a `Reg` but as its hardware encoding, `enc_g`.
`rex` 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 . For most instructions up to and including SSE4 . 2 that will be the whole instruction : this is what we call " standard " instructions and abbreviate " std " in the name here . VEX - prefixed instructions will require their own emitter functions . This will also work for 32 - bits x86 instructions assuming no REX prefix is provided . 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 ` num_opcodes ` == 3 . The register operand is represented here not as a ` Reg ` but as its hardware encoding ` enc_g ` . ` rex ` 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_std_enc_mem(
    sink: &mut MachBuffer<Inst>,
    state: &EmitState,
    info: &EmitInfo,
    prefixes: LegacyPrefixes,
    opcodes: u32,
    mut num_opcodes: usize,
    enc_g: u8,
    mem_e: &Amode,
    rex: RexFlags,
) {
    // General comment for this function: the registers in `mem_e` must be
    // 64-bit integer registers, because they are part of an address
    // expression.  But `enc_g` can be derived from a register of any class.
    let srcloc = state.cur_srcloc();
    let can_trap = mem_e.can_trap();
    if srcloc != SourceLoc::default() && can_trap {
        sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
    }
    prefixes.emit(sink);
    match mem_e {
        Amode::ImmReg { simm32, base, .. } => {
            // If this is an access based off of RSP, it may trap with a stack overflow if it's the
            // first touch of a new stack page.
            if *base == regs::rsp() && !can_trap && info.flags().enable_probestack() {
                sink.add_trap(srcloc, TrapCode::StackOverflow);
            }
            // First, the REX byte.
            let enc_e = int_reg_enc(*base);
            rex.emit_two_op(sink, enc_g, enc_e);
            // Now the opcode(s).  These include any other prefixes the caller
            // hands to us.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }
            // Now the mod/rm and associated immediates.  This is
            // significantly complicated due to the multiple special cases.
            if *simm32 == 0
                && enc_e != regs::ENC_RSP
                && enc_e != regs::ENC_RBP
                && enc_e != regs::ENC_R12
                && enc_e != regs::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(encode_modrm(0, enc_g & 7, enc_e & 7));
            } else if *simm32 == 0 && (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12) {
                sink.put1(encode_modrm(0, enc_g & 7, 4));
                sink.put1(0x24);
            } else if low8_will_sign_extend_to_32(*simm32)
                && enc_e != regs::ENC_RSP
                && enc_e != regs::ENC_R12
            {
                sink.put1(encode_modrm(1, enc_g & 7, enc_e & 7));
                sink.put1((simm32 & 0xFF) as u8);
            } else if enc_e != regs::ENC_RSP && enc_e != regs::ENC_R12 {
                sink.put1(encode_modrm(2, enc_g & 7, enc_e & 7));
                sink.put4(*simm32);
            } else if (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12)
                && low8_will_sign_extend_to_32(*simm32)
            {
                // REX.B distinguishes RSP from R12
                sink.put1(encode_modrm(1, enc_g & 7, 4));
                sink.put1(0x24);
                sink.put1((simm32 & 0xFF) as u8);
            } else if enc_e == regs::ENC_R12 || enc_e == regs::ENC_RSP {
                //.. wait for test case for RSP case
                // REX.B distinguishes RSP from R12
                sink.put1(encode_modrm(2, enc_g & 7, 4));
                sink.put1(0x24);
                sink.put4(*simm32);
            } else {
                unreachable!("ImmReg");
            }
        }
        Amode::ImmRegRegShift {
            simm32,
            base: reg_base,
            index: reg_index,
            shift,
            ..
        } => {
            // If this is an access based off of RSP, it may trap with a stack overflow if it's the
            // first touch of a new stack page.
            if *reg_base == regs::rsp() && !can_trap && info.flags().enable_probestack() {
                sink.add_trap(srcloc, TrapCode::StackOverflow);
            }
            let enc_base = int_reg_enc(*reg_base);
            let enc_index = int_reg_enc(*reg_index);
            // The rex byte.
            rex.emit_three_op(sink, enc_g, enc_index, enc_base);
            // All other prefixes and opcodes.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }
            // modrm, SIB, immediates.
            if low8_will_sign_extend_to_32(*simm32) && enc_index != regs::ENC_RSP {
                sink.put1(encode_modrm(1, enc_g & 7, 4));
                sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
                sink.put1(*simm32 as u8);
            } else if enc_index != regs::ENC_RSP {
                sink.put1(encode_modrm(2, enc_g & 7, 4));
                sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
                sink.put4(*simm32);
            } else {
                panic!("ImmRegRegShift");
            }
        }
        Amode::RipRelative { ref target } => {
            // First, the REX byte, with REX.B = 0.
            rex.emit_two_op(sink, enc_g, 0);
            // Now the opcode(s).  These include any other prefixes the caller
            // hands to us.
            while num_opcodes > 0 {
                num_opcodes -= 1;
                sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8);
            }
            // RIP-relative is mod=00, rm=101.
            sink.put1(encode_modrm(0, enc_g & 7, 0b101));
            let offset = sink.cur_offset();
            sink.use_label_at_offset(offset, *target, LabelUse::JmpRel32);
            sink.put4(0);
        }
    }
}
fn emit_std_enc_mem ( sink : & mut MachBuffer < Inst > , state : & EmitState , info : & EmitInfo , prefixes : LegacyPrefixes , opcodes : u32 , mut num_opcodes : usize , enc_g : u8 , mem_e : & Amode , rex : RexFlags , ) { // General comment for this function: the registers in `mem_e` must be // 64-bit integer registers, because they are part of an address // expression.  But `enc_g` can be derived from a register of any class. let srcloc = state . cur_srcloc ( ) ; let can_trap = mem_e . can_trap ( ) ; if srcloc != SourceLoc :: default ( ) && can_trap { sink . add_trap ( srcloc , TrapCode :: HeapOutOfBounds ) ; } prefixes . emit ( sink ) ; match mem_e { Amode :: ImmReg { simm32 , base , .. } => { // If this is an access based off of RSP, it may trap with a stack overflow if it's the // first touch of a new stack page. if * base == regs :: rsp ( ) && ! can_trap && info . flags ( ) . enable_probestack ( ) { sink . add_trap ( srcloc , TrapCode :: StackOverflow ) ; } // First, the REX byte. let enc_e = int_reg_enc ( * base ) ; rex . emit_two_op ( sink , enc_g , enc_e ) ; // Now the opcode(s).  These include any other prefixes the caller // hands to us. while num_opcodes > 0 { num_opcodes -= 1 ; sink . put1 ( ( ( opcodes >> ( num_opcodes << 3 ) ) & 0xFF ) as u8 ) ; } // Now the mod/rm and associated immediates.  This is // significantly complicated due to the multiple special cases. if * simm32 == 0 && enc_e != regs :: ENC_RSP && enc_e != regs :: ENC_RBP && enc_e != regs :: ENC_R12 && enc_e != regs :: 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 ( encode_modrm ( 0 , enc_g & 7 , enc_e & 7 ) ) ; } else if * simm32 == 0 && ( enc_e == regs :: ENC_RSP || enc_e == regs :: ENC_R12 ) { sink . put1 ( encode_modrm ( 0 , enc_g & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; } else if low8_will_sign_extend_to_32 ( * simm32 ) && enc_e != regs :: ENC_RSP && enc_e != regs :: ENC_R12 { sink . put1 ( encode_modrm ( 1 , enc_g & 7 , enc_e & 7 ) ) ; sink . put1 ( ( simm32 & 0xFF ) as u8 ) ; } else if enc_e != regs :: ENC_RSP && enc_e != regs :: ENC_R12 { sink . put1 ( encode_modrm ( 2 , enc_g & 7 , enc_e & 7 ) ) ; sink . put4 ( * simm32 ) ; } else if ( enc_e == regs :: ENC_RSP || enc_e == regs :: ENC_R12 ) && low8_will_sign_extend_to_32 ( * simm32 ) { // REX.B distinguishes RSP from R12 sink . put1 ( encode_modrm ( 1 , enc_g & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; sink . put1 ( ( simm32 & 0xFF ) as u8 ) ; } else if enc_e == regs :: ENC_R12 || enc_e == regs :: ENC_RSP { //.. wait for test case for RSP case // REX.B distinguishes RSP from R12 sink . put1 ( encode_modrm ( 2 , enc_g & 7 , 4 ) ) ; sink . put1 ( 0x24 ) ; sink . put4 ( * simm32 ) ; } else { unreachable ! ( " " ) ; } } Amode :: ImmRegRegShift { simm32 , base : reg_base , index : reg_index , shift , .. } => { // If this is an access based off of RSP, it may trap with a stack overflow if it's the // first touch of a new stack page. if * reg_base == regs :: rsp ( ) && ! can_trap && info . flags ( ) . enable_probestack ( ) { sink . add_trap ( srcloc , TrapCode :: StackOverflow ) ; } let enc_base = int_reg_enc ( * reg_base ) ; let enc_index = int_reg_enc ( * reg_index ) ; // The rex byte. rex . emit_three_op ( sink , enc_g , enc_index , enc_base ) ; // All other prefixes and opcodes. while num_opcodes > 0 { num_opcodes -= 1 ; sink . put1 ( ( ( opcodes >> ( num_opcodes << 3 ) ) & 0xFF ) as u8 ) ; } // modrm, SIB, immediates. if low8_will_sign_extend_to_32 ( * simm32 ) && enc_index != regs :: ENC_RSP { sink . put1 ( encode_modrm ( 1 , enc_g & 7 , 4 ) ) ; sink . put1 ( encode_sib ( * shift , enc_index & 7 , enc_base & 7 ) ) ; sink . put1 ( * simm32 as u8 ) ; } else if enc_index != regs :: ENC_RSP { sink . put1 ( encode_modrm ( 2 , enc_g & 7 , 4 ) ) ; sink . put1 ( encode_sib ( * shift , enc_index & 7 , enc_base & 7 ) ) ; sink . put4 ( * simm32 ) ; } else { panic ! ( " " ) ; } } Amode :: RipRelative { ref target } => { // First, the REX byte, with REX.B = 0. rex . emit_two_op ( sink , enc_g , 0 ) ; // Now the opcode(s).  These include any other prefixes the caller // hands to us. while num_opcodes > 0 { num_opcodes -= 1 ; sink . put1 ( ( ( opcodes >> ( num_opcodes << 3 ) ) & 0xFF ) as u8 ) ; } // RIP-relative is mod=00, rm=101. sink . put1 ( encode_modrm ( 0 , enc_g & 7 , 0b101 ) ) ; let offset = sink . cur_offset ( ) ; sink . use_label_at_offset ( offset , * target , LabelUse :: JmpRel32 ) ; sink . put4 ( 0 ) ; } } }
This is the core 'emit' function for instructions that reference memory.
This is the core ' emit ' function for instructions that reference memory .
sink
&mut MachBuffer<Inst>
state
&EmitState
info
&EmitInfo
prefixes
LegacyPrefixes
opcodes
u32
num_opcodes
usize
enc_g
u8
mem_e
&Amode
rex
RexFlags
sink
&mut MachBuffer<Inst>
state
&EmitState
info
&EmitInfo
prefixes
LegacyPrefixes
opcodes
u32
num_opcodes
usize
enc_g
u8
mem_e
&Amode
rex
RexFlags