From nobody Mon Feb 9 02:28:17 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1562884495; cv=none; d=zoho.com; s=zohoarc; b=DZdcNr48NwErtKJmJCJHHfkwM7fI5Xs0+ItgWSAy50BOVTWt0BkShAQdTc5nqW5su0cuq5m7aQre6PXpKYiTNBBhCFfRmxuUf9Sijumzqqp66zjsuSpZZYdPTx+HE2pos8L+E4euUPSz8thXBa6GeAUAoK3YABUyioDrj/yX0cs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562884495; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=B/9ak8o8VhmXZsAeWLe+xR8AkOtaBvxJ+j0gYAHd5PM=; b=AYkBR6IHPcoMFhW164S50cyMytcM6N330tkHveopYZg0WZDab7Hq79XCGqQOJrgVCCgXtY6xnsZEWACWeP9rLUgqPwAXQWLD5WnlE/5+Q1OAj/tI3DVrfbUcVGDEs7PnXv3abV8/fV+ljLl/Aa9F/oTUYfza8DXq/Agbiif1KIg= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1562884495254827.84558739696; Thu, 11 Jul 2019 15:34:55 -0700 (PDT) Received: from localhost ([::1]:45652 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hlheP-00063M-G2 for importer@patchew.org; Thu, 11 Jul 2019 18:34:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40448) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hlhdJ-0001l2-5e for qemu-devel@nongnu.org; Thu, 11 Jul 2019 18:33:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hlhdE-00043m-J0 for qemu-devel@nongnu.org; Thu, 11 Jul 2019 18:33:43 -0400 Received: from mail-yb1-xb44.google.com ([2607:f8b0:4864:20::b44]:40665) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hlhd5-0003ek-Uf for qemu-devel@nongnu.org; Thu, 11 Jul 2019 18:33:37 -0400 Received: by mail-yb1-xb44.google.com with SMTP id i14so3194020ybp.7 for ; Thu, 11 Jul 2019 15:33:17 -0700 (PDT) Received: from dionysus.attlocal.net (69-222-133-165.lightspeed.tukrga.sbcglobal.net. [69.222.133.165]) by smtp.gmail.com with ESMTPSA id z191sm1676728ywa.31.2019.07.11.15.33.16 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 11 Jul 2019 15:33:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=B/9ak8o8VhmXZsAeWLe+xR8AkOtaBvxJ+j0gYAHd5PM=; b=Q5F9oOXeNUupQ8Qvny2hcpWNO1bZarqIS5uyLsvWSNo0QrfssZgwhG7e9rOTiuZyQG EU6ZzN13UAK9US7t/LiCkdGV24UzcqPWLVgHRGqVvIJroASxG22xnm4bUiiLttXZ+ItX 8hPbCo4Oat50R9ZF49sZIsAKmFU68Cht+zgCX4DpaF1qxmJ2tLopaB+gr+s7kfHoIGaK 5RHjrzsNkVdpps6Iu7OC1bO97/UlGdmrztXTG6L4wzu5nM/WJT5BMX7NF95HkUo8TyKq JPOekVW1u5vluWFKDxb3KQiDwBrUgn4ze45y68DR17IbYSBX+vuzwqw3QbhE2k0vBwM0 UnDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=B/9ak8o8VhmXZsAeWLe+xR8AkOtaBvxJ+j0gYAHd5PM=; b=a8bjudsL1s8nFMgfm+yxcQpeoqdTB8wHbzwr5guG1IMkVscrU2iIJs9YiYvOtjN3YS gIRzjQYXBIV+zFQD/feA9t/37dsktlbB7wDbL6vwOBd4oSmhSCA9FJx+7q/2x4t/rzf2 SyY0ktkq1lFlVNypiw6jJA+TEd636ynPoem0q0t0ltxP/AkHSDTOV+LI9ahK/OwhZ0pG vw4huuygNR/6RNHqCP8jvQAPNfwTZ5pS3hlYPJP4hTZw3KwpVxFxFNOQ8MZa0MAmdDoN xansR/s4moLTIs+QQzeBa+c+vKmk0WSok+3eQoeuu2IjqupyWSSNeLYS9ujPpwdhZKMk 1yBQ== X-Gm-Message-State: APjAAAXuUGrSG4Y6IQmQcZEJdyd7eLQiuWsWQMLp/ODtxvk34osVbA4S 9190IjXPAPr8sVLCGL4Wjbz4zQTi X-Google-Smtp-Source: APXvYqyvb9aQ0tspvdRb0hh7HuxoTBm8zu9HwS79EGsSek5rZJO7DnbGIFmGx2BW9ksfZMcDynQxUw== X-Received: by 2002:a05:6902:4e7:: with SMTP id w7mr3927734ybs.389.1562884396900; Thu, 11 Jul 2019 15:33:16 -0700 (PDT) From: Jan Bobek To: qemu-devel@nongnu.org Date: Thu, 11 Jul 2019 18:32:48 -0400 Message-Id: <20190711223300.6061-7-jan.bobek@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711223300.6061-1-jan.bobek@gmail.com> References: <20190711223300.6061-1-jan.bobek@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::b44 Subject: [Qemu-devel] [RISU PATCH v3 06/18] risugen_x86: add module X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jan Bobek , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Richard Henderson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" risugen_x86.pm is the main backend module for Intel i386 and x86_64 architectures; it orchestrates generation of the test code with support from the rest of risugen_x86_* modules. Signed-off-by: Jan Bobek Reviewed-by: Richard Henderson --- risugen_x86.pm | 518 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 risugen_x86.pm diff --git a/risugen_x86.pm b/risugen_x86.pm new file mode 100644 index 0000000..ae11843 --- /dev/null +++ b/risugen_x86.pm @@ -0,0 +1,518 @@ +#!/usr/bin/perl -w +##########################################################################= ##### +# Copyright (c) 2019 Jan Bobek +# 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_constraints; +use risugen_x86_memory; + +require Exporter; + +our @ISA =3D qw(Exporter); +our @EXPORT =3D qw(write_test_code); + +use constant { + RISUOP_COMPARE =3D> 0, # compare registers + RISUOP_TESTEND =3D> 1, # end of test, stop + RISUOP_SETMEMBLOCK =3D> 2, # eax is address of memory block (81= 92 bytes) + RISUOP_GETMEMBLOCK =3D> 3, # add the address of memory block to= eax + RISUOP_COMPAREMEM =3D> 4, # compare memory block + + # Maximum alignment restriction permitted for a memory op. + MAXALIGN =3D> 64, + MEMBLOCK_LEN =3D> 8192, +}; + +my $periodic_reg_random =3D 1; +my $is_x86_64 =3D 0; + +sub wrap_int32($) +{ + my ($x) =3D @_; + my $r =3D 1 << 31; + return ($x + $r) % (2 * $r) - $r; +} + +sub asm_insn_risuop($) +{ + my ($op) =3D @_; + asm_insn_ud1(reg =3D> REG_RAX, reg2 =3D> $op); +} + +sub asm_insn_movT(%) +{ + my (%args) =3D @_; + + if ($is_x86_64) { + asm_insn_mov64(%args); + } else { + asm_insn_mov(%args); + } +} + +sub asm_insn_movT_imm(%) +{ + my (%args) =3D @_; + my $imm =3D $args{imm}; delete $args{imm}; + + my $is_sint32 =3D (-0x80000000 <=3D $imm && $imm <=3D 0x7fffffff); + my $is_uint32 =3D (0 <=3D $imm && $imm <=3D 0xffffffff); + + $args{$is_sint32 || $is_uint32 ? 'imm32' : 'imm64'} =3D $imm; + asm_insn_movT(%args); +} + +sub asm_insn_addT(%) +{ + my (%args) =3D @_; + + if ($is_x86_64) { + asm_insn_add64(%args); + } else { + asm_insn_add(%args); + } +} + +sub asm_insn_negT(%) +{ + my (%args) =3D @_; + + if ($is_x86_64) { + asm_insn_neg64(%args); + } else { + asm_insn_neg(%args); + } +} + +sub asm_insn_xchgT(%) +{ + my (%args) =3D @_; + + if ($is_x86_64) { + asm_insn_xchg64(%args); + } else { + asm_insn_xchg(%args); + } +} + +sub write_random_regdata() +{ + my $reg_cnt =3D $is_x86_64 ? 16 : 8; + my $reg_width =3D $is_x86_64 ? 64 : 32; + + # initialize flags register + asm_insn_xor(reg =3D> REG_RAX, reg2 =3D> REG_RAX); + asm_insn_sahf(); + + # general purpose registers + for (my $reg =3D 0; $reg < $reg_cnt; $reg++) { + if ($reg !=3D REG_RSP) { + my $imm =3D randint(width =3D> $reg_width, signed =3D> 1); + asm_insn_movT_imm(reg =3D> $reg, imm =3D> $imm); + } + } +} + +# At the end of this function, we can emit $datalen data-bytes which +# will be skipped over at runtime, but whose address will be present +# in EAX and optionally aligned. +sub prepare_datablock(%) +{ + my (%args) =3D @_; + $args{align} =3D 0 unless defined $args{align} && $args{align} > 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 the CALL instruction. Then, AND the + # EAX/RAX register with correct mask to obtain the aligned + # address. + my $reg =3D REG_RAX; + + if ($is_x86_64) { + my $disp32 =3D 5; # 5-byte JMP + $disp32 +=3D 4 + ($args{align} - 1) if $args{align}; # 4-byte AND + + asm_insn_lea64(reg =3D> $reg, disp32 =3D> $disp32); + asm_insn_and64(reg2 =3D> $reg, imm8 =3D> ~($args{align} - 1)) + if $args{align}; + } else { + my $imm8 =3D 1 + 3 + 5; # 1-byte POP + 3-byte ADD + 5-byte JMP + $imm8 +=3D 3 + ($args{align} - 1) if $args{align}; # 3-byte AND + + # displacement =3D next instruction + asm_insn_call(imm32 =3D> 0x00000000); + asm_insn_pop(reg =3D> $reg); + asm_insn_add(reg2 =3D> $reg, imm8 =3D> $imm8); + asm_insn_and(reg2 =3D> $reg, imm8 =3D> ~($args{align} - 1)) + if $args{align}; + } + + # JMP over the data blob. + asm_insn_jmp(imm32 =3D> $args{datalen}); +} + +# Write a block of random data, $datalen bytes long, optionally +# aligned, and load its address into EAX/RAX. +sub write_random_datablock(%) +{ + my (%args) =3D @_; + prepare_datablock(%args); + + # Generate the random data + my $datalen =3D $args{datalen}; + for (my $w =3D 8; 0 < $w; $w /=3D 2) { + for (; $w <=3D $datalen; $datalen -=3D $w) { + my $value =3D randint(width =3D> 8 * $w); + insnv(value =3D> $value, width =3D> 8 * $w); + } + } +} + +sub write_random_vregdata(%) +{ + my (%args) =3D @_; + $args{ymm} =3D 0 unless defined $args{ymm}; + $args{xmm} =3D $args{ymm} unless defined $args{xmm}; + $args{mm} =3D 0 unless defined $args{mm}; + + die "cannot initialize YMM registers only\n" + if $args{ymm} && !$args{xmm}; + + my $datalen =3D 0; + + my $mmreg_count =3D 8; + my $mmreg_size =3D 8; + $datalen +=3D $mmreg_count * $mmreg_size if $args{mm}; + + my $xmmreg_count =3D $is_x86_64 ? 16 : 8; + my $xmmreg_size =3D 16; + $datalen +=3D $xmmreg_count * $xmmreg_size if $args{xmm}; + + my $ymmreg_count =3D $xmmreg_count; + my $ymmreg_size =3D 32 - $xmmreg_size; + $datalen +=3D $ymmreg_count * $ymmreg_size if $args{ymm}; + + return unless $datalen > 0; + + # Generate random data blob + write_random_datablock(datalen =3D> $datalen + MAXALIGN - 1, + align =3D> MAXALIGN); + + # Load the random data into vector regs. + my $offset =3D 0; + + if ($args{mm}) { + for (my $mmreg =3D 0; $mmreg < $mmreg_count; $mmreg +=3D 1) { + asm_insn_movq(reg =3D> $mmreg, + base =3D> REG_RAX, + disp32 =3D> $offset); + $offset +=3D $mmreg_size; + } + } + if ($args{ymm}) { + for (my $ymmreg =3D 0; $ymmreg < $ymmreg_count; $ymmreg +=3D 1) { + asm_insn_vmovaps(l =3D> ($xmmreg_size + $ymmreg_size) * 8, + reg =3D> $ymmreg, + base =3D> REG_RAX, + disp32 =3D> $offset); + $offset +=3D $xmmreg_size + $ymmreg_size; + } + } elsif ($args{xmm}) { + for (my $xmmreg =3D 0; $xmmreg < $xmmreg_count; $xmmreg +=3D 1) { + asm_insn_movaps(reg =3D> $xmmreg, + base =3D> REG_RAX, + disp32 =3D> $offset); + $offset +=3D $xmmreg_size; + } + } +} + +sub write_memblock_setup() +{ + # Generate random data blob + write_random_datablock(datalen =3D> MEMBLOCK_LEN + MAXALIGN - 1, + align =3D> MAXALIGN); + + # Pointer is in EAX/RAX; set the memblock + asm_insn_risuop(RISUOP_SETMEMBLOCK); +} + +sub write_random_register_data(%) +{ + my (%args) =3D @_; + write_random_vregdata(%{$args{vregs}}) if defined $args{vregs}; + write_random_regdata(); + asm_insn_risuop(RISUOP_COMPARE); +} + +sub write_mem_getoffset(%) +{ + my (%args) =3D @_; + + my @tokens; + push @tokens, "BASE" if defined $args{base}; + push @tokens, "INDEX" if defined $args{index}; + push @tokens, "VINDEX" if defined $args{vindex}; + push @tokens, "END"; + + # (BASE (INDEX | VINDEX)?)? END + my $token =3D shift @tokens; + + if ($token eq "BASE") { + $token =3D shift @tokens; + # We must not modify RSP during tests, therefore it cannot be a + # base register. + return 0 if $args{base} =3D=3D REG_RSP; + + if ($token eq "VINDEX") { + $token =3D shift @tokens; + + die "VSIB requested, but addrw undefined" + unless defined $args{addrw}; + die "VSIB requested, but count undefined" + unless defined $args{count}; + + write_mem_getoffset_base_vindex(%args); + } elsif ($token eq "INDEX") { + $token =3D shift @tokens; + # RSP cannot be used as an index in regular SIB... And we may + # not modify it anyway. + return 0 if $args{index} =3D=3D REG_RSP; + # If index and base registers are the same, we may not be able + # to honor the alignment requirements. + return 0 if $args{index} =3D=3D $args{base}; + + write_mem_getoffset_base_index(%args); + } else { + write_mem_getoffset_base(%args); + } + } + + die "unexpected junk at the end of getoffset tokens: $token @tokens\n" + unless $token eq "END"; +} + +sub write_mem_getoffset_base(%) +{ + my (%args) =3D @_; + + if ($args{mask}) { + die "size $args{size} is too large for masking" + unless $args{size} <=3D 8; + die "simultaneous alignment and masking not supported" + if $args{align} > 1; + + prepare_datablock(datalen =3D> $args{size}); + + my $width =3D $args{size} * 8; + my $value =3D randint(width =3D> $width); + $value =3D ($value & ~$args{mask}) | ($args{value} & $args{mask}); + insnv(value =3D> $value, width =3D> $width, bigendian =3D> 0); + + my $offset =3D -$args{disp}; + $offset =3D wrap_int32($offset) if !$is_x86_64; + + asm_insn_movT_imm(reg =3D> REG_RDX, imm =3D> $offset); + asm_insn_addT(reg2 =3D> REG_RAX, reg =3D> REG_RDX); + } else { + my $offset =3D int(rand(MEMBLOCK_LEN - $args{size})); + $offset &=3D ~($args{align} - 1); + + $offset -=3D $args{disp}; + $offset =3D wrap_int32($offset) if !$is_x86_64; + + asm_insn_movT_imm(reg =3D> REG_RAX, imm =3D> $offset); + asm_insn_risuop(RISUOP_GETMEMBLOCK); + } + + asm_insn_xchgT(reg =3D> $args{base}, reg2 =3D> REG_RAX) + unless $args{base} =3D=3D REG_RAX; +} + +sub write_mem_getoffset_base_index(%) +{ + my (%args) =3D @_; + + my $addrw =3D ($is_x86_64 ? 64 : 32) - $args{ss} - 1; + my $index =3D randint(width =3D> $addrw, signed =3D> 1); + $args{disp} +=3D $index * (1 << $args{ss}); + + write_mem_getoffset_base(%args); + asm_insn_movT_imm(reg =3D> $args{index}, imm =3D> $index); +} + +sub write_mem_getoffset_base_vindex(%) +{ + my (%args) =3D @_; + + my $addrw =3D $args{addrw} - $args{ss} - 1; + my $base =3D randint(width =3D> $addrw, signed =3D> 1); + $args{disp} +=3D $base * (1 << $args{ss}); + + my $datalen =3D $args{addrw} * $args{count} / 8; + prepare_datablock(datalen =3D> $datalen); + + for(my $i =3D 0; $i < $args{count}; ++$i) { + my $index =3D int(rand(MEMBLOCK_LEN - $args{size})); + $index &=3D ~($args{align} - 1); + $index >>=3D $args{ss}; + + insnv(value =3D> $base + $index, + width =3D> $args{addrw}, + bigendian =3D> 0); + } + + asm_insn_vmovdqu(l =3D> $args{addrw} * $args{count}, + reg =3D> $args{vindex}, + base =3D> REG_RAX); + + write_mem_getoffset_base(%args, size =3D> MEMBLOCK_LEN); +} + +sub write_mem_getoffset_rollback(%) +{ + my (%args) =3D @_; + + # The base register contains an address of the form &memblock + + # offset. We need to turn it into just offset, otherwise we may + # get value mismatches since the memory layout can be different. + asm_insn_xchgT(reg =3D> $args{base}, reg2 =3D> REG_RAX) + unless $args{base} =3D=3D REG_RAX; + asm_insn_negT(reg2 =3D> REG_RAX); + asm_insn_risuop(RISUOP_GETMEMBLOCK); + + # I didn't originally think this was neccessary, but there were + # random sign-flag mismatch failures on 32-bit, probably due to + # the absolute address being randomly in the positive/negative + # range of int32 -- the first NEG would then pollute the EFLAGS + # register with this information. Using another NEG is a neat + # way of overwriting all this information with consistent values. + asm_insn_negT(reg2 =3D> REG_RAX); +} + +sub gen_one_insn($) +{ + # Given an instruction-details array, generate an instruction + my ($rec) =3D @_; + my $insnname =3D $rec->{name}; + my $insnwidth =3D $rec->{width}; + + my $constraintfailures =3D 0; + + my %insn; + my %memopts; + INSN: while(1) { + my $opcode =3D randint(width =3D> 32); + $opcode &=3D ~$rec->{fixedbitmask}; + $opcode |=3D $rec->{fixedbits}; + + # This is not 100 % correct, since $opcode is still padded to + # 32-bit width. This is necessary so that extract_fields in + # eval_constraints_block and eval_memory_block works + # correctly, but we need to fix it up before calling asm_insn. + %insn =3D (); + $insn{opcode}{value} =3D $opcode; + $insn{opcode}{width} =3D $insnwidth; + + my $v =3D eval_constraints_block(rec =3D> $rec, insn =3D> \%insn, + is_x86_64 =3D> $is_x86_64); + if ($v && !$is_x86_64 && defined $insn{rex}) { + # REX.W is part of the opcode; we will never be able to + # generate this instruction in 32-bit mode. + return 0 if defined $insn{rex}{w} && $insn{rex}{w}; + $v =3D 0; + } + if ($v) { + %memopts =3D eval_memory_block(rec =3D> $rec, insn =3D> \%insn= ); + $v =3D write_mem_getoffset(%memopts); + } + if (!$v) { + $constraintfailures++; + if ($constraintfailures > 10000) { + print "10000 consecutive constraint failures for $insnname= constraints\n"; + exit (1); + } + next INSN; + } + + # OK, we got a good one + $constraintfailures =3D 0; + + # Get rid of the extra padding before calling asm_insn; see + # above for details. + $insn{opcode}{value} >>=3D 32 - $insnwidth; + + asm_insn(%insn); + write_mem_getoffset_rollback(%memopts) if $memopts{rollback}; + asm_insn_risuop(RISUOP_COMPAREMEM) if $memopts{is_write}; + asm_insn_risuop(RISUOP_COMPARE); + + return 1; + } +} + +sub write_test_code($) +{ + my ($params) =3D @_; + + my $numinsns =3D $params->{ 'numinsns' }; + my $outfile =3D $params->{ 'outfile' }; + + my %insn_details =3D %{ $params->{ 'details' } }; + my @keys =3D @{ $params->{ 'keys' } }; + + $is_x86_64 =3D $params->{ 'x86_64' }; + my $xfeatures =3D $params->{ 'xfeatures' }; + + my %vregs =3D (); + $vregs{ymm} =3D $xfeatures eq 'avx'; + $vregs{xmm} =3D $vregs{ymm} || $xfeatures eq 'sse'; + $vregs{mm} =3D $vregs{xmm} || $xfeatures eq 'mmx'; + + 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 afterw= ards. + write_random_register_data(vregs =3D> \%vregs); + + for (my $i =3D 0; $i < $numinsns;) { + my $insn_enc =3D $keys[int rand (@keys)]; + + next if !gen_one_insn($insn_details{$insn_enc}); + $i +=3D 1; + + # Rewrite the registers periodically. This avoids the tendency + # for the VFP registers to decay to NaNs and zeroes. + if ($periodic_reg_random && ($i % 100) =3D=3D 0) { + write_random_register_data(vregs =3D> \%vregs); + } + progress_update($i); + } + asm_insn_risuop(RISUOP_TESTEND); + progress_end(); + close_bin(); +} + +1; --=20 2.20.1