1
- //! Encodes instructions in the standard x86 encoding mode. This is called IA-32E mode in the Intel
2
- //! manuals but corresponds to the addition of the REX-prefix format (hence the name of this module)
3
- //! that allowed encoding instructions in both compatibility mode (32-bit instructions running on a
1
+ //! Encodes instructions in the standard x86 encoding mode. This is called
2
+ //! IA-32E mode in the Intel manuals but corresponds to the addition of the
3
+ //! REX-prefix format (hence the name of this module) that allowed encoding
4
+ //! instructions in both compatibility mode (32-bit instructions running on a
4
5
//! 64-bit OS) and in 64-bit mode (using the full 64-bit address space).
5
6
//!
6
- //! For all of the routines that take both a memory-or-reg operand (sometimes called "E" in the
7
- //! Intel documentation, see the Intel Developer's manual, vol. 2, section A.2) and a reg-only
8
- //! operand ("G" in Intelese), the order is always G first, then E. The term "enc" in the following
9
- //! means "hardware register encoding number".
10
-
11
- use crate :: machinst:: { Reg , RegClass } ;
12
- use crate :: {
13
- isa:: x64:: inst:: {
14
- args:: { Amode , OperandSize } ,
15
- regs, Inst , LabelUse ,
16
- } ,
17
- machinst:: MachBuffer ,
18
- } ;
7
+ //! For all of the routines that take both a memory-or-reg operand (sometimes
8
+ //! called "E" in the Intel documentation, see the Intel Developer's manual,
9
+ //! vol. 2, section A.2) and a reg-only operand ("G" in Intel-ese), the order is
10
+ //! always G first, then E. The term "enc" in the following means "hardware
11
+ //! register encoding number".
12
+
13
+ use super :: ByteSink ;
14
+ use crate :: isa:: x64:: inst:: args:: { Amode , OperandSize } ;
15
+ use crate :: isa:: x64:: inst:: { regs, Inst , LabelUse } ;
16
+ use crate :: machinst:: { MachBuffer , Reg , RegClass } ;
19
17
20
18
pub ( crate ) fn low8_will_sign_extend_to_64 ( x : u32 ) -> bool {
21
19
let xs = ( x as i32 ) as i64 ;
@@ -81,13 +79,25 @@ impl RexFlags {
81
79
Self ( 1 )
82
80
}
83
81
82
+ /// True if 64-bit operands are used.
83
+ #[ inline( always) ]
84
+ pub fn must_clear_w ( & self ) -> bool {
85
+ ( self . 0 & 1 ) != 0
86
+ }
87
+
84
88
/// Require that the REX prefix is emitted.
85
89
#[ inline( always) ]
86
90
pub fn always_emit ( & mut self ) -> & mut Self {
87
91
self . 0 = self . 0 | 2 ;
88
92
self
89
93
}
90
94
95
+ /// True if the REX prefix must always be emitted.
96
+ #[ inline( always) ]
97
+ pub fn must_always_emit ( & self ) -> bool {
98
+ ( self . 0 & 2 ) != 0
99
+ }
100
+
91
101
/// Emit the rex prefix if the referenced register would require it for 8-bit operations.
92
102
#[ inline( always) ]
93
103
pub fn always_emit_if_8bit_needed ( & mut self , reg : Reg ) -> & mut Self {
@@ -98,21 +108,9 @@ impl RexFlags {
98
108
self
99
109
}
100
110
101
- /// True if 64-bit operands are used.
102
- #[ inline( always) ]
103
- pub fn must_clear_w ( & self ) -> bool {
104
- ( self . 0 & 1 ) != 0
105
- }
106
-
107
- /// True if the REX prefix must always be emitted.
108
- #[ inline( always) ]
109
- pub fn must_always_emit ( & self ) -> bool {
110
- ( self . 0 & 2 ) != 0
111
- }
112
-
113
111
/// Emit a unary instruction.
114
112
#[ inline( always) ]
115
- pub fn emit_one_op ( & self , sink : & mut MachBuffer < Inst > , enc_e : u8 ) {
113
+ pub fn emit_one_op < BS : ByteSink + ? Sized > ( & self , sink : & mut BS , enc_e : u8 ) {
116
114
// Register Operand coded in Opcode Byte
117
115
// REX.R and REX.X unused
118
116
// REX.B == 1 accesses r8-r15
@@ -128,7 +126,7 @@ impl RexFlags {
128
126
129
127
/// Emit a binary instruction.
130
128
#[ inline( always) ]
131
- pub fn emit_two_op ( & self , sink : & mut MachBuffer < Inst > , enc_g : u8 , enc_e : u8 ) {
129
+ pub fn emit_two_op < BS : ByteSink + ? Sized > ( & self , sink : & mut BS , enc_g : u8 , enc_e : u8 ) {
132
130
let w = if self . must_clear_w ( ) { 0 } else { 1 } ;
133
131
let r = ( enc_g >> 3 ) & 1 ;
134
132
let x = 0 ;
@@ -141,9 +139,9 @@ impl RexFlags {
141
139
142
140
/// Emit a ternary instruction.
143
141
#[ inline( always) ]
144
- pub fn emit_three_op (
142
+ pub fn emit_three_op < BS : ByteSink + ? Sized > (
145
143
& self ,
146
- sink : & mut MachBuffer < Inst > ,
144
+ sink : & mut BS ,
147
145
enc_g : u8 ,
148
146
enc_index : u8 ,
149
147
enc_base : u8 ,
@@ -232,7 +230,7 @@ pub enum LegacyPrefixes {
232
230
impl LegacyPrefixes {
233
231
/// Emit the legacy prefix as bytes (e.g. in REX instructions).
234
232
#[ inline( always) ]
235
- pub ( crate ) fn emit ( & self , sink : & mut MachBuffer < Inst > ) {
233
+ pub ( crate ) fn emit < BS : ByteSink + ? Sized > ( & self , sink : & mut BS ) {
236
234
match self {
237
235
Self :: _66 => sink. put1 ( 0x66 ) ,
238
236
Self :: _F0 => sink. put1 ( 0xF0 ) ,
@@ -501,7 +499,7 @@ impl Imm {
501
499
}
502
500
}
503
501
504
- fn emit ( & self , sink : & mut MachBuffer < Inst > ) {
502
+ fn emit < BS : ByteSink + ? Sized > ( & self , sink : & mut BS ) {
505
503
match self {
506
504
Imm :: None => { }
507
505
Imm :: Imm8 ( n) => sink. put1 ( * n as u8 ) ,
@@ -514,8 +512,8 @@ impl Imm {
514
512
///
515
513
/// This is conceptually the same as emit_modrm_sib_enc_ge, except it is for the case where the E
516
514
/// operand is a register rather than memory. Hence it is much simpler.
517
- pub ( crate ) fn emit_std_enc_enc (
518
- sink : & mut MachBuffer < Inst > ,
515
+ pub ( crate ) fn emit_std_enc_enc < BS : ByteSink + ? Sized > (
516
+ sink : & mut BS ,
519
517
prefixes : LegacyPrefixes ,
520
518
opcodes : u32 ,
521
519
mut num_opcodes : usize ,
@@ -571,8 +569,8 @@ pub(crate) fn emit_std_reg_mem(
571
569
) ;
572
570
}
573
571
574
- pub ( crate ) fn emit_std_reg_reg (
575
- sink : & mut MachBuffer < Inst > ,
572
+ pub ( crate ) fn emit_std_reg_reg < BS : ByteSink + ? Sized > (
573
+ sink : & mut BS ,
576
574
prefixes : LegacyPrefixes ,
577
575
opcodes : u32 ,
578
576
num_opcodes : usize ,
@@ -586,7 +584,7 @@ pub(crate) fn emit_std_reg_reg(
586
584
}
587
585
588
586
/// Write a suitable number of bits from an imm64 to the sink.
589
- pub ( crate ) fn emit_simm ( sink : & mut MachBuffer < Inst > , size : u8 , simm32 : u32 ) {
587
+ pub ( crate ) fn emit_simm < BS : ByteSink + ? Sized > ( sink : & mut BS , size : u8 , simm32 : u32 ) {
590
588
match size {
591
589
8 | 4 => sink. put4 ( simm32) ,
592
590
2 => sink. put2 ( simm32 as u16 ) ,
0 commit comments