Skip to main content

native_v86_core/cpu/
string.rs

1// string operations
2//
3//       cmp  si  di
4// movs   0    1   1/w    A4
5// cmps   1    1   1/r    A6
6// stos   0    0   1/w    AA
7// lods   0    1   0      AC
8// scas   1    0   1/r    AE
9// ins    0    0   1/w
10// outs   0    1   0
11
12use crate::cpu::arith::{cmp16, cmp32, cmp8};
13use crate::cpu::cpu::{
14    get_seg, io_port_read16, io_port_read32, io_port_read8, io_port_write16, io_port_write32,
15    io_port_write8, read_reg16, read_reg32, safe_read16, safe_read32s, safe_read8, safe_write16,
16    safe_write32, safe_write8, set_reg_asize, test_privileges_for_io, translate_address_read,
17    translate_address_write_and_can_skip_dirty, writable_or_pagefault, write_reg16, write_reg32,
18    write_reg8, AL, AX, DX, EAX, ECX, EDI, ES, ESI, FLAG_DIRECTION,
19};
20use crate::cpu::global_pointers::{flags, instruction_pointer, previous_ip};
21use crate::cpu::memory;
22use crate::jit;
23use crate::page::Page;
24
25fn count_until_end_of_page(direction: i32, size: i32, addr: u32) -> u32 {
26    (if direction == 1 {
27        (0x1000 - (addr & 0xFFF)) / size as u32
28    } else {
29        (addr & 0xFFF) / size as u32 + 1
30    }) as u32
31}
32
33#[derive(Copy, Clone, PartialEq)]
34enum Instruction {
35    Movs,
36    Lods,
37    Stos,
38    Scas,
39    Cmps,
40    Ins,
41    Outs,
42}
43#[derive(PartialEq)]
44enum Size {
45    B,
46    W,
47    D,
48}
49#[derive(Copy, Clone)]
50enum Rep {
51    None,
52    Z,
53    NZ,
54}
55
56// We implement all string instructions here and rely on the inliner on doing its job of optimising
57// away anything known at compile time (check with `wasm-dis build/v86.wasm`)
58#[inline(always)]
59unsafe fn string_instruction(
60    is_asize_32: bool,
61    ds_or_prefix: i32,
62    instruction: Instruction,
63    size: Size,
64    rep: Rep,
65) {
66    let asize_mask = if is_asize_32 { -1 } else { 0xFFFF };
67
68    let direction = if 0 != *flags & FLAG_DIRECTION { -1 } else { 1 };
69
70    let mut count = match rep {
71        Rep::Z | Rep::NZ => {
72            let c = (read_reg32(ECX) & asize_mask) as u32;
73            if c == 0 {
74                return;
75            };
76            c
77        }
78        Rep::None => 0,
79    };
80
81    let es = match instruction {
82        Instruction::Movs
83        | Instruction::Cmps
84        | Instruction::Stos
85        | Instruction::Scas
86        | Instruction::Ins => return_on_pagefault!(get_seg(ES)),
87        _ => 0,
88    };
89    let ds = match instruction {
90        Instruction::Movs
91        | Instruction::Cmps
92        | Instruction::Lods
93        | Instruction::Scas
94        | Instruction::Outs => return_on_pagefault!(get_seg(ds_or_prefix)),
95        _ => 0,
96    };
97
98    let size_bytes = match size {
99        Size::B => 1,
100        Size::W => 2,
101        Size::D => 4,
102    };
103    let size_mask = match size {
104        Size::B => 0xFF,
105        Size::W => 0xFFFF,
106        Size::D => -1,
107    };
108
109    let increment = direction * size_bytes;
110
111    let data = match instruction {
112        Instruction::Stos | Instruction::Scas => read_reg32(EAX),
113        _ => 0,
114    };
115
116    let mut src = match instruction {
117        Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
118            read_reg32(ESI) & asize_mask
119        }
120        _ => 0,
121    };
122    let mut dst = match instruction {
123        Instruction::Movs
124        | Instruction::Cmps
125        | Instruction::Stos
126        | Instruction::Scas
127        | Instruction::Ins => read_reg32(EDI) & asize_mask,
128        _ => 0,
129    };
130
131    let port = match instruction {
132        Instruction::Ins | Instruction::Outs => {
133            let port = read_reg16(DX);
134            if !test_privileges_for_io(port, size_bytes) {
135                return;
136            }
137            port
138        }
139        _ => 0,
140    };
141
142    let is_aligned = (ds + src) & (size_bytes - 1) == 0 && (es + dst) & (size_bytes - 1) == 0;
143
144    // unaligned movs is properly handled in the fast path
145    let mut rep_fast = (instruction == Instruction::Movs || is_aligned)
146        && is_asize_32 // 16-bit address wraparound
147        && match rep {
148            Rep::NZ | Rep::Z => true,
149            Rep::None => false,
150        };
151
152    let mut phys_dst = 0;
153    let mut phys_src = 0;
154    let mut skip_dirty_page = false;
155
156    let mut movs_into_svga_lfb = false;
157    let mut movs_reenter_fast_path = false;
158
159    let count_until_end_of_page = if rep_fast {
160        match instruction {
161            Instruction::Movs => {
162                let (addr, skip) =
163                    return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
164                movs_into_svga_lfb = memory::in_svga_lfb(addr);
165                rep_fast = rep_fast && (!memory::in_mapped_range(addr) || movs_into_svga_lfb);
166                phys_dst = addr;
167                skip_dirty_page = skip;
168            }
169            Instruction::Stos | Instruction::Ins => {
170                let (addr, skip) =
171                    return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
172                rep_fast = rep_fast && !memory::in_mapped_range(addr);
173                phys_dst = addr;
174                skip_dirty_page = skip;
175            }
176            Instruction::Cmps | Instruction::Scas => {
177                let addr = return_on_pagefault!(translate_address_read(es + dst));
178                rep_fast = rep_fast && !memory::in_mapped_range(addr);
179                phys_dst = addr;
180                skip_dirty_page = true;
181            }
182            _ => {}
183        };
184
185        match instruction {
186            Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
187                let addr = return_on_pagefault!(translate_address_read(ds + src));
188                rep_fast = rep_fast && !memory::in_mapped_range(addr);
189                phys_src = addr;
190            }
191            _ => {}
192        };
193
194        let count_until_end_of_page = u32::min(
195            count,
196            match instruction {
197                Instruction::Movs | Instruction::Cmps => u32::min(
198                    count_until_end_of_page(direction, size_bytes, phys_src),
199                    count_until_end_of_page(direction, size_bytes, phys_dst),
200                ),
201                Instruction::Stos | Instruction::Ins | Instruction::Scas => {
202                    count_until_end_of_page(direction, size_bytes, phys_dst)
203                }
204                Instruction::Lods | Instruction::Outs => {
205                    count_until_end_of_page(direction, size_bytes, phys_src)
206                }
207            },
208        );
209
210        match instruction {
211            Instruction::Movs => {
212                let c = count_until_end_of_page * size_bytes as u32;
213
214                let overlap_interferes = if phys_src < phys_dst {
215                    // backward moves may overlap at the front of the destination string
216                    phys_dst - phys_src < c && direction == 1
217                } else if phys_src > phys_dst {
218                    // forward moves may overlap at the front of the source string
219                    phys_src - phys_dst < c && direction == -1
220                } else {
221                    false
222                };
223                rep_fast = rep_fast && !overlap_interferes;
224
225                // In case the following page-boundary check fails, re-enter instruction after
226                // one iteration of the slow path
227                movs_reenter_fast_path = rep_fast;
228                rep_fast = rep_fast
229                    && (phys_src & 0xFFF <= 0x1000 - size_bytes as u32)
230                    && (phys_dst & 0xFFF <= 0x1000 - size_bytes as u32);
231            }
232            _ => {}
233        }
234
235        count_until_end_of_page
236    } else {
237        0 // not used
238    };
239
240    if rep_fast {
241        dbg_assert!(count_until_end_of_page > 0);
242
243        if !skip_dirty_page {
244            jit::jit_dirty_page(Page::page_of(phys_dst));
245        }
246
247        let mut rep_cmp_finished = false;
248
249        let mut i = 0;
250        while i < count_until_end_of_page {
251            i += 1;
252
253            let src_val = match instruction {
254                Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
255                    match size {
256                        Size::B => memory::read8_no_mmap_check(phys_src),
257                        Size::W => memory::read16_no_mmap_check(phys_src),
258                        Size::D => memory::read32_no_mmap_check(phys_src),
259                    }
260                }
261                Instruction::Scas | Instruction::Stos => data & size_mask,
262                Instruction::Ins => match size {
263                    Size::B => io_port_read8(port),
264                    Size::W => io_port_read16(port),
265                    Size::D => io_port_read32(port),
266                },
267            };
268
269            let mut dst_val = 0;
270
271            match instruction {
272                Instruction::Cmps | Instruction::Scas => match size {
273                    Size::B => dst_val = memory::read8_no_mmap_check(phys_dst),
274                    Size::W => dst_val = memory::read16_no_mmap_check(phys_dst),
275                    Size::D => dst_val = memory::read32_no_mmap_check(phys_dst),
276                },
277                Instruction::Outs => match size {
278                    Size::B => io_port_write8(port, src_val),
279                    Size::W => io_port_write16(port, src_val),
280                    Size::D => io_port_write32(port, src_val),
281                },
282                Instruction::Lods => match size {
283                    Size::B => write_reg8(AL, src_val),
284                    Size::W => write_reg16(AX, src_val),
285                    Size::D => write_reg32(EAX, src_val),
286                },
287                Instruction::Ins => match size {
288                    Size::B => memory::write8_no_mmap_or_dirty_check(phys_dst, src_val),
289                    Size::W => memory::write16_no_mmap_or_dirty_check(phys_dst, src_val),
290                    Size::D => memory::write32_no_mmap_or_dirty_check(phys_dst, src_val),
291                },
292                Instruction::Movs => {
293                    if direction == -1 {
294                        phys_src -= (count_until_end_of_page - 1) * size_bytes as u32;
295                        phys_dst -= (count_until_end_of_page - 1) * size_bytes as u32;
296                    }
297                    if movs_into_svga_lfb {
298                        memory::memcpy_into_svga_lfb(
299                            phys_src,
300                            phys_dst,
301                            count_until_end_of_page * size_bytes as u32,
302                        );
303                    } else {
304                        memory::memcpy_no_mmap_or_dirty_check(
305                            phys_src,
306                            phys_dst,
307                            count_until_end_of_page * size_bytes as u32,
308                        );
309                    }
310                    i = count_until_end_of_page;
311                    break;
312                }
313                Instruction::Stos => match size {
314                    Size::B => {
315                        if direction == -1 {
316                            phys_dst -= count_until_end_of_page - 1
317                        }
318                        memory::memset_no_mmap_or_dirty_check(
319                            phys_dst,
320                            src_val as u8,
321                            count_until_end_of_page,
322                        );
323                        i = count_until_end_of_page;
324                        break;
325                    }
326                    Size::W => memory::write16_no_mmap_or_dirty_check(phys_dst, src_val),
327                    Size::D => memory::write32_no_mmap_or_dirty_check(phys_dst, src_val),
328                },
329            };
330
331            match instruction {
332                Instruction::Movs
333                | Instruction::Cmps
334                | Instruction::Stos
335                | Instruction::Scas
336                | Instruction::Ins => {
337                    phys_dst += increment as u32;
338                }
339                _ => {}
340            }
341            match instruction {
342                Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
343                    phys_src += increment as u32;
344                }
345                _ => {}
346            };
347
348            match instruction {
349                Instruction::Scas | Instruction::Cmps => {
350                    let rep_cmp = match rep {
351                        Rep::Z => src_val == dst_val,
352                        Rep::NZ => src_val != dst_val,
353                        Rep::None => {
354                            dbg_assert!(false);
355                            true
356                        }
357                    };
358                    if !rep_cmp || count == i {
359                        match size {
360                            Size::B => cmp8(src_val, dst_val),
361                            Size::W => cmp16(src_val, dst_val),
362                            Size::D => cmp32(src_val, dst_val),
363                        };
364                        rep_cmp_finished = true;
365                        break;
366                    }
367                }
368                _ => {}
369            }
370        }
371
372        dbg_assert!(i <= count);
373        count -= i;
374
375        if !rep_cmp_finished && count != 0 {
376            // go back to the current instruction, since this loop just handles a single page
377            *instruction_pointer = *previous_ip;
378        }
379
380        src += i as i32 * increment;
381        dst += i as i32 * increment;
382    } else {
383        loop {
384            match instruction {
385                Instruction::Ins => {
386                    // check fault *before* reading from port
387                    // (technically not necessary according to Intel manuals)
388                    break_on_pagefault!(writable_or_pagefault(es + dst, size_bytes));
389                }
390                _ => {}
391            };
392            let src_val = match instruction {
393                Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
394                    break_on_pagefault!(match size {
395                        Size::B => safe_read8(ds + src),
396                        Size::W => safe_read16(ds + src),
397                        Size::D => safe_read32s(ds + src),
398                    })
399                }
400                Instruction::Scas | Instruction::Stos => data & size_mask,
401                Instruction::Ins => match size {
402                    Size::B => io_port_read8(port),
403                    Size::W => io_port_read16(port),
404                    Size::D => io_port_read32(port),
405                },
406            };
407
408            let mut dst_val = 0;
409
410            match instruction {
411                Instruction::Cmps | Instruction::Scas => match size {
412                    Size::B => dst_val = break_on_pagefault!(safe_read8(es + dst)),
413                    Size::W => dst_val = break_on_pagefault!(safe_read16(es + dst)),
414                    Size::D => dst_val = break_on_pagefault!(safe_read32s(es + dst)),
415                },
416                Instruction::Outs => match size {
417                    Size::B => io_port_write8(port, src_val),
418                    Size::W => io_port_write16(port, src_val),
419                    Size::D => io_port_write32(port, src_val),
420                },
421                Instruction::Lods => match size {
422                    Size::B => write_reg8(AL, src_val),
423                    Size::W => write_reg16(AX, src_val),
424                    Size::D => write_reg32(EAX, src_val),
425                },
426                Instruction::Movs | Instruction::Stos | Instruction::Ins => match size {
427                    Size::B => break_on_pagefault!(safe_write8(es + dst, src_val)),
428                    Size::W => break_on_pagefault!(safe_write16(es + dst, src_val)),
429                    Size::D => break_on_pagefault!(safe_write32(es + dst, src_val)),
430                },
431            };
432
433            match instruction {
434                Instruction::Movs
435                | Instruction::Cmps
436                | Instruction::Stos
437                | Instruction::Scas
438                | Instruction::Ins => dst = dst + increment & asize_mask,
439                _ => {}
440            }
441            match instruction {
442                Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
443                    src = src + increment & asize_mask
444                }
445                _ => {}
446            };
447
448            count -= 1;
449
450            let finished = match rep {
451                Rep::Z | Rep::NZ => match (rep, instruction) {
452                    (Rep::Z, Instruction::Cmps) => src_val != dst_val || count == 0,
453                    (Rep::Z, Instruction::Scas) => src_val != dst_val || count == 0,
454                    (Rep::NZ, Instruction::Cmps) => src_val == dst_val || count == 0,
455                    (Rep::NZ, Instruction::Scas) => src_val == dst_val || count == 0,
456                    (Rep::NZ | Rep::Z, Instruction::Movs) => {
457                        if count == 0 {
458                            true
459                        } else if movs_reenter_fast_path {
460                            *instruction_pointer = *previous_ip;
461                            true
462                        } else {
463                            false
464                        }
465                    }
466                    _ => count == 0,
467                },
468                Rep::None => true,
469            };
470
471            if finished {
472                match instruction {
473                    Instruction::Scas | Instruction::Cmps => match size {
474                        Size::B => cmp8(src_val, dst_val),
475                        Size::W => cmp16(src_val, dst_val),
476                        Size::D => cmp32(src_val, dst_val),
477                    },
478                    _ => {}
479                }
480                break;
481            }
482        }
483    }
484
485    match instruction {
486        Instruction::Movs
487        | Instruction::Cmps
488        | Instruction::Stos
489        | Instruction::Scas
490        | Instruction::Ins => set_reg_asize(is_asize_32, EDI, dst),
491        _ => {}
492    }
493    match instruction {
494        Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
495            set_reg_asize(is_asize_32, ESI, src)
496        }
497        _ => {}
498    };
499
500    match rep {
501        Rep::Z | Rep::NZ => {
502            set_reg_asize(is_asize_32, ECX, count as i32);
503        }
504        Rep::None => {}
505    }
506}
507
508#[no_mangle]
509pub unsafe fn movsb_rep(is_asize_32: bool, seg: i32) {
510    string_instruction(is_asize_32, seg, Instruction::Movs, Size::B, Rep::Z)
511}
512#[no_mangle]
513pub unsafe fn movsw_rep(is_asize_32: bool, seg: i32) {
514    string_instruction(is_asize_32, seg, Instruction::Movs, Size::W, Rep::Z)
515}
516#[no_mangle]
517pub unsafe fn movsd_rep(is_asize_32: bool, seg: i32) {
518    string_instruction(is_asize_32, seg, Instruction::Movs, Size::D, Rep::Z)
519}
520pub unsafe fn movsb_no_rep(is_asize_32: bool, seg: i32) {
521    string_instruction(is_asize_32, seg, Instruction::Movs, Size::B, Rep::None)
522}
523pub unsafe fn movsw_no_rep(is_asize_32: bool, seg: i32) {
524    string_instruction(is_asize_32, seg, Instruction::Movs, Size::W, Rep::None)
525}
526pub unsafe fn movsd_no_rep(is_asize_32: bool, seg: i32) {
527    string_instruction(is_asize_32, seg, Instruction::Movs, Size::D, Rep::None)
528}
529
530#[no_mangle]
531pub unsafe fn lodsb_rep(is_asize_32: bool, seg: i32) {
532    string_instruction(is_asize_32, seg, Instruction::Lods, Size::B, Rep::Z)
533}
534#[no_mangle]
535pub unsafe fn lodsw_rep(is_asize_32: bool, seg: i32) {
536    string_instruction(is_asize_32, seg, Instruction::Lods, Size::W, Rep::Z)
537}
538#[no_mangle]
539pub unsafe fn lodsd_rep(is_asize_32: bool, seg: i32) {
540    string_instruction(is_asize_32, seg, Instruction::Lods, Size::D, Rep::Z)
541}
542pub unsafe fn lodsb_no_rep(is_asize_32: bool, seg: i32) {
543    string_instruction(is_asize_32, seg, Instruction::Lods, Size::B, Rep::None)
544}
545pub unsafe fn lodsw_no_rep(is_asize_32: bool, seg: i32) {
546    string_instruction(is_asize_32, seg, Instruction::Lods, Size::W, Rep::None)
547}
548pub unsafe fn lodsd_no_rep(is_asize_32: bool, seg: i32) {
549    string_instruction(is_asize_32, seg, Instruction::Lods, Size::D, Rep::None)
550}
551
552#[no_mangle]
553pub unsafe fn stosb_rep(is_asize_32: bool) {
554    string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::Z)
555}
556#[no_mangle]
557pub unsafe fn stosw_rep(is_asize_32: bool) {
558    string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::Z)
559}
560#[no_mangle]
561pub unsafe fn stosd_rep(is_asize_32: bool) {
562    string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::Z)
563}
564pub unsafe fn stosb_no_rep(is_asize_32: bool) {
565    string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::None)
566}
567pub unsafe fn stosw_no_rep(is_asize_32: bool) {
568    string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::None)
569}
570pub unsafe fn stosd_no_rep(is_asize_32: bool) {
571    string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::None)
572}
573
574#[no_mangle]
575pub unsafe fn cmpsb_repz(is_asize_32: bool, seg: i32) {
576    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::Z)
577}
578#[no_mangle]
579pub unsafe fn cmpsw_repz(is_asize_32: bool, seg: i32) {
580    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::Z)
581}
582#[no_mangle]
583pub unsafe fn cmpsd_repz(is_asize_32: bool, seg: i32) {
584    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::Z)
585}
586#[no_mangle]
587pub unsafe fn cmpsb_repnz(is_asize_32: bool, seg: i32) {
588    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::NZ)
589}
590#[no_mangle]
591pub unsafe fn cmpsw_repnz(is_asize_32: bool, seg: i32) {
592    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::NZ)
593}
594#[no_mangle]
595pub unsafe fn cmpsd_repnz(is_asize_32: bool, seg: i32) {
596    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::NZ)
597}
598#[no_mangle]
599pub unsafe fn cmpsb_no_rep(is_asize_32: bool, seg: i32) {
600    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::None)
601}
602#[no_mangle]
603pub unsafe fn cmpsw_no_rep(is_asize_32: bool, seg: i32) {
604    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::None)
605}
606#[no_mangle]
607pub unsafe fn cmpsd_no_rep(is_asize_32: bool, seg: i32) {
608    string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::None)
609}
610
611#[no_mangle]
612pub unsafe fn scasb_repz(is_asize_32: bool) {
613    string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::Z)
614}
615#[no_mangle]
616pub unsafe fn scasw_repz(is_asize_32: bool) {
617    string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::Z)
618}
619#[no_mangle]
620pub unsafe fn scasd_repz(is_asize_32: bool) {
621    string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::Z)
622}
623#[no_mangle]
624pub unsafe fn scasb_repnz(is_asize_32: bool) {
625    string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::NZ)
626}
627#[no_mangle]
628pub unsafe fn scasw_repnz(is_asize_32: bool) {
629    string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::NZ)
630}
631#[no_mangle]
632pub unsafe fn scasd_repnz(is_asize_32: bool) {
633    string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::NZ)
634}
635pub unsafe fn scasb_no_rep(is_asize_32: bool) {
636    string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::None)
637}
638pub unsafe fn scasw_no_rep(is_asize_32: bool) {
639    string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::None)
640}
641pub unsafe fn scasd_no_rep(is_asize_32: bool) {
642    string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::None)
643}
644
645#[no_mangle]
646pub unsafe fn outsb_rep(is_asize_32: bool, seg: i32) {
647    string_instruction(is_asize_32, seg, Instruction::Outs, Size::B, Rep::Z)
648}
649#[no_mangle]
650pub unsafe fn outsw_rep(is_asize_32: bool, seg: i32) {
651    string_instruction(is_asize_32, seg, Instruction::Outs, Size::W, Rep::Z)
652}
653#[no_mangle]
654pub unsafe fn outsd_rep(is_asize_32: bool, seg: i32) {
655    string_instruction(is_asize_32, seg, Instruction::Outs, Size::D, Rep::Z)
656}
657#[no_mangle]
658pub unsafe fn outsb_no_rep(is_asize_32: bool, seg: i32) {
659    string_instruction(is_asize_32, seg, Instruction::Outs, Size::B, Rep::None)
660}
661#[no_mangle]
662pub unsafe fn outsw_no_rep(is_asize_32: bool, seg: i32) {
663    string_instruction(is_asize_32, seg, Instruction::Outs, Size::W, Rep::None)
664}
665#[no_mangle]
666pub unsafe fn outsd_no_rep(is_asize_32: bool, seg: i32) {
667    string_instruction(is_asize_32, seg, Instruction::Outs, Size::D, Rep::None)
668}
669
670#[no_mangle]
671pub unsafe fn insb_rep(is_asize_32: bool) {
672    string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::Z)
673}
674#[no_mangle]
675pub unsafe fn insw_rep(is_asize_32: bool) {
676    string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::Z)
677}
678#[no_mangle]
679pub unsafe fn insd_rep(is_asize_32: bool) {
680    string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::Z)
681}
682#[no_mangle]
683pub unsafe fn insb_no_rep(is_asize_32: bool) {
684    string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::None)
685}
686#[no_mangle]
687pub unsafe fn insw_no_rep(is_asize_32: bool) {
688    string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::None)
689}
690#[no_mangle]
691pub unsafe fn insd_no_rep(is_asize_32: bool) {
692    string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::None)
693}