1use super::evex::EvexZeroingMode;
7use super::operand::{EncoderOperand, MemoryOperand};
8use super::types::{
9 BranchType, BranchWidth, BroadcastMode, EncodableEncoding, EncoderHints, RoundingMode,
10};
11use crate::isa::{Mnemonic, Register};
12
13pub const MAX_ENCODER_OPERANDS: usize = 5;
15
16#[derive(Debug, Clone)]
21pub struct EncoderRequest {
22 pub mnemonic: Mnemonic,
24 pub operands: [EncoderOperand; MAX_ENCODER_OPERANDS],
26 pub operand_count: u8,
28 pub operand_size: u8,
30 pub address_size: u8,
32 pub mask_reg: Option<Register>,
34 pub zeroing_mode: EvexZeroingMode,
36 pub preferred_encoding: Option<EncodableEncoding>,
38 pub branch_type: BranchType,
40 pub branch_width: BranchWidth,
42 pub hints: EncoderHints,
44}
45
46impl EncoderRequest {
47 #[must_use]
49 pub fn new(mnemonic: Mnemonic) -> Self {
50 Self {
51 mnemonic,
52 operands: [EncoderOperand::None; MAX_ENCODER_OPERANDS],
53 operand_count: 0,
54 operand_size: 0,
55 address_size: 0,
56 mask_reg: None,
57 zeroing_mode: EvexZeroingMode::Merging,
58 preferred_encoding: None,
59 branch_type: BranchType::None,
60 branch_width: BranchWidth::None,
61 hints: EncoderHints::default(),
62 }
63 }
64
65 #[must_use]
69 pub fn with_operand(mut self, operand: EncoderOperand) -> Self {
70 if (self.operand_count as usize) < MAX_ENCODER_OPERANDS {
71 self.operands[self.operand_count as usize] = operand;
72 self.operand_count += 1;
73 }
74 self
75 }
76
77 #[must_use]
79 pub fn with_reg(self, register: Register) -> Self {
80 self.with_operand(EncoderOperand::reg(register))
81 }
82
83 #[must_use]
85 pub fn with_mem(self, memory: MemoryOperand) -> Self {
86 self.with_operand(EncoderOperand::mem(memory))
87 }
88
89 #[must_use]
91 pub fn with_imm(self, value: u64) -> Self {
92 self.with_operand(EncoderOperand::imm(value))
93 }
94
95 #[must_use]
97 pub fn with_rel(self, offset: i32) -> Self {
98 self.with_operand(EncoderOperand::rel(offset))
99 }
100
101 #[must_use]
103 pub fn with_operand_size(mut self, size: u16) -> Self {
104 self.operand_size = size as u8;
105 self
106 }
107
108 #[must_use]
110 pub fn with_address_size(mut self, size: u16) -> Self {
111 self.address_size = size as u8;
112 self
113 }
114
115 #[must_use]
117 pub fn with_mask(mut self, mask: Register) -> Self {
118 self.mask_reg = Some(mask);
119 self
120 }
121
122 #[must_use]
124 pub fn with_zeroing(mut self, zeroing: EvexZeroingMode) -> Self {
125 self.zeroing_mode = zeroing;
126 self
127 }
128
129 #[must_use]
131 pub fn with_zeroing_enabled(self) -> Self {
132 self.with_zeroing(EvexZeroingMode::Zeroing)
133 }
134
135 #[must_use]
137 pub fn with_encoding(mut self, encoding: EncodableEncoding) -> Self {
138 self.preferred_encoding = Some(encoding);
139 self
140 }
141
142 #[must_use]
144 pub fn with_branch_type(mut self, branch_type: BranchType) -> Self {
145 self.branch_type = branch_type;
146 self
147 }
148
149 #[must_use]
151 pub fn with_branch_width(mut self, branch_width: BranchWidth) -> Self {
152 self.branch_width = branch_width;
153 self
154 }
155
156 #[must_use]
158 pub fn with_broadcast(mut self, mode: BroadcastMode) -> Self {
159 self.hints.broadcast_mode = mode;
160 self
161 }
162
163 #[must_use]
165 pub fn with_rounding(mut self, mode: RoundingMode) -> Self {
166 self.hints.rounding_mode = Some(mode);
167 self
168 }
169
170 #[must_use]
172 pub fn with_sae(mut self) -> Self {
173 self.hints.suppress_all_exceptions = true;
174 self
175 }
176
177 #[must_use]
179 pub fn with_hints(mut self, hints: EncoderHints) -> Self {
180 self.hints = hints;
181 self
182 }
183
184 #[must_use]
186 pub const fn has_mask(&self) -> bool {
187 self.mask_reg.is_some()
188 }
189
190 #[must_use]
192 pub const fn is_zeroing(&self) -> bool {
193 matches!(self.zeroing_mode, EvexZeroingMode::Zeroing)
194 }
195
196 #[must_use]
198 pub const fn has_preferred_encoding(&self) -> bool {
199 self.preferred_encoding.is_some()
200 }
201
202 #[must_use]
204 pub const fn has_broadcast(&self) -> bool {
205 !matches!(self.hints.broadcast_mode, BroadcastMode::None)
206 }
207
208 #[must_use]
210 pub const fn has_rounding(&self) -> bool {
211 self.hints.rounding_mode.is_some()
212 }
213
214 #[must_use]
216 pub const fn has_sae(&self) -> bool {
217 self.hints.suppress_all_exceptions
218 }
219
220 #[must_use]
222 pub const fn has_branch_type(&self) -> bool {
223 !matches!(self.branch_type, BranchType::None)
224 }
225
226 #[cfg(feature = "decoder")]
230 #[must_use]
231 pub fn from_decoded(instruction: &crate::decoder::DecodedInstruction) -> Self {
232 let mut request = Self::new(instruction.mnemonic)
235 .with_operand_size(instruction.operand_size)
236 .with_address_size(instruction.address_size);
237
238 for i in 0..instruction.operand_count as usize {
240 if let Some(operand) = instruction.operand(i) {
241 let encoder_op = Self::convert_operand(operand);
242 request = request.with_operand(encoder_op);
243 }
244 }
245
246 request
247 }
248
249 #[cfg(feature = "decoder")]
251 fn convert_operand(operand: &crate::decoder::Operand) -> EncoderOperand {
252 use crate::isa::OperandKind;
253
254 match operand.kind {
255 OperandKind::Register => {
256 if let Some(reg) = operand.reg() {
257 EncoderOperand::reg(reg)
258 } else {
259 EncoderOperand::None
260 }
261 }
262 OperandKind::Memory => {
263 if let Some(mem_data) = operand.mem() {
264 let mem = MemoryOperand {
265 segment: mem_data.segment,
266 base: mem_data.base,
267 index: mem_data.index,
268 scale: mem_data.scale,
269 displacement: mem_data.displacement,
270 disp_size: mem_data.disp_size,
271 };
272 EncoderOperand::mem(mem)
273 } else {
274 EncoderOperand::None
275 }
276 }
277 OperandKind::Immediate | OperandKind::RelativeOffset => {
278 if let Some(value) = operand.imm() {
279 EncoderOperand::imm(value)
280 } else {
281 EncoderOperand::None
282 }
283 }
284 _ => EncoderOperand::None,
285 }
286 }
287
288 #[must_use]
290 pub fn operand(&self, index: usize) -> Option<&EncoderOperand> {
291 if index < self.operand_count as usize {
292 Some(&self.operands[index])
293 } else {
294 None
295 }
296 }
297
298 pub fn operands(&self) -> impl Iterator<Item = &EncoderOperand> {
300 self.operands[..self.operand_count as usize].iter()
301 }
302
303 #[must_use]
305 pub const fn has_operands(&self) -> bool {
306 self.operand_count > 0
307 }
308
309 #[must_use]
311 pub const fn has_operand_size_override(&self) -> bool {
312 self.operand_size != 0
313 }
314
315 #[must_use]
317 pub const fn has_address_size_override(&self) -> bool {
318 self.address_size != 0
319 }
320
321 #[must_use]
323 pub fn has_memory_operand(&self) -> bool {
324 self.operands().any(|op| op.is_memory())
325 }
326
327 #[must_use]
329 pub fn has_immediate_operand(&self) -> bool {
330 self.operands().any(|op| op.is_immediate())
331 }
332
333 #[must_use]
335 pub fn has_relative_operand(&self) -> bool {
336 self.operands().any(|op| op.is_relative())
337 }
338
339 #[must_use]
341 pub fn has_zmm_operand(&self) -> bool {
342 self.operands().any(|op| {
343 if let EncoderOperand::Reg(reg) = op {
344 reg.is_zmm()
345 } else {
346 false
347 }
348 })
349 }
350
351 pub fn clear_operands(&mut self) {
353 self.operands = [EncoderOperand::None; MAX_ENCODER_OPERANDS];
354 self.operand_count = 0;
355 }
356}
357
358impl Default for EncoderRequest {
359 fn default() -> Self {
360 Self::new(Mnemonic::Invalid)
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn test_encoder_request_new() {
370 let request = EncoderRequest::new(Mnemonic::MOV);
371 assert_eq!(request.mnemonic, Mnemonic::MOV);
372 assert_eq!(request.operand_count, 0);
373 assert_eq!(request.operand_size, 0);
374 assert_eq!(request.address_size, 0);
375 assert!(request.preferred_encoding.is_none());
376 assert_eq!(request.branch_type, BranchType::None);
377 assert_eq!(request.branch_width, BranchWidth::None);
378 }
379
380 #[test]
381 fn test_encoder_request_with_reg() {
382 let request = EncoderRequest::new(Mnemonic::MOV)
383 .with_reg(Register::RAX)
384 .with_reg(Register::RBX);
385
386 assert_eq!(request.operand_count, 2);
387 assert!(request.operands[0].is_register());
388 assert!(request.operands[1].is_register());
389 assert_eq!(request.operands[0].as_register(), Some(Register::RAX));
390 assert_eq!(request.operands[1].as_register(), Some(Register::RBX));
391 }
392
393 #[test]
394 fn test_encoder_request_with_mem() {
395 let mem = MemoryOperand::base_disp(Register::RBP, -16);
396 let request = EncoderRequest::new(Mnemonic::MOV).with_mem(mem);
397
398 assert_eq!(request.operand_count, 1);
399 assert!(request.operands[0].is_memory());
400 }
401
402 #[test]
403 fn test_encoder_request_with_imm() {
404 let request = EncoderRequest::new(Mnemonic::MOV).with_imm(0x12345678);
405
406 assert_eq!(request.operand_count, 1);
407 assert!(request.operands[0].is_immediate());
408 assert_eq!(request.operands[0].as_immediate(), Some(0x12345678));
409 }
410
411 #[test]
412 fn test_encoder_request_with_rel() {
413 let request = EncoderRequest::new(Mnemonic::JMP).with_rel(-128);
414
415 assert_eq!(request.operand_count, 1);
416 assert!(request.operands[0].is_relative());
417 assert_eq!(request.operands[0].as_relative(), Some(-128));
418 }
419
420 #[test]
421 fn test_encoder_request_with_operand_size() {
422 let request = EncoderRequest::new(Mnemonic::MOV).with_operand_size(32);
423
424 assert_eq!(request.operand_size, 32);
425 assert!(request.has_operand_size_override());
426 }
427
428 #[test]
429 fn test_encoder_request_with_address_size() {
430 let request = EncoderRequest::new(Mnemonic::LEA).with_address_size(32);
431
432 assert_eq!(request.address_size, 32);
433 assert!(request.has_address_size_override());
434 }
435
436 #[test]
437 fn test_encoder_request_max_operands() {
438 let mut request = EncoderRequest::new(Mnemonic::MOV)
439 .with_reg(Register::RAX)
440 .with_reg(Register::RBX)
441 .with_reg(Register::RCX)
442 .with_reg(Register::RDX)
443 .with_reg(Register::RSI);
444
445 request = request.with_reg(Register::RDI);
447
448 assert_eq!(request.operand_count, 5);
449 assert!(request.operand(5).is_none());
450 }
451
452 #[test]
453 fn test_encoder_request_operands_iter() {
454 let request = EncoderRequest::new(Mnemonic::MOV)
455 .with_reg(Register::RAX)
456 .with_reg(Register::RBX);
457
458 let count = request.operands().count();
459 assert_eq!(count, 2);
460 }
461
462 #[test]
463 fn test_encoder_request_has_memory_operand() {
464 let mem = MemoryOperand::base(Register::RAX);
465 let request = EncoderRequest::new(Mnemonic::MOV).with_mem(mem);
466
467 assert!(request.has_memory_operand());
468 assert!(!request.has_immediate_operand());
469 }
470
471 #[test]
472 fn test_encoder_request_has_immediate_operand() {
473 let request = EncoderRequest::new(Mnemonic::MOV).with_imm(0x1234);
474
475 assert!(request.has_immediate_operand());
476 assert!(!request.has_memory_operand());
477 }
478
479 #[test]
480 fn test_encoder_request_clear_operands() {
481 let mut request = EncoderRequest::new(Mnemonic::MOV)
482 .with_reg(Register::RAX)
483 .with_reg(Register::RBX);
484
485 assert_eq!(request.operand_count, 2);
486
487 request.clear_operands();
488
489 assert_eq!(request.operand_count, 0);
490 assert!(!request.has_operands());
491 }
492
493 #[test]
494 fn test_encoder_request_default() {
495 let request = EncoderRequest::default();
496 assert_eq!(request.mnemonic, Mnemonic::Invalid);
497 assert_eq!(request.operand_count, 0);
498 assert!(request.mask_reg.is_none());
499 assert_eq!(request.zeroing_mode, EvexZeroingMode::Merging);
500 }
501
502 #[test]
503 fn test_encoder_request_with_mask() {
504 let request = EncoderRequest::new(Mnemonic::VADDPS).with_mask(Register::K1);
505
506 assert!(request.has_mask());
507 assert_eq!(request.mask_reg, Some(Register::K1));
508 assert!(!request.is_zeroing());
509 }
510
511 #[test]
512 fn test_encoder_request_with_zeroing() {
513 let request = EncoderRequest::new(Mnemonic::VADDPS)
514 .with_mask(Register::K1)
515 .with_zeroing_enabled();
516
517 assert!(request.has_mask());
518 assert!(request.is_zeroing());
519 assert_eq!(request.zeroing_mode, EvexZeroingMode::Zeroing);
520 }
521
522 #[test]
523 fn test_encoder_request_has_zmm_operand() {
524 let request = EncoderRequest::new(Mnemonic::VADDPS)
525 .with_reg(Register::ZMM1)
526 .with_reg(Register::ZMM2)
527 .with_reg(Register::ZMM3);
528
529 assert!(request.has_zmm_operand());
530
531 let request_xmm = EncoderRequest::new(Mnemonic::VADDPS)
532 .with_reg(Register::XMM1)
533 .with_reg(Register::XMM2)
534 .with_reg(Register::XMM3);
535
536 assert!(!request_xmm.has_zmm_operand());
537 }
538
539 #[test]
540 fn test_encoder_request_with_encoding() {
541 let request = EncoderRequest::new(Mnemonic::VADDPS).with_encoding(EncodableEncoding::Evex);
542
543 assert!(request.has_preferred_encoding());
544 assert_eq!(request.preferred_encoding, Some(EncodableEncoding::Evex));
545 }
546
547 #[test]
548 fn test_encoder_request_with_branch_type() {
549 let request = EncoderRequest::new(Mnemonic::JMP).with_branch_type(BranchType::Near);
550
551 assert!(request.has_branch_type());
552 assert_eq!(request.branch_type, BranchType::Near);
553 }
554
555 #[test]
556 fn test_encoder_request_with_broadcast() {
557 let request = EncoderRequest::new(Mnemonic::VADDPS).with_broadcast(BroadcastMode::To4);
558
559 assert!(request.has_broadcast());
560 assert_eq!(request.hints.broadcast_mode, BroadcastMode::To4);
561 }
562
563 #[test]
564 fn test_encoder_request_with_rounding() {
565 let request = EncoderRequest::new(Mnemonic::VADDPS).with_rounding(RoundingMode::RD);
566
567 assert!(request.has_rounding());
568 assert_eq!(request.hints.rounding_mode, Some(RoundingMode::RD));
569 }
570
571 #[test]
572 fn test_encoder_request_with_sae() {
573 let request = EncoderRequest::new(Mnemonic::VADDPS).with_sae();
574
575 assert!(request.has_sae());
576 }
577}