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