qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images
@ 2019-06-19  5:04 Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
                   ` (6 more replies)
  0 siblings, 7 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

Hi all,

this is v1 of my changes to risugen in order to support generating x86
test images. It's still work-in-progress (thus marked RFC; notably,
there is no support for AVX yet), but I would like to get this out
there to get some early feedback on my approach.

Initially, I thought adding support for arbitrarily-long instructions
would be more or less enough for x86, but unfortunately this turned
out not to be the case; the length variation introduced by ModR/M, SIB
and displacement fields would force us to have to have at least 6
config file entries per almost every instruction, which is pretty much
unmaintainable. Instead, I drew inspiration from the "memory" blocks
in arm.risu for specifying memory constraints, and introduced "emit"
blocks for x86. Example x86 config file with SSE and SSE2 instructions
can be found in the last two commits, let me know what you think.

There are still some limitations -- besides missing (E)VEX support,
some forms of ModR/M are also not supported (mostly because it's hard
or impossible to figure out and use the correct memory address), and
the LDMXCSR instruction is currently commented out because there's no
way to specify constraints on memory contents. However, this patch
series should have enough code to demonstrate my intended general
approach, and that's what I am looking for feedback for.

Best,
 -Jan

Jan Bobek (7):
  risugen_common: add insnv, randint_constr, rand_fill
  risugen_x86_asm: add module
  risugen_x86_emit: add module
  risugen_x86: add module
  risugen: allow all byte-aligned instructions
  x86.risu: add SSE instructions
  x86.risu: add SSE2 instructions

 risugen             |  15 +-
 risugen_common.pm   | 101 +++++++++-
 risugen_x86.pm      | 455 ++++++++++++++++++++++++++++++++++++++++++++
 risugen_x86_asm.pm  | 186 ++++++++++++++++++
 risugen_x86_emit.pm |  85 +++++++++
 x86.risu            | 245 ++++++++++++++++++++++++
 6 files changed, 1075 insertions(+), 12 deletions(-)
 create mode 100644 risugen_x86.pm
 create mode 100644 risugen_x86_asm.pm
 create mode 100644 risugen_x86_emit.pm
 create mode 100644 x86.risu

-- 
2.20.1



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-27  8:53   ` Richard Henderson
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module Jan Bobek
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

Add three common utility functions:

- insnv allows emitting variable-length instructions in little-endian
  or big-endian byte order; it subsumes functionality of former
  insn16() and insn32() functions.

- randint_constr allows generating random integers according to
  several constraints passed as arguments.

- rand_fill uses randint_constr to fill a given hash with
  (optionally constrained) random values.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen_common.pm | 101 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 95 insertions(+), 6 deletions(-)

diff --git a/risugen_common.pm b/risugen_common.pm
index 71ee996..98b9170 100644
--- a/risugen_common.pm
+++ b/risugen_common.pm
@@ -23,7 +23,8 @@ BEGIN {
     require Exporter;
 
     our @ISA = qw(Exporter);
-    our @EXPORT = qw(open_bin close_bin set_endian insn32 insn16 $bytecount
+    our @EXPORT = qw(open_bin close_bin set_endian insn32 insn16
+                   $bytecount insnv randint_constr rand_fill
                    progress_start progress_update progress_end
                    eval_with_fields is_pow_of_2 sextract ctz
                    dump_insn_details);
@@ -37,7 +38,7 @@ my $bigendian = 0;
 # (default is little endian, 0).
 sub set_endian
 {
-    $bigendian = @_;
+    ($bigendian) = @_;
 }
 
 sub open_bin
@@ -52,18 +53,106 @@ sub close_bin
     close(BIN) or die "can't close output file: $!";
 }
 
+sub insnv(%)
+{
+    my (%args) = @_;
+
+    # Default to big-endian order, so that the instruction bytes are
+    # emitted in the same order as they are written in the
+    # configuration file.
+    $args{bigendian} = 1 unless defined $args{bigendian};
+
+    while (0 < $args{len}) {
+        my $format;
+        my $len;
+
+        if ($args{len} >= 8) {
+            $format = "Q";
+            $len = 8;
+        } elsif ($args{len} >= 4) {
+            $format = "L";
+            $len = 4;
+        } elsif ($args{len} >= 2) {
+            $format = "S";
+            $len = 2;
+        } else {
+            $format = "C";
+            $len = 1;
+        }
+
+        $format .= ($args{bigendian} ? ">" : "<") if $len > 1;
+
+        my $bitlen = 8 * $len;
+        my $bitmask = (1 << $bitlen) - 1;
+        my $value = ($args{bigendian}
+                     ? ($args{value} >> (8 * $args{len} - $bitlen))
+                     : $args{value});
+
+        print BIN pack($format, $value & $bitmask);
+        $bytecount += $len;
+
+        $args{len} -= $len;
+        $args{value} >>= $bitlen unless $args{bigendian};
+    }
+}
+
 sub insn32($)
 {
     my ($insn) = @_;
-    print BIN pack($bigendian ? "N" : "V", $insn);
-    $bytecount += 4;
+    insnv(value => $insn, len => 4, bigendian => $bigendian);
 }
 
 sub insn16($)
 {
     my ($insn) = @_;
-    print BIN pack($bigendian ? "n" : "v", $insn);
-    $bytecount += 2;
+    insnv(value => $insn, len => 2, bigendian => $bigendian);
+}
+
+sub randint_constr(%)
+{
+    my (%args) = @_;
+    my $bitlen = $args{bitlen};
+    my $halfrange = 1 << ($bitlen - 1);
+
+    while (1) {
+        my $value = int(rand(2 * $halfrange));
+        $value -= $halfrange if defined $args{signed} && $args{signed};
+        $value &= ~$args{fixedbitmask} if defined $args{fixedbitmask};
+        $value |= $args{fixedbits} if defined $args{fixedbits};
+
+        if (defined $args{constraint}) {
+            if (!($args{constraint} >> 63)) {
+                $value = $args{constraint};
+            } elsif ($value == ~$args{constraint}) {
+                next;
+            }
+        }
+
+        return $value;
+    }
+}
+
+sub rand_fill($$)
+{
+    my ($target, $constraints) = @_;
+
+    for (keys %{$target}) {
+        my %args = (bitlen => $target->{$_}{bitlen});
+
+        $args{fixedbits} = $target->{$_}{fixedbits}
+            if defined $target->{$_}{fixedbits};
+        $args{fixedbitmask} = $target->{$_}{fixedbitmask}
+            if defined $target->{$_}{fixedbitmask};
+        $args{signed} = $target->{$_}{signed}
+            if defined $target->{$_}{signed};
+
+        $args{constraint} = $constraints->{$_}
+            if defined $constraints->{$_};
+
+        $target->{$_} = randint_constr(%args);
+    }
+
+    return $target;
 }
 
 # Progress bar implementation
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-27  9:05   ` Richard Henderson
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 3/7] risugen_x86_emit: " Jan Bobek
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

The module risugen_x86_asm.pm exports several constants and the
function write_insn, which work in tandem to allow emission of x86
instructions in more clear and structured manner.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen_x86_asm.pm | 186 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 186 insertions(+)
 create mode 100644 risugen_x86_asm.pm

diff --git a/risugen_x86_asm.pm b/risugen_x86_asm.pm
new file mode 100644
index 0000000..b10d3e7
--- /dev/null
+++ b/risugen_x86_asm.pm
@@ -0,0 +1,186 @@
+#!/usr/bin/perl -w
+###############################################################################
+# Copyright (c) 2019 Linaro Limited
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Jan Bobek - initial implementation
+###############################################################################
+
+# risugen_x86_asm -- risugen_x86's helper module for x86 assembly
+package risugen_x86_asm;
+
+use strict;
+use warnings;
+
+use risugen_common;
+
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(
+    write_insn
+    REG_EAX REG_ECX REG_EDX REG_EBX REG_ESP REG_EBP REG_ESI REG_EDI
+    MOD_INDIRECT MOD_INDIRECT_DISP8 MOD_INDIRECT_DISP32 MOD_DIRECT
+    X86PFX_DATA16 X86PFX_REPNE X86PFX_REP
+    X86OP_LEA X86OP_XOR X86OP_ALU_imm8 X86OP_MOV X86OP_SAHF X86OP_CALL
+    X86OP_JMP X86OP_UD1 X86OP_MOVAPS
+    );
+
+use constant {
+    REG_EAX => 0,
+    REG_ECX => 1,
+    REG_EDX => 2,
+    REG_EBX => 3,
+    REG_ESP => 4,
+    REG_EBP => 5,
+    REG_ESI => 6,
+    REG_EDI => 7,
+
+    MOD_INDIRECT        => 0b00,
+    MOD_INDIRECT_DISP8  => 0b01,
+    MOD_INDIRECT_DISP32 => 0b10,
+    MOD_DIRECT          => 0b11,
+
+    X86PFX_DATA16 => {value => 0x66, len => 1},
+    X86PFX_REPNE  => {value => 0xF2, len => 1},
+    X86PFX_REP    => {value => 0xF3, len => 1},
+
+    X86OP_LEA      => {value => 0x8D, len => 1},
+    X86OP_XOR      => {value => 0x33, len => 1},
+    X86OP_ALU_imm8 => {value => 0x83, len => 1},
+    X86OP_MOV      => {value => 0x8B, len => 1},
+    X86OP_SAHF     => {value => 0x9E, len => 1},
+    X86OP_CALL     => {value => 0xE8, len => 1},
+    X86OP_JMP      => {value => 0xE9, len => 1},
+
+    X86OP_UD1      => {value => 0x0FB9, len => 2},
+    X86OP_MOVAPS   => {value => 0x0F28, len => 2},
+};
+
+sub rex_encode(%)
+{
+    my (%args) = @_;
+
+    $args{w} = 0 unless defined $args{w};
+    $args{r} = 0 unless defined $args{w};
+    $args{x} = 0 unless defined $args{w};
+    $args{b} = 0 unless defined $args{w};
+
+    return (value => 0x40
+            | (($args{w} ? 1 : 0) << 3)
+            | (($args{r} ? 1 : 0) << 2)
+            | (($args{x} ? 1 : 0) << 1)
+            | ($args{b} ? 1 : 0),
+            len => 1);
+}
+
+sub modrm_encode(%)
+{
+    my (%args) = @_;
+
+    die "MOD field out-of-range: $args{mod}"
+        unless 0 <= $args{mod} && $args{mod} <= 3;
+    die "REG field out-of-range: $args{reg}"
+        unless 0 <= $args{reg} && $args{reg} <= 7;
+    die "RM field out-of-range: $args{rm}"
+        unless 0 <= $args{rm} && $args{rm} <= 7;
+
+    return (value =>
+            ($args{mod} << 6)
+            | ($args{reg} << 3)
+            | $args{rm},
+            len => 1);
+}
+
+sub sib_encode(%)
+{
+    my (%args) = @_;
+
+    die "SS field out-of-range: $args{ss}"
+        unless 0 <= $args{ss} && $args{ss} <= 3;
+    die "INDEX field out-of-range: $args{index}"
+        unless 0 <= $args{index} && $args{index} <= 7;
+    die "BASE field out-of-range: $args{base}"
+        unless 0 <= $args{base} && $args{base} <= 7;
+
+    return (value =>
+            ($args{ss} << 6)
+            | ($args{index} << 3)
+            | $args{base},
+            len => 1);
+}
+
+sub write_insn(%)
+{
+    my (%insn) = @_;
+
+    my @tokens;
+    push @tokens, "EVEX"   if defined $insn{evex};
+    push @tokens, "VEX"    if defined $insn{vex};
+    push @tokens, "REP"    if defined $insn{rep};
+    push @tokens, "REPNE"  if defined $insn{repne};
+    push @tokens, "DATA16" if defined $insn{data16};
+    push @tokens, "REX"    if defined $insn{rex};
+    push @tokens, "OP"     if defined $insn{opcode};
+    push @tokens, "MODRM"  if defined $insn{modrm};
+    push @tokens, "SIB"    if defined $insn{sib};
+    push @tokens, "DISP"   if defined $insn{disp};
+    push @tokens, "IMM"    if defined $insn{imm};
+    push @tokens, "END";
+
+    # (EVEX | VEX | ((REP | REPNE)? DATA16? REX?)) OP (MODRM SIB? DISP?)? IMM? END
+
+    my $token = shift @tokens;
+    if ($token eq "EVEX") {
+        insnv(evex_encode(%{$insn{evex}}));
+        $token = shift @tokens;
+    } elsif ($token eq "VEX") {
+        insnv(vex_encode(%{$insn{vex}}));
+        $token = shift @tokens;
+    } else {
+        if ($token eq "REP") {
+            insnv(%{&X86PFX_REP});
+            $token = shift @tokens;
+        } elsif ($token eq "REPNE") {
+            insnv(%{&X86PFX_REPNE});
+            $token = shift @tokens;
+        }
+        if ($token eq "DATA16") {
+            insnv(%{&X86PFX_DATA16});
+            $token = shift @tokens;
+        }
+        if ($token eq "REX") {
+            insnv(rex_encode(%{$insn{rex}}));
+            $token = shift @tokens;
+        }
+    }
+
+    die "Unexpected instruction tokens where OP expected: $token @tokens\n"
+        unless $token eq "OP";
+
+    insnv(%{$insn{opcode}});
+    $token = shift @tokens;
+
+    if ($token eq "MODRM") {
+        insnv(modrm_encode(%{$insn{modrm}}));
+        $token = shift @tokens;
+
+        if ($token eq "SIB") {
+            insnv(sib_encode(%{$insn{sib}}));
+            $token = shift @tokens;
+        }
+        if ($token eq "DISP") {
+            insnv(%{$insn{disp}}, bigendian => 0);
+            $token = shift @tokens;
+        }
+    }
+    if ($token eq "IMM") {
+        insnv(%{$insn{imm}}, bigendian => 0);
+        $token = shift @tokens;
+    }
+
+    die "Unexpected junk tokens at the end of instruction: $token @tokens\n"
+        unless $token eq "END";
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 3/7] risugen_x86_emit: add module
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: " Jan Bobek
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

The helper module risugen_x86_emit.pm exports a single function
"parse_emitblock", which serves to capture and return instruction
constraints described by "emit" blocks in an x86 configuration file.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen             |  2 +-
 risugen_x86_emit.pm | 85 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)
 create mode 100644 risugen_x86_emit.pm

diff --git a/risugen b/risugen
index e690b18..fe3d00e 100755
--- a/risugen
+++ b/risugen
@@ -43,7 +43,7 @@ my @pattern_re = ();            # include pattern
 my @not_pattern_re = ();        # exclude pattern
 
 # Valid block names (keys in blocks hash)
-my %valid_blockname = ( constraints => 1, memory => 1 );
+my %valid_blockname = ( constraints => 1, memory => 1, emit => 1 );
 
 sub parse_risu_directive($$@)
 {
diff --git a/risugen_x86_emit.pm b/risugen_x86_emit.pm
new file mode 100644
index 0000000..0e3cc1c
--- /dev/null
+++ b/risugen_x86_emit.pm
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+###############################################################################
+# Copyright (c) 2019 Linaro Limited
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Jan Bobek - initial implementation
+###############################################################################
+
+# risugen_x86_emit -- risugen_x86's helper module for emit blocks
+package risugen_x86_emit;
+
+use strict;
+use warnings;
+
+use risugen_common;
+use risugen_x86_asm;
+
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(parse_emitblock);
+
+my $emit_opts;
+
+sub rep(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{rep} = \%opts;
+}
+
+sub repne(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{repne} = \%opts;
+}
+
+sub data16(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{data16} = \%opts;
+}
+
+sub rex(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{rex} = \%opts;
+}
+
+sub modrm(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{modrm} = \%opts;
+}
+
+sub mem(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{mem} = \%opts;
+}
+
+sub imm(%)
+{
+    my (%opts) = @_;
+    $emit_opts->{imm} = \%opts;
+}
+
+sub parse_emitblock($$)
+{
+    my ($rec, $insn) = @_;
+    my $insnname = $rec->{name};
+    my $opcode = $insn->{opcode}{value};
+
+    $emit_opts = {};
+
+    my $emitblock = $rec->{blocks}{"emit"};
+    if (defined $emitblock) {
+        eval_with_fields($insnname, $opcode, $rec, "emit", $emitblock);
+    }
+
+    return $emit_opts;
+}
+
+1;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
                   ` (2 preceding siblings ...)
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 3/7] risugen_x86_emit: " Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-27 10:29   ` Richard Henderson
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions Jan Bobek
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

The risugen_x86.pm module contains most of the code specific to Intel
i386 and x86_64 architectures. This commit also adds --x86_64 option,
which enables emission of 64-bit (rather than 32-bit) assembly.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen        |   6 +-
 risugen_x86.pm | 455 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 460 insertions(+), 1 deletion(-)
 create mode 100644 risugen_x86.pm

diff --git a/risugen b/risugen
index fe3d00e..09a702a 100755
--- a/risugen
+++ b/risugen
@@ -310,6 +310,7 @@ Valid options:
                    Useful to test before support for FP is available.
     --sve        : enable sve floating point
     --be         : generate instructions in Big-Endian byte order (ppc64 only).
+    --x86_64     : generate 64-bit (rather than 32-bit) x86 code.
     --help       : print this message
 EOT
 }
@@ -322,6 +323,7 @@ sub main()
     my $fp_enabled = 1;
     my $sve_enabled = 0;
     my $big_endian = 0;
+    my $is_x86_64 = 0;
     my ($infile, $outfile);
 
     GetOptions( "help" => sub { usage(); exit(0); },
@@ -338,6 +340,7 @@ sub main()
                 },
                 "be" => sub { $big_endian = 1; },
                 "no-fp" => sub { $fp_enabled = 0; },
+                "x86_64" => sub { $is_x86_64 = 1; },
                 "sve" => sub { $sve_enabled = 1; },
         ) or return 1;
     # allow "--pattern re,re" and "--pattern re --pattern re"
@@ -372,7 +375,8 @@ sub main()
         'keys' => \@insn_keys,
         'arch' => $full_arch[0],
         'subarch' => $full_arch[1] || '',
-        'bigendian' => $big_endian
+        'bigendian' => $big_endian,
+        'x86_64' => $is_x86_64
     );
 
     write_test_code(\%params);
diff --git a/risugen_x86.pm b/risugen_x86.pm
new file mode 100644
index 0000000..879d6e1
--- /dev/null
+++ b/risugen_x86.pm
@@ -0,0 +1,455 @@
+#!/usr/bin/perl -w
+###############################################################################
+# Copyright (c) 2019 Linaro Limited
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Jan Bobek - initial implementation
+###############################################################################
+
+# risugen_x86 -- risugen module for Intel i386/x86_64 architectures
+package risugen_x86;
+
+use strict;
+use warnings;
+
+use risugen_common;
+use risugen_x86_asm;
+use risugen_x86_emit;
+
+require Exporter;
+
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(write_test_code);
+
+use constant {
+    RISUOP_COMPARE     => 0,        # compare registers
+    RISUOP_TESTEND     => 1,        # end of test, stop
+    RISUOP_SETMEMBLOCK => 2,        # eax is address of memory block (8192 bytes)
+    RISUOP_GETMEMBLOCK => 3,        # add the address of memory block to eax
+    RISUOP_COMPAREMEM  => 4,        # compare memory block
+
+    # Maximum alignment restriction permitted for a memory op.
+    MAXALIGN => 64,
+    MEMBLOCK_LEN => 8192,
+};
+
+my $periodic_reg_random = 1;
+my $is_x86_64 = 0;
+
+sub write_risuop($)
+{
+    my ($op) = @_;
+
+    write_insn(opcode => X86OP_UD1,
+               modrm => {mod => MOD_DIRECT,
+                         reg => REG_EAX,
+                         rm => $op});
+}
+
+sub write_mov_rr($$)
+{
+    my ($r1, $r2) = @_;
+
+    my %insn = (opcode => X86OP_MOV,
+                modrm => {mod => MOD_DIRECT,
+                          reg => ($r1 & 0x7),
+                          rm => ($r2 & 0x7)});
+
+    $insn{rex}{w} = 1 if $is_x86_64;
+    $insn{rex}{r} = 1 if $r1 >= 8;
+    $insn{rex}{b} = 1 if $r2 >= 8;
+
+    write_insn(%insn);
+}
+
+sub write_mov_reg_imm($$)
+{
+    my ($reg, $imm) = @_;
+
+    my %insn = (opcode => {value => 0xB8 | ($reg & 0x7), len => 1},
+                imm => {value => $imm, len => $is_x86_64 ? 8 : 4});
+
+    $insn{rex}{w} = 1 if $is_x86_64;
+    $insn{rex}{b} = 1 if $reg >= 8;
+
+    write_insn(%insn);
+}
+
+sub write_random_regdata()
+{
+    my $reg_cnt = $is_x86_64 ? 16 : 8;
+    my $bitlen = $is_x86_64 ? 64 : 32;
+
+    # initialize flags register
+    write_insn(opcode => X86OP_XOR,
+               modrm => {mod => MOD_DIRECT,
+                         reg => REG_EAX,
+                         rm => REG_EAX});
+    write_insn(opcode => X86OP_SAHF);
+
+    # general purpose registers
+    for (my $reg = 0; $reg < $reg_cnt; $reg++) {
+        if ($reg != REG_ESP) {
+            my $imm = randint_constr(bitlen => $bitlen, signed => 1);
+            write_mov_reg_imm($reg, $imm);
+        }
+    }
+}
+
+sub write_random_datablock($)
+{
+    my ($datalen) = @_;
+
+    # Write a block of random data, $datalen bytes long, aligned
+    # according to MAXALIGN, and load its address into EAX/RAX.
+
+    $datalen += MAXALIGN - 1;
+
+    # First, load current EIP/RIP into EAX/RAX. Easy to do on x86_64
+    # thanks to RIP-relative addressing, but on i386 we need to play
+    # some well-known tricks with CALL instruction.
+    if ($is_x86_64) {
+        # 4-byte AND + 5-byte JMP
+        my $disp32 = 4 + 5 + (MAXALIGN - 1);
+        my $reg = REG_EAX;
+
+        write_insn(rex => {w => 1},
+                   opcode => X86OP_LEA,
+                   modrm => {mod => MOD_INDIRECT,
+                             reg => $reg, rm => REG_EBP},
+                   disp => {value => $disp32, len => 4});
+
+        write_insn(rex => {w => 1},
+                   opcode => X86OP_ALU_imm8,
+                   modrm => {mod => MOD_DIRECT,
+                             reg => 4, rm => $reg},
+                   imm => {value => ~(MAXALIGN - 1),
+                           len => 1});
+
+    } else {
+        # 1-byte POP + 3-byte ADD + 3-byte AND + 5-byte JMP
+        my $imm8 = 1 + 3 + 3 + 5 + (MAXALIGN - 1);
+        my $reg = REG_EAX;
+
+        # displacement = next instruction
+        write_insn(opcode => X86OP_CALL,
+                   imm => {value => 0x00000000, len => 4});
+
+        write_insn(opcode => {value => 0x58 | ($reg & 0x7),
+                              len => 1});
+
+        write_insn(opcode => X86OP_ALU_imm8,
+                   modrm => {mod => MOD_DIRECT,
+                             reg => 0, rm => $reg},
+                   imm => {value => $imm8, len => 1});
+
+        write_insn(opcode => X86OP_ALU_imm8,
+                   modrm => {mod => MOD_DIRECT,
+                             reg => 4, rm => $reg},
+                   imm => {value => ~(MAXALIGN - 1),
+                           len => 1});
+    }
+
+    # JMP over the data blob.
+    write_insn(opcode => X86OP_JMP,
+               imm => {value => $datalen, len => 4});
+
+    # Generate the random data
+    for (my $w = 8; 0 < $w; $w /= 2) {
+        for (; $w <= $datalen; $datalen -= $w) {
+            insnv(%{rand_insn_imm(size => $w)});
+        }
+    }
+}
+
+sub write_random_xmmdata()
+{
+    my $xmm_cnt = $is_x86_64 ? 16 : 8;
+    my $xmm_len = 16;
+    my $datalen = $xmm_cnt * $xmm_len;
+
+    # Generate random data blob
+    write_random_datablock($datalen);
+
+    # Load the random data into XMM regs.
+    for (my $xmm_reg = 0; $xmm_reg < $xmm_cnt; $xmm_reg++) {
+        my %insn = (opcode => X86OP_MOVAPS,
+                    modrm => {mod => MOD_INDIRECT_DISP32,
+                              reg => ($xmm_reg & 0x7),
+                              rm => REG_EAX},
+                    disp => {value => $xmm_reg * $xmm_len,
+                             len => 4});
+
+        $insn{rex}{r} = 1 if $xmm_reg >= 8;
+
+        write_insn(%insn);
+    }
+}
+
+sub write_memblock_setup()
+{
+    # Generate random data blob
+    write_random_datablock(MEMBLOCK_LEN);
+    # Pointer is in EAX/RAX; set the memblock
+    write_risuop(RISUOP_SETMEMBLOCK);
+}
+
+sub write_random_register_data()
+{
+    write_random_xmmdata();
+    write_random_regdata();
+    write_risuop(RISUOP_COMPARE);
+}
+
+sub rand_insn_imm(%)
+{
+    my (%args) = @_;
+
+    return {
+        value => randint_constr(bitlen => ($args{size} * 8), signed => 1),
+        len => $args{size}
+    };
+}
+
+sub rand_insn_opcode($)
+{
+    # Given an instruction-details array, generate an instruction
+    my ($rec) = @_;
+    my $insnname = $rec->{name};
+    my $insnwidth = $rec->{width};
+
+    my $constraintfailures = 0;
+
+    INSN: while(1) {
+        my $opcode = randint_constr(bitlen => 32,
+                                    fixedbits => $rec->{fixedbits},
+                                    fixedbitmask => $rec->{fixedbitmask});
+
+        my $constraint = $rec->{blocks}{"constraints"};
+        if (defined $constraint) {
+            # user-specified constraint: evaluate in an environment
+            # with variables set corresponding to the variable fields.
+            my $v = eval_with_fields($insnname, $opcode, $rec, "constraints", $constraint);
+            if (!$v) {
+                $constraintfailures++;
+                if ($constraintfailures > 10000) {
+                    print "10000 consecutive constraint failures for $insnname constraints string:\n$constraint\n";
+                    exit (1);
+                }
+                next INSN;
+            }
+        }
+
+        # OK, we got a good one
+        $constraintfailures = 0;
+
+        return {
+            value => $opcode >> (32 - $insnwidth),
+            len => $insnwidth / 8
+        };
+    }
+}
+
+sub rand_insn_modrm($$)
+{
+    my ($opts, $insn) = @_;
+    my $modrm;
+
+    while (1) {
+        $modrm = rand_fill({mod => {bitlen => 2},
+                            reg => {bitlen => 3},
+                            rm => {bitlen => 3}},
+                           $opts);
+
+        if ($modrm->{mod} != MOD_DIRECT) {
+            # Displacement only; we cannot use this since we
+            # don't know absolute address of the memblock.
+            next if $modrm->{mod} == MOD_INDIRECT && $modrm->{rm} == REG_EBP;
+
+            if ($modrm->{rm} == REG_ESP) {
+                # SIB byte present
+                my $sib = rand_fill({ss => {bitlen => 2},
+                                     index => {bitlen => 3},
+                                     base => {bitlen => 3}}, {});
+
+                # We cannot modify ESP/RSP during the tests
+                next if $sib->{base} == REG_ESP;
+
+                # When base and index register are the same,
+                # computing the correct memblock addresses and
+                # offsets gets way too complicated...
+                next if $sib->{base} == $sib->{index};
+
+                # No base register
+                next if $modrm->{mod} == MOD_INDIRECT && $sib->{base} == REG_EBP;
+
+                $insn->{sib} = $sib;
+            }
+
+            $insn->{disp} = rand_insn_imm(size => 1)
+                if $modrm->{mod} == MOD_INDIRECT_DISP8;
+
+            $insn->{disp} = rand_insn_imm(size => 4)
+                if $modrm->{mod} == MOD_INDIRECT_DISP32;
+        }
+
+        $insn->{modrm} = $modrm;
+        last;
+    }
+}
+
+sub rand_insn_rex($$)
+{
+    my ($opts, $insn) = @_;
+
+    $opts->{w} = 0 unless defined $opts->{w};
+    $opts->{x} = 0 unless defined $opts->{x} || defined $insn->{sib};
+
+    my $rex = rand_fill({w => {bitlen => 1},
+                         r => {bitlen => 1},
+                         b => {bitlen => 1},
+                         x => {bitlen => 1}},
+                        $opts);
+
+    $insn->{rex} = $rex
+        if $rex->{w} || $rex->{r} || $rex->{b} || $rex->{x};
+}
+
+sub write_mem_getoffset($$)
+{
+    my ($opts, $insn) = @_;
+    my $offset, my $index;
+
+    $opts->{size}  = 0 unless defined $opts->{size};
+    $opts->{align} = 1 unless defined $opts->{align};
+
+    if (!defined $opts->{base}
+        && defined $insn->{modrm}
+        && $insn->{modrm}{mod} != MOD_DIRECT) {
+
+        $opts->{base} = (defined $insn->{sib}
+                         ? $insn->{sib}{base}
+                         : $insn->{modrm}{rm});
+
+        if ($insn->{modrm}{mod} == MOD_INDIRECT && $opts->{base} == REG_EBP) {
+            delete $opts->{base}; # No base register
+        } else {
+            $opts->{base} |= $insn->{rex}{b} << 3 if defined $insn->{rex};
+            $opts->{base} |= (!$insn->{vex}{b}) << 3 if defined $insn->{vex};
+        }
+    }
+
+    if (!defined $opts->{index} && defined $insn->{sib}) {
+        $opts->{index} = $insn->{sib}{index};
+        $opts->{index} |= $insn->{rex}{x} << 3 if defined $insn->{rex};
+        $opts->{index} |= (!$insn->{vex}{x}) << 3 if defined $insn->{vex};
+        delete $opts->{index} if $opts->{index} == REG_ESP; # ESP means "none"
+    }
+
+    $opts->{ss} = $insn->{sib}{ss} if !defined $opts->{ss} && defined $insn->{sib};
+    $opts->{disp} = $insn->{disp} if !defined $opts->{disp} && defined $insn->{disp};
+
+    $offset = int(rand(MEMBLOCK_LEN - $opts->{size}));
+    $offset &= ~($opts->{align} - 1);
+
+    $offset -= $opts->{disp}{value} if defined $opts->{disp};
+
+    if (defined $opts->{index}) {
+        $index = randint_constr(bitlen => 32, signed => 1);
+        $offset -= $index * (1 << $opts->{ss});
+    }
+
+    if (defined $opts->{base} && defined $offset) {
+        write_mov_reg_imm(REG_EAX, $offset);
+        write_risuop(RISUOP_GETMEMBLOCK);
+        write_mov_rr($opts->{base}, REG_EAX);
+    }
+    if (defined $opts->{index} && defined $index) {
+        write_mov_reg_imm($opts->{index}, $index);
+    }
+}
+
+sub gen_one_insn($)
+{
+    my ($rec) = @_;
+    my $insn;
+
+    $insn->{opcode} = rand_insn_opcode($rec);
+    my $opts = parse_emitblock($rec, $insn);
+
+    # Operation with a ModR/M byte can potentially use a memory
+    # operand
+    $opts->{mem} = {}
+        unless defined $opts->{mem} || !defined $opts->{modrm};
+
+    # If none of REX/VEX/EVEX are specified, default to REX
+    $opts->{rex} = {}
+        unless defined $opts->{rex} || defined $opts->{vex} || defined $opts->{evex};
+
+    # REX requires x86_64
+    delete $opts->{rex}
+        unless $is_x86_64;
+
+    $insn->{rep}    = $opts->{rep}    if defined $opts->{rep};
+    $insn->{repne}  = $opts->{repne}  if defined $opts->{repne};
+    $insn->{data16} = $opts->{data16} if defined $opts->{data16};
+
+    rand_insn_modrm($opts->{modrm}, $insn) if defined $opts->{modrm};
+
+    # TODO rand_insn_vex($opts->{vex}, $insn) if defined $opts->{vex};
+    # TODO rand_insn_evex($opts->{evex}, $insn) if defined $opts->{evex};
+    rand_insn_rex($opts->{rex}, $insn) if defined $opts->{rex};
+
+    $insn->{imm} = rand_insn_imm(%{$opts->{imm}}) if defined $opts->{imm};
+
+    write_mem_getoffset($opts->{mem}, $insn);
+    write_insn(%{$insn});
+}
+
+sub write_test_code($)
+{
+    my ($params) = @_;
+
+    my $numinsns = $params->{ 'numinsns' };
+    my $outfile = $params->{ 'outfile' };
+
+    my %insn_details = %{ $params->{ 'details' } };
+    my @keys = @{ $params->{ 'keys' } };
+
+    $is_x86_64 = $params->{ 'x86_64' };
+
+    open_bin($outfile);
+
+    # TODO better random number generator?
+    srand(0);
+
+    print "Generating code using patterns: @keys...\n";
+    progress_start(78, $numinsns);
+
+    write_memblock_setup();
+
+    # memblock setup doesn't clean its registers, so this must come afterwards.
+    write_random_register_data();
+
+    for my $i (1..$numinsns) {
+        my $insn_enc = $keys[int rand (@keys)];
+        # my $forcecond = (rand() < $condprob) ? 1 : 0;
+        gen_one_insn($insn_details{$insn_enc});
+        write_risuop(RISUOP_COMPARE);
+        # Rewrite the registers periodically. This avoids the tendency
+        # for the VFP registers to decay to NaNs and zeroes.
+        if ($periodic_reg_random && ($i % 100) == 0) {
+            write_random_register_data();
+        }
+        progress_update($i);
+    }
+    write_risuop(RISUOP_TESTEND);
+    progress_end();
+    close_bin();
+}
+
+1;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
                   ` (3 preceding siblings ...)
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: " Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-27 10:30   ` Richard Henderson
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 6/7] x86.risu: add SSE instructions Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 7/7] x86.risu: add SSE2 instructions Jan Bobek
  6 siblings, 1 reply; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

Accept all instructions whose bit length is divisible by 8. Note that
the maximum instruction length (as specified in the config file) is 32
bits, hence this change permits instructions which are 8 bits or 24
bits long (16-bit instructions have already been considered valid).

Note that while valid x86 instructions may be up to 15 bytes long, the
length constraint described above only applies to the main opcode
field, which is usually only 1 or 2 bytes long. Therefore, the primary
purpose of this change is to allow 1-byte x86 opcodes.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/risugen b/risugen
index 09a702a..17bf98f 100755
--- a/risugen
+++ b/risugen
@@ -229,12 +229,11 @@ sub parse_config_file($)
                 push @fields, [ $var, $bitpos, $bitmask ];
             }
         }
-        if ($bitpos == 16) {
-            # assume this is a half-width thumb instruction
+        if ($bitpos % 8 == 0) {
             # Note that we don't fiddle with the bitmasks or positions,
             # which means the generated insn will be in the high halfword!
-            $insnwidth = 16;
-        } elsif ($bitpos != 0) {
+            $insnwidth -= $bitpos;
+        } else {
             print STDERR "$file:$.: ($insn $enc) not enough bits specified\n";
             exit(1);
         }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 6/7] x86.risu: add SSE instructions
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
                   ` (4 preceding siblings ...)
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 7/7] x86.risu: add SSE2 instructions Jan Bobek
  6 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

Add an x86 configuration file with all SSE instructions.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 x86.risu | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)
 create mode 100644 x86.risu

diff --git a/x86.risu b/x86.risu
new file mode 100644
index 0000000..cc40bbc
--- /dev/null
+++ b/x86.risu
@@ -0,0 +1,99 @@
+###############################################################################
+# Copyright (c) 2019 Linaro Limited
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Jan Bobek - initial implementation
+###############################################################################
+
+# Input file for risugen defining x86 instructions
+.mode x86
+
+# SSE Data Transfer Instructions
+MOVUPS          SSE     00001111 0001000 d !emit { modrm(); mem(size => 16); }
+MOVSS           SSE     00001111 0001000 d !emit { rep(); modrm(); mem(size => 4); }
+MOVHLPS         SSE     00001111 00010010  !emit { modrm(mod => MOD_DIRECT); }
+MOVLPS          SSE     00001111 0001001 d !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+MOVLHPS         SSE     00001111 00010110  !emit { modrm(mod => MOD_DIRECT); }
+MOVHPS          SSE     00001111 0001011 d !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+MOVAPS          SSE     00001111 0010100 d !emit { modrm(); mem(size => 16, align => 16); }
+MOVMSKPS        SSE     00001111 01010000  !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); }
+
+# SSE Packed Arithmetic Instructions
+ADDPS           SSE     00001111 01011000 !emit { modrm(); mem(size => 16, align => 16); }
+ADDSS           SSE     00001111 01011000 !emit { rep(); modrm(); mem(size => 4); }
+SUBPS           SSE     00001111 01011100 !emit { modrm(); mem(size => 16, align => 16); }
+SUBSS           SSE     00001111 01011100 !emit { rep(); modrm(); mem(size => 4); }
+MULPS           SSE     00001111 01011001 !emit { modrm(); mem(size => 16, align => 16); }
+MULSS           SSE     00001111 01011001 !emit { rep(); modrm(); mem(size => 4); }
+DIVPS           SSE     00001111 01011110 !emit { modrm(); mem(size => 16, align => 16); }
+DIVSS           SSE     00001111 01011110 !emit { rep(); modrm(); mem(size => 4); }
+RCPPS           SSE     00001111 01010011 !emit { modrm(); mem(size => 16, align => 16); }
+RCPSS           SSE     00001111 01010011 !emit { rep(); modrm(); mem(size => 4); }
+SQRTPS          SSE     00001111 01010001 !emit { modrm(); mem(size => 16, align => 16); }
+SQRTSS          SSE     00001111 01010001 !emit { rep(); modrm(); mem(size => 4); }
+RSQRTPS         SSE     00001111 01010010 !emit { modrm(); mem(size => 16, align => 16); }
+RSQRTSS         SSE     00001111 01010010 !emit { rep(); modrm(); mem(size => 4); }
+MINPS           SSE     00001111 01011101 !emit { modrm(); mem(size => 16, align => 16); }
+MINSS           SSE     00001111 01011101 !emit { rep(); modrm(); mem(size => 4); }
+MAXPS           SSE     00001111 01011111 !emit { modrm(); mem(size => 16, align => 16); }
+MAXSS           SSE     00001111 01011111 !emit { rep(); modrm(); mem(size => 4); }
+
+# SSE Comparison Instructions
+CMPPS           SSE     00001111 11000010 !emit { modrm(); mem(size => 16, align => 16); imm(size => 1); }
+CMPSS           SSE     00001111 11000010 !emit { rep(); modrm(); mem(size => 4); imm(size => 1); }
+UCOMISS         SSE     00001111 00101110 !emit { modrm(); mem(size => 4); }
+COMISS          SSE     00001111 00101111 !emit { modrm(); mem(size => 4); }
+
+# SSE Logical Instructions
+ANDPS           SSE     00001111 01010100 !emit { modrm(); mem(size => 16, align => 16); }
+ANDNPS          SSE     00001111 01010101 !emit { modrm(); mem(size => 16, align => 16); }
+ORPS            SSE     00001111 01010110 !emit { modrm(); mem(size => 16, align => 16); }
+XORPS           SSE     00001111 01010111 !emit { modrm(); mem(size => 16, align => 16); }
+
+# SSE Shuffle and Unpack Instructions
+SHUFPS          SSE     00001111 11000110 !emit { modrm(); mem(size => 16, align => 16); imm(size => 1); }
+UNPCKLPS        SSE     00001111 00010100 !emit { modrm(); mem(size => 16, align => 16); }
+UNPCKHPS        SSE     00001111 00010101 !emit { modrm(); mem(size => 16, align => 16); }
+
+# SSE Conversion Instructions
+CVTPI2PS        SSE     00001111 00101010 !emit { modrm(); mem(size => 8); }
+CVTSI2SS        SSE     00001111 00101010 !emit { rep(); modrm(); mem(size => 4); }
+CVTSI2SS_64     SSE     00001111 00101010 !emit { rep(); rex(w => 1); modrm(); mem(size => 8); }
+CVTPS2PI        SSE     00001111 00101101 !emit { modrm(); mem(size => 8); }
+CVTSS2SI        SSE     00001111 00101101 !emit { rep(); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTSS2SI_64     SSE     00001111 00101101 !emit { rep(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTTPS2PI       SSE     00001111 00101100 !emit { modrm(); mem(size => 8); }
+CVTTSS2SI       SSE     00001111 00101100 !emit { rep(); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTTSS2SI_64    SSE     00001111 00101100 !emit { rep(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 4); }
+
+# SSE MXCSR State Management Instructions
+# LDMXCSR         SSE     00001111 10101110 !emit { modrm(mod => ~MOD_DIRECT, reg => 2); mem(size => 4); }
+STMXCSR         SSE     00001111 10101110 !emit { modrm(mod => ~MOD_DIRECT, reg => 3); mem(size => 4); }
+
+# SSE 64-bit SIMD Integer Instructions
+PAVGB           SSE     00001111 11100000 !emit { modrm(); mem(size => 8); }
+PAVGW           SSE     00001111 11100011 !emit { modrm(); mem(size => 8); }
+PEXTRW          SSE     00001111 11000101 !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); mem(size => 8); imm(size => 1); }
+PINSRW          SSE     00001111 11000100 !emit { modrm(); mem(size => 2); imm(size => 1); }
+PMAXUB          SSE     00001111 11011110 !emit { modrm(); mem(size => 8); }
+PMAXSW          SSE     00001111 11101110 !emit { modrm(); mem(size => 8); }
+PMINUB          SSE     00001111 11011010 !emit { modrm(); mem(size => 8); }
+PMINSW          SSE     00001111 11101010 !emit { modrm(); mem(size => 8); }
+PMOVMSKB        SSE     00001111 11010111 !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); mem(size => 8); }
+PMULHUW         SSE     00001111 11100100 !emit { modrm(); mem(size => 8); }
+PSADBW          SSE     00001111 11110110 !emit { modrm(); mem(size => 8); }
+PSHUFW          SSE     00001111 01110000 !emit { modrm(); mem(size => 8); imm(size => 1); }
+
+# SSE Cacheability Control, Prefetch, and Instruction Ordering Instructions
+MASKMOVQ        SSE     00001111 11110111 !emit { modrm(mod => MOD_DIRECT); mem(size => 8, base => REG_EDI); }
+MOVNTQ          SSE     00001111 11100111 !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+MOVNTPS         SSE     00001111 00101011 !emit { modrm(mod => ~MOD_DIRECT); mem(size => 16, align => 16); }
+PREFETCHT0      SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 1); mem(size => 1); }
+PREFETCHT1      SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 2); mem(size => 1); }
+PREFETCHT2      SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 3); mem(size => 1); }
+PREFETCHNTA     SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 0); mem(size => 1); }
+SFENCE          SSE     00001111 10101110 !emit { modrm(mod => MOD_DIRECT, reg => 7); }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [RISU RFC PATCH v1 7/7] x86.risu: add SSE2 instructions
  2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
                   ` (5 preceding siblings ...)
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 6/7] x86.risu: add SSE instructions Jan Bobek
@ 2019-06-19  5:04 ` Jan Bobek
  6 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-19  5:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jan Bobek, Alex Bennée, Richard Henderson

Add all SSE2 instructions to the x86 configuration file.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 x86.risu | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 153 insertions(+), 7 deletions(-)

diff --git a/x86.risu b/x86.risu
index cc40bbc..b3e4c88 100644
--- a/x86.risu
+++ b/x86.risu
@@ -12,63 +12,137 @@
 # Input file for risugen defining x86 instructions
 .mode x86
 
-# SSE Data Transfer Instructions
+# SSE/SSE2 Data Transfer Instructions
 MOVUPS          SSE     00001111 0001000 d !emit { modrm(); mem(size => 16); }
+MOVUPD          SSE2    00001111 0001000 d !emit { data16(); modrm(); mem(size => 16); }
 MOVSS           SSE     00001111 0001000 d !emit { rep(); modrm(); mem(size => 4); }
+MOVSD           SSE2    00001111 0001000 d !emit { repne(); modrm(); mem(size => 8); }
+
 MOVHLPS         SSE     00001111 00010010  !emit { modrm(mod => MOD_DIRECT); }
 MOVLPS          SSE     00001111 0001001 d !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+MOVLPD          SSE2    00001111 0001001 d !emit { data16(); modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+
 MOVLHPS         SSE     00001111 00010110  !emit { modrm(mod => MOD_DIRECT); }
 MOVHPS          SSE     00001111 0001011 d !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+MOVHPD          SSE2    00001111 0001011 d !emit { data16(); modrm(mod => ~MOD_DIRECT); mem(size => 8); }
+
 MOVAPS          SSE     00001111 0010100 d !emit { modrm(); mem(size => 16, align => 16); }
+MOVAPD          SSE2    00001111 0010100 d !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 MOVMSKPS        SSE     00001111 01010000  !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); }
+MOVMKSPD        SSE2    00001111 01010000  !emit { data16(); modrm(mod => MOD_DIRECT, reg => ~REG_ESP); }
 
-# SSE Packed Arithmetic Instructions
+# SSE/SSE2 Packed Arithmetic Instructions
 ADDPS           SSE     00001111 01011000 !emit { modrm(); mem(size => 16, align => 16); }
+ADDPD           SSE2    00001111 01011000 !emit { data16(); modrm(); mem(size => 16, align => 16) }
 ADDSS           SSE     00001111 01011000 !emit { rep(); modrm(); mem(size => 4); }
+ADDSD           SSE2    00001111 01011000 !emit { repne(); modrm(); mem(size => 4); }
+
 SUBPS           SSE     00001111 01011100 !emit { modrm(); mem(size => 16, align => 16); }
+SUBPD           SSE2    00001111 01011100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 SUBSS           SSE     00001111 01011100 !emit { rep(); modrm(); mem(size => 4); }
+SUBSD           SSE2    00001111 01011100 !emit { repne(); modrm(); mem(size => 4); }
+
 MULPS           SSE     00001111 01011001 !emit { modrm(); mem(size => 16, align => 16); }
+MULPD           SSE2    00001111 01011001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 MULSS           SSE     00001111 01011001 !emit { rep(); modrm(); mem(size => 4); }
-DIVPS           SSE     00001111 01011110 !emit { modrm(); mem(size => 16, align => 16); }
+MULSD           SSE2    00001111 01011001 !emit { repne(); modrm(); mem(size => 4); }
+
+DIVPS           SSE     00001111 01011110 !emit { modrm(); modrm(); mem(size => 16, align => 16); }
+DIVPD           SSE2    00001111 01011110 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 DIVSS           SSE     00001111 01011110 !emit { rep(); modrm(); mem(size => 4); }
+DIVSD           SSE2    00001111 01011110 !emit { repne(); modrm(); mem(size => 4); }
+
 RCPPS           SSE     00001111 01010011 !emit { modrm(); mem(size => 16, align => 16); }
 RCPSS           SSE     00001111 01010011 !emit { rep(); modrm(); mem(size => 4); }
+
 SQRTPS          SSE     00001111 01010001 !emit { modrm(); mem(size => 16, align => 16); }
+SQRTPD          SSE2    00001111 01010001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 SQRTSS          SSE     00001111 01010001 !emit { rep(); modrm(); mem(size => 4); }
+SQRTSD          SSE2    00001111 01010001 !emit { repne(); modrm(); mem(size => 4); }
+
 RSQRTPS         SSE     00001111 01010010 !emit { modrm(); mem(size => 16, align => 16); }
 RSQRTSS         SSE     00001111 01010010 !emit { rep(); modrm(); mem(size => 4); }
+
 MINPS           SSE     00001111 01011101 !emit { modrm(); mem(size => 16, align => 16); }
+MINPD           SSE2    00001111 01011101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 MINSS           SSE     00001111 01011101 !emit { rep(); modrm(); mem(size => 4); }
+MINSD           SSE2    00001111 01011101 !emit { repne(); modrm(); mem(size => 4); }
+
 MAXPS           SSE     00001111 01011111 !emit { modrm(); mem(size => 16, align => 16); }
+MAXPD           SSE2    00001111 01011111 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 MAXSS           SSE     00001111 01011111 !emit { rep(); modrm(); mem(size => 4); }
+MAXSD           SSE2    00001111 01011111 !emit { repne(); modrm(); mem(size => 4); }
 
-# SSE Comparison Instructions
+# SSE/SSE2 Comparison Instructions
 CMPPS           SSE     00001111 11000010 !emit { modrm(); mem(size => 16, align => 16); imm(size => 1); }
+CMPPD           SSE2    00001111 11000010 !emit { data16(); modrm(); mem(size => 16, align => 16); imm(size => 1); }
 CMPSS           SSE     00001111 11000010 !emit { rep(); modrm(); mem(size => 4); imm(size => 1); }
+CMPSD           SSE2    00001111 11000010 !emit { repne(); modrm(); mem(size => 4); imm(size => 1); }
+
 UCOMISS         SSE     00001111 00101110 !emit { modrm(); mem(size => 4); }
+UCOMISD         SSE2    00001111 00101110 !emit { data16(); modrm(); mem(size => 4); }
+
 COMISS          SSE     00001111 00101111 !emit { modrm(); mem(size => 4); }
+COMISD          SSE2    00001111 00101111 !emit { data16(); modrm(); mem(size => 4); }
 
-# SSE Logical Instructions
+# SSE/SSE2 Logical Instructions
 ANDPS           SSE     00001111 01010100 !emit { modrm(); mem(size => 16, align => 16); }
+ANDPD           SSE2    00001111 01010100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 ANDNPS          SSE     00001111 01010101 !emit { modrm(); mem(size => 16, align => 16); }
+ANDNPD          SSE2    00001111 01010101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 ORPS            SSE     00001111 01010110 !emit { modrm(); mem(size => 16, align => 16); }
+ORPD            SSE2    00001111 01010110 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 XORPS           SSE     00001111 01010111 !emit { modrm(); mem(size => 16, align => 16); }
+XORPD           SSE2    00001111 01010111 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 
-# SSE Shuffle and Unpack Instructions
+# SSE/SSE2 Shuffle and Unpack Instructions
 SHUFPS          SSE     00001111 11000110 !emit { modrm(); mem(size => 16, align => 16); imm(size => 1); }
+SHUFPD          SSE2    00001111 11000110 !emit { data16(); modrm(); mem(size => 16, align => 16); imm(size => 1); }
+
 UNPCKLPS        SSE     00001111 00010100 !emit { modrm(); mem(size => 16, align => 16); }
+UNPCKLPD        SSE2    00001111 00010100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 UNPCKHPS        SSE     00001111 00010101 !emit { modrm(); mem(size => 16, align => 16); }
+UNPCKHPD        SSE2    00001111 00010101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 
-# SSE Conversion Instructions
+# SSE/SSE2 Conversion Instructions
 CVTPI2PS        SSE     00001111 00101010 !emit { modrm(); mem(size => 8); }
+CVTPI2PD        SSE2    00001111 00101010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 CVTSI2SS        SSE     00001111 00101010 !emit { rep(); modrm(); mem(size => 4); }
+CVTSI2SD        SSE2    00001111 00101010 !emit { repne(); modrm(); mem(size => 8); }
 CVTSI2SS_64     SSE     00001111 00101010 !emit { rep(); rex(w => 1); modrm(); mem(size => 8); }
+CVTSI2SD_64     SSE2    00001111 00101010 !emit { repne(); rex(w => 1); modrm(); mem(size => 8); }
+
 CVTPS2PI        SSE     00001111 00101101 !emit { modrm(); mem(size => 8); }
+CVTPD2PI        SSE2    00001111 00101101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 CVTSS2SI        SSE     00001111 00101101 !emit { rep(); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTSD2SI        SSE2    00001111 00101101 !emit { repne(); modrm(reg => ~REG_ESP); mem(size => 8); }
 CVTSS2SI_64     SSE     00001111 00101101 !emit { rep(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTSD2SI_64     SSE2    00001111 00101101 !emit { repne(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 8); }
+
 CVTTPS2PI       SSE     00001111 00101100 !emit { modrm(); mem(size => 8); }
+CVTTPD2PI       SSE2    00001111 00101100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
 CVTTSS2SI       SSE     00001111 00101100 !emit { rep(); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTTSD2SI       SSE2    00001111 00101100 !emit { repne(); modrm(reg => ~REG_ESP); mem(size => 8); }
 CVTTSS2SI_64    SSE     00001111 00101100 !emit { rep(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 4); }
+CVTTSD2SI_64    SSE2    00001111 00101100 !emit { repne(); rex(w => 1); modrm(reg => ~REG_ESP); mem(size => 8); }
+
+CVTPD2PQ        SSE2    00001111 11100110 !emit { repne(); modrm(); mem(size => 16, align => 16); }
+CVTTPD2PQ       SSE2    00001111 11100110 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+CVTDQ2PD        SSE2    00001111 11100110 !emit { rep(); modrm(); mem(size => 8); }
+
+CVTPS2PD        SSE2    00001111 01011010 !emit { modrm(); mem(size => 8); }
+CVTPD2PS        SSE2    00001111 01011010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+CVTSS2SD        SSE2    00001111 01011010 !emit { rep(); modrm(); mem(size => 4); }
+CVTSD2SS        SSE2    00001111 01011010 !emit { repne(); modrm(); mem(size => 8); }
+
+CVTDQ2PS        SSE2    00001111 01011011 !emit { modrm(); mem(size => 16, align => 16); }
+CVTPS2DQ        SSE2    00001111 01011011 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+CVTTPS2DQ       SSE2    00001111 01011011 !emit { rep(); modrm(); mem(size => 16, align => 16); }
 
 # SSE MXCSR State Management Instructions
 # LDMXCSR         SSE     00001111 10101110 !emit { modrm(mod => ~MOD_DIRECT, reg => 2); mem(size => 4); }
@@ -88,6 +162,67 @@ PMULHUW         SSE     00001111 11100100 !emit { modrm(); mem(size => 8); }
 PSADBW          SSE     00001111 11110110 !emit { modrm(); mem(size => 8); }
 PSHUFW          SSE     00001111 01110000 !emit { modrm(); mem(size => 8); imm(size => 1); }
 
+# SSE2 128-bit SIMD Integer Instructions
+MOVDQA          SSE2    00001111 011 d 1111 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+MOVDQU          SSE2    00001111 011 d 1111 !emit { rep(); modrm(); mem(size => 16); }
+MOVQ2DQ         SSE2    00001111 11010110 !emit { rep(); modrm(mod => MOD_DIRECT); }
+MOVDQ2Q         SSE2    00001111 11010110 !emit { repne(); modrm(mod => MOD_DIRECT); }
+
+PMULUDQ_64      SSE2    00001111 11110100 !emit { modrm(); mem(size => 8); }
+PMULUDQ         SSE2    00001111 11110100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDB           SSE2    00001111 11111100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDW           SSE2    00001111 11111101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDD           SSE2    00001111 11111110 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDQ           SSE2    00001111 11010100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDSB          SSE2    00001111 11101100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDSW          SSE2    00001111 11101101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDUSB         SSE2    00001111 11011100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PADDUSW         SSE2    00001111 11011101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBB           SSE2    00001111 11111000 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBW           SSE2    00001111 11111001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBD           SSE2    00001111 11111010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBQ_64        SSE2    00001111 11111011 !emit { modrm(); mem(size => 8); }
+PSUBQ           SSE2    00001111 11111011 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBSB          SSE2    00001111 11101000 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBSW          SSE2    00001111 11101001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBUSB         SSE2    00001111 11011000 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSUBUSW         SSE2    00001111 11011001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
+PSHUFLW         SSE2    00001111 01110000 !emit { repne(); modrm(); mem(size => 16, align => 16); imm(size => 1); }
+PSHUFHW         SSE2    00001111 01110000 !emit { rep(); modrm(); mem(size => 16, align => 16); imm(size => 1); }
+PSHUFD          SSE2    00001111 01110000 !emit { data16(); modrm(); mem(size => 16, align => 16); imm(size => 1); }
+
+PSLLW           SSE2    00001111 11110001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSLLW_imm       SSE2    00001111 01110001 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 6); imm(size => 1); }
+PSLLD           SSE2    00001111 11110010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSLLD_imm       SSE2    00001111 01110010 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 6); imm(size => 1); }
+PSLLQ           SSE2    00001111 11110011 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSLLQ_imm       SSE2    00001111 01110011 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 6); imm(size => 1); }
+PSLLDQ          SSE2    00001111 01110011 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 7); imm(size => 1); }
+
+PSRAW           SSE2    00001111 11100001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSRAW_imm       SSE2    00001111 01110001 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 4); imm(size => 1); }
+PSRAD           SSE2    00001111 11100010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSRAD_imm       SSE2    00001111 01110010 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 4); imm(size => 1); }
+
+PSRLW           SSE2    00001111 11010001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSRLW_imm       SSE2    00001111 01110001 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 2); imm(size => 1); }
+PSRLD           SSE2    00001111 11010010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSRLD_imm       SSE2    00001111 01110010 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 2); imm(size => 1); }
+PSRLQ           SSE2    00001111 11010011 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PSRLQ_imm       SSE2    00001111 01110011 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 2); imm(size => 1); }
+PSRLDQ          SSE2    00001111 01110011 !emit { data16(); modrm(mod => MOD_DIRECT, reg => 3); imm(size => 1); }
+
+PUNPCKHBW       SSE2    00001111 01101000 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKHWD       SSE2    00001111 01101001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKHDQ       SSE2    00001111 01101010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKHQDQ      SSE2    00001111 01101101 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
+PUNPCKLBW       SSE2    00001111 01100000 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKLWD       SSE2    00001111 01100001 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKLDQ       SSE2    00001111 01100010 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+PUNPCKLQDQ      SSE2    00001111 01101100 !emit { data16(); modrm(); mem(size => 16, align => 16); }
+
 # SSE Cacheability Control, Prefetch, and Instruction Ordering Instructions
 MASKMOVQ        SSE     00001111 11110111 !emit { modrm(mod => MOD_DIRECT); mem(size => 8, base => REG_EDI); }
 MOVNTQ          SSE     00001111 11100111 !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
@@ -97,3 +232,14 @@ PREFETCHT1      SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg
 PREFETCHT2      SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 3); mem(size => 1); }
 PREFETCHNTA     SSE     00001111 00011000 !emit { modrm(mod => ~MOD_DIRECT, reg => 0); mem(size => 1); }
 SFENCE          SSE     00001111 10101110 !emit { modrm(mod => MOD_DIRECT, reg => 7); }
+
+# SSE2 Cacheability Control, Prefetch, and Instruction Ordering Instructions
+CFLUSH          SSE2    00001111 10101110 !emit { modrm(mod => ~MOD_DIRECT, reg => 7); mem(size => 1); }
+LFENCE          SSE2    00001111 10101110 !emit { modrm(mod => 0b11, reg => 0b101); }
+MFENCE          SSE2    00001111 10101110 !emit { modrm(mod => 0b11, reg => 0b111); }
+PAUSE           SSE2    10010000          !emit { rep(); }
+MASKMOVDQU      SSE2    00001111 11110111 !emit { data16(); modrm(mod => MOD_DIRECT); mem(size => 16, base => REG_EDI); }
+MOVNTPD         SSE2    00001111 00101011 !emit { data16(); modrm(mod => ~MOD_DIRECT); mem(size => 16, align => 16); }
+MOVNTDQ         SSE2    00001111 11100111 !emit { data16(); modrm(mod => ~MOD_DIRECT); mem(size => 16, align => 16); }
+MOVNTI          SSE2    00001111 11000011 !emit { modrm(mod => ~MOD_DIRECT); mem(size => 4); }
+MOVNTI_64       SSE2    00001111 11000011 !emit { rex(w => 1); modrm(mod => ~MOD_DIRECT); mem(size => 8); }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
@ 2019-06-27  8:53   ` Richard Henderson
  2019-06-28 15:10     ` Jan Bobek
  0 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2019-06-27  8:53 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/19/19 7:04 AM, Jan Bobek wrote:
> +        my $value = ($args{bigendian}
> +                     ? ($args{value} >> (8 * $args{len} - $bitlen))
> +                     : $args{value});
...
> +        $args{value} >>= $bitlen unless $args{bigendian};

I think this could be clearer without modifying $args.
I mis-read these the first time around.

Perhaps

    my $bitpos = 0;
    my $bitend = 8 * $args{len};
    while ($bitpos < $bitend) {
        ...
        my $value = $args{value} >> ($args{bigendian}
                                     ? $bitend - $bitpos - $bitlen
                                     : $bitpos);
        ...
        $bitpos += $bitlen;
    }

> +sub randint_constr(%)
> +{
> +    my (%args) = @_;
> +    my $bitlen = $args{bitlen};
> +    my $halfrange = 1 << ($bitlen - 1);
> +
> +    while (1) {
> +        my $value = int(rand(2 * $halfrange));
> +        $value -= $halfrange if defined $args{signed} && $args{signed};
> +        $value &= ~$args{fixedbitmask} if defined $args{fixedbitmask};
> +        $value |= $args{fixedbits} if defined $args{fixedbits};
> +
> +        if (defined $args{constraint}) {
> +            if (!($args{constraint} >> 63)) {
> +                $value = $args{constraint};
> +            } elsif ($value == ~$args{constraint}) {
> +                next;
> +            }
> +        }

I don't understand what you're doing here with {constraint}.
Some additional commentary would help.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module Jan Bobek
@ 2019-06-27  9:05   ` Richard Henderson
  2019-06-28 15:57     ` Jan Bobek
  0 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2019-06-27  9:05 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/19/19 7:04 AM, Jan Bobek wrote:
> +sub rex_encode(%)
> +{
> +    my (%args) = @_;
> +
> +    $args{w} = 0 unless defined $args{w};
> +    $args{r} = 0 unless defined $args{w};
> +    $args{x} = 0 unless defined $args{w};
> +    $args{b} = 0 unless defined $args{w};

What makes you believe that REX.[RXB] are dependent on REX.W?
Or are these merely cut-and-paste errors?


> +sub modrm_encode(%)
> +{
> +    my (%args) = @_;
> +
> +    die "MOD field out-of-range: $args{mod}"
> +        unless 0 <= $args{mod} && $args{mod} <= 3;
> +    die "REG field out-of-range: $args{reg}"
> +        unless 0 <= $args{reg} && $args{reg} <= 7;
> +    die "RM field out-of-range: $args{rm}"
> +        unless 0 <= $args{rm} && $args{rm} <= 7;
> +
> +    return (value =>
> +            ($args{mod} << 6)
> +            | ($args{reg} << 3)
> +            | $args{rm},
> +            len => 1);
> +}
> +
> +sub sib_encode(%)
> +{
> +    my (%args) = @_;
> +
> +    die "SS field out-of-range: $args{ss}"
> +        unless 0 <= $args{ss} && $args{ss} <= 3;
> +    die "INDEX field out-of-range: $args{index}"
> +        unless 0 <= $args{index} && $args{index} <= 7;
> +    die "BASE field out-of-range: $args{base}"
> +        unless 0 <= $args{base} && $args{base} <= 7;
> +
> +    return (value =>
> +            ($args{ss} << 6)
> +            | ($args{index} << 3)
> +            | $args{base},
> +            len => 1);
> +}

These are interdependent, in that SIB requires MODRM.RM == 4.  But I don't see
anything that either enforces that or validates it, either here or within
write_insn below.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: " Jan Bobek
@ 2019-06-27 10:29   ` Richard Henderson
  2019-06-27 10:53     ` Richard Henderson
  2019-06-28 17:06     ` Jan Bobek
  0 siblings, 2 replies; 18+ messages in thread
From: Richard Henderson @ 2019-06-27 10:29 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/19/19 7:04 AM, Jan Bobek wrote:
> +    --x86_64     : generate 64-bit (rather than 32-bit) x86 code.

Better is to use

	.mode	x86.64
vs
	.mode	x86.32

or some such, like we do for aarch64.

> +sub write_mov_reg_imm($$)
> +{
> +    my ($reg, $imm) = @_;
> +
> +    my %insn = (opcode => {value => 0xB8 | ($reg & 0x7), len => 1},
> +                imm => {value => $imm, len => $is_x86_64 ? 8 : 4});
> +
> +    $insn{rex}{w} = 1 if $is_x86_64;
> +    $insn{rex}{b} = 1 if $reg >= 8;
> +
> +    write_insn(%insn);
> +}

There are 3 different insns that x86_64 can use for different ranges of
immediates; you are always using the full 10 byte version.

Using 0xb8 without REX.W may be used for any unsigned 32-bit value.
Using 0xc7 with REX.W may be used for any signed 32-bit value.
Using 0xb8 with REX.W of course allows any 64-bit value.

It's not terribly important, but the code size does get large.

> +sub rand_insn_modrm($$)
> +{
> +    my ($opts, $insn) = @_;
> +    my $modrm;
> +
> +    while (1) {
> +        $modrm = rand_fill({mod => {bitlen => 2},
> +                            reg => {bitlen => 3},
> +                            rm => {bitlen => 3}},
> +                           $opts);
> +
> +        if ($modrm->{mod} != MOD_DIRECT) {
> +            # Displacement only; we cannot use this since we
> +            # don't know absolute address of the memblock.
> +            next if $modrm->{mod} == MOD_INDIRECT && $modrm->{rm} == REG_EBP;
...
> +sub rand_insn_rex($$)
> +{
> +    my ($opts, $insn) = @_;
> +
> +    $opts->{w} = 0 unless defined $opts->{w};
> +    $opts->{x} = 0 unless defined $opts->{x} || defined $insn->{sib};
> +
> +    my $rex = rand_fill({w => {bitlen => 1},
> +                         r => {bitlen => 1},
> +                         b => {bitlen => 1},
> +                         x => {bitlen => 1}},
> +                        $opts);

I don't think it's a good idea to generate reg/rm/sib.index separate from
rex.r/b/x.  In particular, all of your tests vs EBP and ESP are not quite
right, since the final insn may be referencing R12 or R13.

What is your plan for handling the unary insns for which modrm.r is opcode and
not a register?  This doesn't seem to allow for those.  How about insns for
which modrm.mod must be 3 (register) or must be != 3 (memory/address)?  Is this
simply going to fall into "testing of illegal encodings"?


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions
  2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions Jan Bobek
@ 2019-06-27 10:30   ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2019-06-27 10:30 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/19/19 7:04 AM, Jan Bobek wrote:
> Accept all instructions whose bit length is divisible by 8. Note that
> the maximum instruction length (as specified in the config file) is 32
> bits, hence this change permits instructions which are 8 bits or 24
> bits long (16-bit instructions have already been considered valid).
> 
> Note that while valid x86 instructions may be up to 15 bytes long, the
> length constraint described above only applies to the main opcode
> field, which is usually only 1 or 2 bytes long. Therefore, the primary
> purpose of this change is to allow 1-byte x86 opcodes.
> 
> Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
> ---
>  risugen | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-27 10:29   ` Richard Henderson
@ 2019-06-27 10:53     ` Richard Henderson
  2019-06-28 16:03       ` Jan Bobek
  2019-06-28 17:06     ` Jan Bobek
  1 sibling, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2019-06-27 10:53 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/27/19 12:29 PM, Richard Henderson wrote:
> On 6/19/19 7:04 AM, Jan Bobek wrote:
>> +    --x86_64     : generate 64-bit (rather than 32-bit) x86 code.
> Better is to use
> 
> 	.mode	x86.64
> vs
> 	.mode	x86.32
> 
> or some such, like we do for aarch64.
> 

Nevermind.  Unlike aarch64, the same input file can be used for both 32-bit and
64-bit mode, more or less.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill
  2019-06-27  8:53   ` Richard Henderson
@ 2019-06-28 15:10     ` Jan Bobek
  0 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-28 15:10 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Alex Bennée


[-- Attachment #1.1: Type: text/plain, Size: 2435 bytes --]

On 6/27/19 4:53 AM, Richard Henderson wrote:
> On 6/19/19 7:04 AM, Jan Bobek wrote:
>> +        my $value = ($args{bigendian}
>> +                     ? ($args{value} >> (8 * $args{len} - $bitlen))
>> +                     : $args{value});
> ...
>> +        $args{value} >>= $bitlen unless $args{bigendian};
> 
> I think this could be clearer without modifying $args.
> I mis-read these the first time around.
> 
> Perhaps
> 
>     my $bitpos = 0;
>     my $bitend = 8 * $args{len};
>     while ($bitpos < $bitend) {
>         ...
>         my $value = $args{value} >> ($args{bigendian}
>                                      ? $bitend - $bitpos - $bitlen
>                                      : $bitpos);
>         ...
>         $bitpos += $bitlen;
>     }

Looks good, I'll change it.

>> +sub randint_constr(%)
>> +{
>> +    my (%args) = @_;
>> +    my $bitlen = $args{bitlen};
>> +    my $halfrange = 1 << ($bitlen - 1);
>> +
>> +    while (1) {
>> +        my $value = int(rand(2 * $halfrange));
>> +        $value -= $halfrange if defined $args{signed} && $args{signed};
>> +        $value &= ~$args{fixedbitmask} if defined $args{fixedbitmask};
>> +        $value |= $args{fixedbits} if defined $args{fixedbits};
>> +
>> +        if (defined $args{constraint}) {
>> +            if (!($args{constraint} >> 63)) {
>> +                $value = $args{constraint};
>> +            } elsif ($value == ~$args{constraint}) {
>> +                next;
>> +            }
>> +        }
> 
> I don't understand what you're doing here with {constraint}.
> Some additional commentary would help.

The idea is: if the most significant bit of $args{constraint} is zero,
$args{constraint} is the value we want to return; if the most
significant bit is one, ~$args{constraint} (its bit inversion) is the
value we want to *avoid*, so we try again. This is used to to
implement constraints on fields such as

MOVLPS          SSE     00001111 0001001 d !emit { modrm(mod => ~MOD_DIRECT); mem(size => 8); }
MOVLHPS         SSE     00001111 00010110  !emit { modrm(mod => MOD_DIRECT); }

The bitshift by 63 assumes 64-bit integers, but that assumption is
present in other places, too. I couldn't think of a better way to do
it: comparing it to zero doesn't work because the value is unsigned.
I will include a comment explaining this in v2, unless you have
other suggestions.

-Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module
  2019-06-27  9:05   ` Richard Henderson
@ 2019-06-28 15:57     ` Jan Bobek
  0 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-28 15:57 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Alex Bennée


[-- Attachment #1.1: Type: text/plain, Size: 2166 bytes --]

On 6/27/19 5:05 AM, Richard Henderson wrote:
> On 6/19/19 7:04 AM, Jan Bobek wrote:
>> +sub rex_encode(%)
>> +{
>> +    my (%args) = @_;
>> +
>> +    $args{w} = 0 unless defined $args{w};
>> +    $args{r} = 0 unless defined $args{w};
>> +    $args{x} = 0 unless defined $args{w};
>> +    $args{b} = 0 unless defined $args{w};
> 
> What makes you believe that REX.[RXB] are dependent on REX.W?
> Or are these merely cut-and-paste errors?

Oops, that's a typo.

>> +sub modrm_encode(%)
>> +{
>> +    my (%args) = @_;
>> +
>> +    die "MOD field out-of-range: $args{mod}"
>> +        unless 0 <= $args{mod} && $args{mod} <= 3;
>> +    die "REG field out-of-range: $args{reg}"
>> +        unless 0 <= $args{reg} && $args{reg} <= 7;
>> +    die "RM field out-of-range: $args{rm}"
>> +        unless 0 <= $args{rm} && $args{rm} <= 7;
>> +
>> +    return (value =>
>> +            ($args{mod} << 6)
>> +            | ($args{reg} << 3)
>> +            | $args{rm},
>> +            len => 1);
>> +}
>> +
>> +sub sib_encode(%)
>> +{
>> +    my (%args) = @_;
>> +
>> +    die "SS field out-of-range: $args{ss}"
>> +        unless 0 <= $args{ss} && $args{ss} <= 3;
>> +    die "INDEX field out-of-range: $args{index}"
>> +        unless 0 <= $args{index} && $args{index} <= 7;
>> +    die "BASE field out-of-range: $args{base}"
>> +        unless 0 <= $args{base} && $args{base} <= 7;
>> +
>> +    return (value =>
>> +            ($args{ss} << 6)
>> +            | ($args{index} << 3)
>> +            | $args{base},
>> +            len => 1);
>> +}
> 
> These are interdependent, in that SIB requires MODRM.RM == 4.  But I don't see
> anything that either enforces that or validates it, either here or within
> write_insn below.

It also requires MODRM.MOD != 3. You are right, this is not validated
by the risugen_x86_asm module at all; the caller is supposed to know
what they're doing. I also don't validate if displacement is present
when required; the exact conditions are somewhat complicated, already
present in one form or another in risugen_x86 and it generally seemed
like not worth the effort.

-Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-27 10:53     ` Richard Henderson
@ 2019-06-28 16:03       ` Jan Bobek
  0 siblings, 0 replies; 18+ messages in thread
From: Jan Bobek @ 2019-06-28 16:03 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Alex Bennée


[-- Attachment #1.1: Type: text/plain, Size: 652 bytes --]

On 6/27/19 6:53 AM, Richard Henderson wrote:
> On 6/27/19 12:29 PM, Richard Henderson wrote:
>> On 6/19/19 7:04 AM, Jan Bobek wrote:
>>> +    --x86_64     : generate 64-bit (rather than 32-bit) x86 code.
>> Better is to use
>>
>> 	.mode	x86.64
>> vs
>> 	.mode	x86.32
>>
>> or some such, like we do for aarch64.
>>
> 
> Nevermind.  Unlike aarch64, the same input file can be used for both 32-bit and
> 64-bit mode, more or less.

Exactly. :) For the record, I don't like the switch either; in fact,
all the architecture-specific switches in risugen are a bit unsightly,
but I couldn't think of a better solution right away.

-Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-27 10:29   ` Richard Henderson
  2019-06-27 10:53     ` Richard Henderson
@ 2019-06-28 17:06     ` Jan Bobek
  2019-06-29 12:03       ` Richard Henderson
  1 sibling, 1 reply; 18+ messages in thread
From: Jan Bobek @ 2019-06-28 17:06 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Alex Bennée


[-- Attachment #1.1: Type: text/plain, Size: 4303 bytes --]

On 6/27/19 6:29 AM, Richard Henderson wrote:
> On 6/19/19 7:04 AM, Jan Bobek wrote:
>> +sub write_mov_reg_imm($$)
>> +{
>> +    my ($reg, $imm) = @_;
>> +
>> +    my %insn = (opcode => {value => 0xB8 | ($reg & 0x7), len => 1},
>> +                imm => {value => $imm, len => $is_x86_64 ? 8 : 4});
>> +
>> +    $insn{rex}{w} = 1 if $is_x86_64;
>> +    $insn{rex}{b} = 1 if $reg >= 8;
>> +
>> +    write_insn(%insn);
>> +}
> 
> There are 3 different insns that x86_64 can use for different ranges of
> immediates; you are always using the full 10 byte version.
> 
> Using 0xb8 without REX.W may be used for any unsigned 32-bit value.
> Using 0xc7 with REX.W may be used for any signed 32-bit value.
> Using 0xb8 with REX.W of course allows any 64-bit value.
> 
> It's not terribly important, but the code size does get large.

Funnily enough, the very first version of this function did try to
save bytes by using different instructions, but when I started writing
write_mem_getoffset, I ran into trouble with signedness. In response,
I hard-coded the 10 byte version for debugging and then never switched
it back.

I'll try to do something about this in v2.

>> +sub rand_insn_modrm($$)
>> +{
>> +    my ($opts, $insn) = @_;
>> +    my $modrm;
>> +
>> +    while (1) {
>> +        $modrm = rand_fill({mod => {bitlen => 2},
>> +                            reg => {bitlen => 3},
>> +                            rm => {bitlen => 3}},
>> +                           $opts);
>> +
>> +        if ($modrm->{mod} != MOD_DIRECT) {
>> +            # Displacement only; we cannot use this since we
>> +            # don't know absolute address of the memblock.
>> +            next if $modrm->{mod} == MOD_INDIRECT && $modrm->{rm} == REG_EBP;
> ...
>> +sub rand_insn_rex($$)
>> +{
>> +    my ($opts, $insn) = @_;
>> +
>> +    $opts->{w} = 0 unless defined $opts->{w};
>> +    $opts->{x} = 0 unless defined $opts->{x} || defined $insn->{sib};
>> +
>> +    my $rex = rand_fill({w => {bitlen => 1},
>> +                         r => {bitlen => 1},
>> +                         b => {bitlen => 1},
>> +                         x => {bitlen => 1}},
>> +                        $opts);
> 
> I don't think it's a good idea to generate reg/rm/sib.index separate from
> rex.r/b/x.  In particular, all of your tests vs EBP and ESP are not quite
> right, since the final insn may be referencing R12 or R13.

That's true. (Although not in all cases; see Table 2-5 in the Intel Manual,
Volume 2, Chapter 2, Section 2.2.1 "REX Prefixes" for some cases when REX.B
is not decoded.) This is a compromise that I've accepted, at least for v1
of the patch series. Note that this problem is also present in config entries
such as

PMOVMSKB        SSE     00001111 11010111 !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); }

Here, we force MODRM.REG != 4, but this avoids not only ESP/RSP, but
also R12.

Hmmm... I suppose I have some ideas on how to do it better. I'll try
to fix this, though I suspect getting it 100 % right might be
difficult and time-consuming.

> What is your plan for handling the unary insns for which modrm.r is opcode and
> not a register?  This doesn't seem to allow for those.  How about insns for
> which modrm.mod must be 3 (register) or must be != 3 (memory/address)?

Both of these translate to forcing or avoiding a certain value in a field,
which is handled by the $opts argument to rand_fill; I mention this in my
email about the first patch in this series.

> Is this
> simply going to fall into "testing of illegal encodings"?

Speaking of testing of illegal encodings, it occurred to me that it
might be quite hard: since x86 uses variable-length encoding, you
cannot tell how many bytes should be skipped if an invalid instruction
is encountered.

Perhaps we could use a multi-byte NOP with the length embedded in some
of the ignored fields? We could then teach RISU to look at the
preceding instruction and skip the correct number of bytes when
appropriate. Do you think it would be worth the effort? RISU currently
doesn't seem to support this use-case, but it should be
straightforward to implement: just add a record to the trace file
that the instruction generates a SIGILL.

-Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
  2019-06-28 17:06     ` Jan Bobek
@ 2019-06-29 12:03       ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2019-06-29 12:03 UTC (permalink / raw)
  To: Jan Bobek, qemu-devel; +Cc: Alex Bennée

On 6/28/19 7:06 PM, Jan Bobek wrote:
> That's true. (Although not in all cases; see Table 2-5 in the Intel Manual,
> Volume 2, Chapter 2, Section 2.2.1 "REX Prefixes" for some cases when REX.B
> is not decoded.) This is a compromise that I've accepted, at least for v1
> of the patch series. Note that this problem is also present in config entries
> such as
> 
> PMOVMSKB        SSE     00001111 11010111 !emit { modrm(mod => MOD_DIRECT, reg => ~REG_ESP); }
> 
> Here, we force MODRM.REG != 4, but this avoids not only ESP/RSP, but
> also R12.
> 
> Hmmm... I suppose I have some ideas on how to do it better. I'll try
> to fix this, though I suspect getting it 100 % right might be
> difficult and time-consuming.

I wonder if it might be better to do the randomization at a higher level:

* Pick full registers, either 3 bits for 32-bit or 4 bits for 64-bit,
  and eventually 5 bits for avx512 z-regs for evex encoding.  Let
  risugen_x86_asm encode those depending on the chosen encoding.

* Pick only register vs memory for MODRM.MOD.  If memory, randomize
  base + index + shift + disp.  Let risugen_x86_asm encode those
  values into the modrm+sib+offset.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2019-06-29 12:07 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-19  5:04 [Qemu-devel] [RISU RFC PATCH v1 0/7] Support for generating x86 SSE/SSE2 test images Jan Bobek
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 1/7] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
2019-06-27  8:53   ` Richard Henderson
2019-06-28 15:10     ` Jan Bobek
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 2/7] risugen_x86_asm: add module Jan Bobek
2019-06-27  9:05   ` Richard Henderson
2019-06-28 15:57     ` Jan Bobek
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 3/7] risugen_x86_emit: " Jan Bobek
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: " Jan Bobek
2019-06-27 10:29   ` Richard Henderson
2019-06-27 10:53     ` Richard Henderson
2019-06-28 16:03       ` Jan Bobek
2019-06-28 17:06     ` Jan Bobek
2019-06-29 12:03       ` Richard Henderson
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 5/7] risugen: allow all byte-aligned instructions Jan Bobek
2019-06-27 10:30   ` Richard Henderson
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 6/7] x86.risu: add SSE instructions Jan Bobek
2019-06-19  5:04 ` [Qemu-devel] [RISU RFC PATCH v1 7/7] x86.risu: add SSE2 instructions Jan Bobek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).