public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Tomas Mraz <tmraz@fedoraproject.org>
To: git-commits@fedoraproject.org
Subject: [rpms/openssl] rebase_40beta: add S390x chacha20-poly1305 assembler support from master branch
Date: Tue, 09 Jun 2026 12:44:29 GMT	[thread overview]
Message-ID: <178100906903.1.12836358596486699200.rpms-openssl-569a3cb91727@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/openssl
Branch : rebase_40beta
Commit : 569a3cb9172744b0ba3d329cb83d6e1a0e4f4d41
Author : Tomas Mraz <tmraz@fedoraproject.org>
Date   : 2019-05-06T11:07:12+02:00
Stats  : +5597/-1 in 2 file(s)
URL    : https://src.fedoraproject.org/rpms/openssl/c/569a3cb9172744b0ba3d329cb83d6e1a0e4f4d41?branch=rebase_40beta

Log:
add S390x chacha20-poly1305 assembler support from master branch

---
diff --git a/openssl-1.1.1-s390x-update.patch b/openssl-1.1.1-s390x-update.patch
new file mode 100644
index 0000000..f82b0ec
--- /dev/null
+++ b/openssl-1.1.1-s390x-update.patch
@@ -0,0 +1,5591 @@
+diff -up openssl-1.1.1b/crypto/chacha/asm/chacha-s390x.pl.s390x-update openssl-1.1.1b/crypto/chacha/asm/chacha-s390x.pl
+--- openssl-1.1.1b/crypto/chacha/asm/chacha-s390x.pl.s390x-update	2019-02-26 15:15:30.000000000 +0100
++++ openssl-1.1.1b/crypto/chacha/asm/chacha-s390x.pl	2019-05-06 10:59:30.859784823 +0200
+@@ -1,5 +1,5 @@
+ #! /usr/bin/env perl
+-# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
++# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
+ #
+ # Licensed under the OpenSSL license (the "License").  You may not use
+ # this file except in compliance with the License.  You can obtain a copy
+@@ -20,41 +20,53 @@
+ #
+ # 3 times faster than compiler-generated code.
+ 
+-$flavour = shift;
++#
++# August 2018
++#
++# Add vx code path: 4x"vertical".
++#
++# Copyright IBM Corp. 2018
++# Author: Patrick Steuer <patrick.steuer@de.ibm.com>
++
++#
++# February 2019
++#
++# Add 6x"horizontal" VX implementation. It's ~25% faster than IBM's
++# 4x"vertical" submission [on z13] and >3 faster than scalar code.
++# But to harness overheads revert to transliteration of VSX code path
++# from chacha-ppc module, which is also 4x"vertical", to handle inputs
++# not longer than 256 bytes.
++
++use strict;
++use FindBin qw($Bin);
++use lib "$Bin/../..";
++use perlasm::s390x qw(:DEFAULT :VX :LD AUTOLOAD LABEL INCLUDE);
+ 
++my $flavour = shift;
++
++my ($z,$SIZE_T);
+ if ($flavour =~ /3[12]/) {
++	$z=0;	# S/390 ABI
+ 	$SIZE_T=4;
+-	$g="";
+ } else {
++	$z=1;	# zSeries ABI
+ 	$SIZE_T=8;
+-	$g="g";
+ }
+ 
++my $output;
+ while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
+-open STDOUT,">$output";
+-
+-sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
+-{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+-    $code .= "\t$opcode\t".join(',',@_)."\n";
+-}
+ 
+ my $sp="%r15";
+-
+ my $stdframe=16*$SIZE_T+4*8;
+-my $frame=$stdframe+4*20;
+-
+-my ($out,$inp,$len,$key,$counter)=map("%r$_",(2..6));
+ 
++sub ROUND {
+ my @x=map("%r$_",(0..7,"x","x","x","x",(10..13)));
+ my @t=map("%r$_",(8,9));
+-
+-sub ROUND {
+ my ($a0,$b0,$c0,$d0)=@_;
+ my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+ my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+ my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+-my ($xc,$xc_)=map("\"$_\"",@t);
+-my @x=map("\"$_\"",@x);
++my ($xc,$xc_)=map("$_",@t);
+ 
+ 	# Consider order in which variables are addressed by their
+ 	# index:
+@@ -78,249 +90,967 @@ my @x=map("\"$_\"",@x);
+ 	# 'c' stores and loads in the middle, but none in the beginning
+ 	# or end.
+ 
+-	(
+-	"&alr	(@x[$a0],@x[$b0])",	# Q1
+-	 "&alr	(@x[$a1],@x[$b1])",	# Q2
+-	"&xr	(@x[$d0],@x[$a0])",
+-	 "&xr	(@x[$d1],@x[$a1])",
+-	"&rll	(@x[$d0],@x[$d0],16)",
+-	 "&rll	(@x[$d1],@x[$d1],16)",
+-
+-	"&alr	($xc,@x[$d0])",
+-	 "&alr	($xc_,@x[$d1])",
+-	"&xr	(@x[$b0],$xc)",
+-	 "&xr	(@x[$b1],$xc_)",
+-	"&rll	(@x[$b0],@x[$b0],12)",
+-	 "&rll	(@x[$b1],@x[$b1],12)",
+-
+-	"&alr	(@x[$a0],@x[$b0])",
+-	 "&alr	(@x[$a1],@x[$b1])",
+-	"&xr	(@x[$d0],@x[$a0])",
+-	 "&xr	(@x[$d1],@x[$a1])",
+-	"&rll	(@x[$d0],@x[$d0],8)",
+-	 "&rll	(@x[$d1],@x[$d1],8)",
+-
+-	"&alr	($xc,@x[$d0])",
+-	 "&alr	($xc_,@x[$d1])",
+-	"&xr	(@x[$b0],$xc)",
+-	 "&xr	(@x[$b1],$xc_)",
+-	"&rll	(@x[$b0],@x[$b0],7)",
+-	 "&rll	(@x[$b1],@x[$b1],7)",
+-
+-	"&stm	($xc,$xc_,'$stdframe+4*8+4*$c0($sp)')",	# reload pair of 'c's
+-	"&lm	($xc,$xc_,'$stdframe+4*8+4*$c2($sp)')",
+-
+-	"&alr	(@x[$a2],@x[$b2])",	# Q3
+-	 "&alr	(@x[$a3],@x[$b3])",	# Q4
+-	"&xr	(@x[$d2],@x[$a2])",
+-	 "&xr	(@x[$d3],@x[$a3])",
+-	"&rll	(@x[$d2],@x[$d2],16)",
+-	 "&rll	(@x[$d3],@x[$d3],16)",
+-
+-	"&alr	($xc,@x[$d2])",
+-	 "&alr	($xc_,@x[$d3])",
+-	"&xr	(@x[$b2],$xc)",
+-	 "&xr	(@x[$b3],$xc_)",
+-	"&rll	(@x[$b2],@x[$b2],12)",
+-	 "&rll	(@x[$b3],@x[$b3],12)",
+-
+-	"&alr	(@x[$a2],@x[$b2])",
+-	 "&alr	(@x[$a3],@x[$b3])",
+-	"&xr	(@x[$d2],@x[$a2])",
+-	 "&xr	(@x[$d3],@x[$a3])",
+-	"&rll	(@x[$d2],@x[$d2],8)",
+-	 "&rll	(@x[$d3],@x[$d3],8)",
+-
+-	"&alr	($xc,@x[$d2])",
+-	 "&alr	($xc_,@x[$d3])",
+-	"&xr	(@x[$b2],$xc)",
+-	 "&xr	(@x[$b3],$xc_)",
+-	"&rll	(@x[$b2],@x[$b2],7)",
+-	 "&rll	(@x[$b3],@x[$b3],7)"
+-	);
+-}
+-
+-$code.=<<___;
+-.text
+-
+-.globl	ChaCha20_ctr32
+-.type	ChaCha20_ctr32,\@function
+-.align	32
+-ChaCha20_ctr32:
+-	lt${g}r	$len,$len			# $len==0?
+-	bzr	%r14
+-	a${g}hi	$len,-64
+-	l${g}hi	%r1,-$frame
+-	stm${g}	%r6,%r15,`6*$SIZE_T`($sp)
+-	sl${g}r	$out,$inp			# difference
+-	la	$len,0($inp,$len)		# end of input minus 64
+-	larl	%r7,.Lsigma
+-	lgr	%r0,$sp
+-	la	$sp,0(%r1,$sp)
+-	st${g}	%r0,0($sp)
+-
+-	lmg	%r8,%r11,0($key)		# load key
+-	lmg	%r12,%r13,0($counter)		# load counter
+-	lmg	%r6,%r7,0(%r7)			# load sigma constant
+-
+-	la	%r14,0($inp)
+-	st${g}	$out,$frame+3*$SIZE_T($sp)
+-	st${g}	$len,$frame+4*$SIZE_T($sp)
+-	stmg	%r6,%r13,$stdframe($sp)		# copy key schedule to stack
+-	srlg	@x[12],%r12,32			# 32-bit counter value
+-	j	.Loop_outer
+-
+-.align	16
+-.Loop_outer:
+-	lm	@x[0],@x[7],$stdframe+4*0($sp)		# load x[0]-x[7]
+-	lm	@t[0],@t[1],$stdframe+4*10($sp)		# load x[10]-x[11]
+-	lm	@x[13],@x[15],$stdframe+4*13($sp)	# load x[13]-x[15]
+-	stm	@t[0],@t[1],$stdframe+4*8+4*10($sp)	# offload x[10]-x[11]
+-	lm	@t[0],@t[1],$stdframe+4*8($sp)		# load x[8]-x[9]
+-	st	@x[12],$stdframe+4*12($sp)		# save counter
+-	st${g}	%r14,$frame+2*$SIZE_T($sp)		# save input pointer
+-	lhi	%r14,10
+-	j	.Loop
+-
+-.align	4
+-.Loop:
+-___
+-	foreach (&ROUND(0, 4, 8,12)) { eval; }
+-	foreach (&ROUND(0, 5,10,15)) { eval; }
+-$code.=<<___;
+-	brct	%r14,.Loop
+-
+-	l${g}	%r14,$frame+2*$SIZE_T($sp)		# pull input pointer
+-	stm	@t[0],@t[1],$stdframe+4*8+4*8($sp)	# offload x[8]-x[9]
+-	lm${g}	@t[0],@t[1],$frame+3*$SIZE_T($sp)
+-
+-	al	@x[0],$stdframe+4*0($sp)	# accumulate key schedule
+-	al	@x[1],$stdframe+4*1($sp)
+-	al	@x[2],$stdframe+4*2($sp)
+-	al	@x[3],$stdframe+4*3($sp)
+-	al	@x[4],$stdframe+4*4($sp)
+-	al	@x[5],$stdframe+4*5($sp)
+-	al	@x[6],$stdframe+4*6($sp)
+-	al	@x[7],$stdframe+4*7($sp)
+-	lrvr	@x[0],@x[0]
+-	lrvr	@x[1],@x[1]
+-	lrvr	@x[2],@x[2]
+-	lrvr	@x[3],@x[3]
+-	lrvr	@x[4],@x[4]
+-	lrvr	@x[5],@x[5]
+-	lrvr	@x[6],@x[6]
+-	lrvr	@x[7],@x[7]
+-	al	@x[12],$stdframe+4*12($sp)
+-	al	@x[13],$stdframe+4*13($sp)
+-	al	@x[14],$stdframe+4*14($sp)
+-	al	@x[15],$stdframe+4*15($sp)
+-	lrvr	@x[12],@x[12]
+-	lrvr	@x[13],@x[13]
+-	lrvr	@x[14],@x[14]
+-	lrvr	@x[15],@x[15]
+-
+-	la	@t[0],0(@t[0],%r14)		# reconstruct output pointer
+-	cl${g}r	%r14,@t[1]
+-	jh	.Ltail
+-
+-	x	@x[0],4*0(%r14)			# xor with input
+-	x	@x[1],4*1(%r14)
+-	st	@x[0],4*0(@t[0])		# store output
+-	x	@x[2],4*2(%r14)
+-	st	@x[1],4*1(@t[0])
+-	x	@x[3],4*3(%r14)
+-	st	@x[2],4*2(@t[0])
+-	x	@x[4],4*4(%r14)
+-	st	@x[3],4*3(@t[0])
+-	 lm	@x[0],@x[3],$stdframe+4*8+4*8($sp)	# load x[8]-x[11]
+-	x	@x[5],4*5(%r14)
+-	st	@x[4],4*4(@t[0])
+-	x	@x[6],4*6(%r14)
+-	 al	@x[0],$stdframe+4*8($sp)
+-	st	@x[5],4*5(@t[0])
+-	x	@x[7],4*7(%r14)
+-	 al	@x[1],$stdframe+4*9($sp)
+-	st	@x[6],4*6(@t[0])
+-	x	@x[12],4*12(%r14)
+-	 al	@x[2],$stdframe+4*10($sp)
+-	st	@x[7],4*7(@t[0])
+-	x	@x[13],4*13(%r14)
+-	 al	@x[3],$stdframe+4*11($sp)
+-	st	@x[12],4*12(@t[0])
+-	x	@x[14],4*14(%r14)
+-	st	@x[13],4*13(@t[0])
+-	x	@x[15],4*15(%r14)
+-	st	@x[14],4*14(@t[0])
+-	 lrvr	@x[0],@x[0]
+-	st	@x[15],4*15(@t[0])
+-	 lrvr	@x[1],@x[1]
+-	 lrvr	@x[2],@x[2]
+-	 lrvr	@x[3],@x[3]
+-	lhi	@x[12],1
+-	 x	@x[0],4*8(%r14)
+-	al	@x[12],$stdframe+4*12($sp)	# increment counter
+-	 x	@x[1],4*9(%r14)
+-	 st	@x[0],4*8(@t[0])
+-	 x	@x[2],4*10(%r14)
+-	 st	@x[1],4*9(@t[0])
+-	 x	@x[3],4*11(%r14)
+-	 st	@x[2],4*10(@t[0])
+-	 st	@x[3],4*11(@t[0])
+-
+-	cl${g}r	%r14,@t[1]			# done yet?
+-	la	%r14,64(%r14)
+-	jl	.Loop_outer
+-
+-.Ldone:
+-	xgr	%r0,%r0
+-	xgr	%r1,%r1
+-	xgr	%r2,%r2
+-	xgr	%r3,%r3
+-	stmg	%r0,%r3,$stdframe+4*4($sp)	# wipe key copy
+-	stmg	%r0,%r3,$stdframe+4*12($sp)
+-
+-	lm${g}	%r6,%r15,`$frame+6*$SIZE_T`($sp)
+-	br	%r14
+-
+-.align	16
+-.Ltail:
+-	la	@t[1],64($t[1])
+-	stm	@x[0],@x[7],$stdframe+4*0($sp)
+-	sl${g}r	@t[1],%r14
+-	lm	@x[0],@x[3],$stdframe+4*8+4*8($sp)
+-	l${g}hi	@x[6],0
+-	stm	@x[12],@x[15],$stdframe+4*12($sp)
+-	al	@x[0],$stdframe+4*8($sp)
+-	al	@x[1],$stdframe+4*9($sp)
+-	al	@x[2],$stdframe+4*10($sp)
+-	al	@x[3],$stdframe+4*11($sp)
+-	lrvr	@x[0],@x[0]
+-	lrvr	@x[1],@x[1]
+-	lrvr	@x[2],@x[2]
+-	lrvr	@x[3],@x[3]
+-	stm	@x[0],@x[3],$stdframe+4*8($sp)
+-
+-.Loop_tail:
+-	llgc	@x[4],0(@x[6],%r14)
+-	llgc	@x[5],$stdframe(@x[6],$sp)
+-	xr	@x[5],@x[4]
+-	stc	@x[5],0(@x[6],@t[0])
+-	la	@x[6],1(@x[6])
+-	brct	@t[1],.Loop_tail
+-
+-	j	.Ldone
+-.size	ChaCha20_ctr32,.-ChaCha20_ctr32
+-
+-.align	32
+-.Lsigma:
+-.long	0x61707865,0x3320646e,0x79622d32,0x6b206574	# endian-neutral
+-.asciz	"ChaCha20 for s390x, CRYPTOGAMS by <appro\@openssl.org>"
+-.align	4
+-___
++	alr	(@x[$a0],@x[$b0]);	# Q1
++	 alr	(@x[$a1],@x[$b1]);	# Q2
++	xr	(@x[$d0],@x[$a0]);
++	 xr	(@x[$d1],@x[$a1]);
++	rll	(@x[$d0],@x[$d0],16);
++	 rll	(@x[$d1],@x[$d1],16);
++
++	alr	($xc,@x[$d0]);
++	 alr	($xc_,@x[$d1]);
++	xr	(@x[$b0],$xc);
++	 xr	(@x[$b1],$xc_);
++	rll	(@x[$b0],@x[$b0],12);
++	 rll	(@x[$b1],@x[$b1],12);
++
++	alr	(@x[$a0],@x[$b0]);
++	 alr	(@x[$a1],@x[$b1]);
++	xr	(@x[$d0],@x[$a0]);
++	 xr	(@x[$d1],@x[$a1]);
++	rll	(@x[$d0],@x[$d0],8);
++	 rll	(@x[$d1],@x[$d1],8);
++
++	alr	($xc,@x[$d0]);
++	 alr	($xc_,@x[$d1]);
++	xr	(@x[$b0],$xc);
++	 xr	(@x[$b1],$xc_);
++	rll	(@x[$b0],@x[$b0],7);
++	 rll	(@x[$b1],@x[$b1],7);
++
++	stm	($xc,$xc_,"$stdframe+4*8+4*$c0($sp)");	# reload pair of 'c's
++	lm	($xc,$xc_,"$stdframe+4*8+4*$c2($sp)");
++
++	alr	(@x[$a2],@x[$b2]);	# Q3
++	 alr	(@x[$a3],@x[$b3]);	# Q4
++	xr	(@x[$d2],@x[$a2]);
++	 xr	(@x[$d3],@x[$a3]);
++	rll	(@x[$d2],@x[$d2],16);
++	 rll	(@x[$d3],@x[$d3],16);
++
++	alr	($xc,@x[$d2]);
++	 alr	($xc_,@x[$d3]);
++	xr	(@x[$b2],$xc);
++	 xr	(@x[$b3],$xc_);
++	rll	(@x[$b2],@x[$b2],12);
++	 rll	(@x[$b3],@x[$b3],12);
++
++	alr	(@x[$a2],@x[$b2]);
++	 alr	(@x[$a3],@x[$b3]);
++	xr	(@x[$d2],@x[$a2]);
++	 xr	(@x[$d3],@x[$a3]);
++	rll	(@x[$d2],@x[$d2],8);
++	 rll	(@x[$d3],@x[$d3],8);
++
++	alr	($xc,@x[$d2]);
++	 alr	($xc_,@x[$d3]);
++	xr	(@x[$b2],$xc);
++	 xr	(@x[$b3],$xc_);
++	rll	(@x[$b2],@x[$b2],7);
++	 rll	(@x[$b3],@x[$b3],7);
++}
++
++sub VX_lane_ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my @x=map("%v$_",(0..15));
+ 
+-foreach (split("\n",$code)) {
+-	s/\`([^\`]*)\`/eval $1/ge;
++	vaf	(@x[$a0],@x[$a0],@x[$b0]);	# Q1
++	vx	(@x[$d0],@x[$d0],@x[$a0]);
++	verllf	(@x[$d0],@x[$d0],16);
++	vaf	(@x[$a1],@x[$a1],@x[$b1]);	# Q2
++	vx	(@x[$d1],@x[$d1],@x[$a1]);
++	verllf	(@x[$d1],@x[$d1],16);
++	vaf	(@x[$a2],@x[$a2],@x[$b2]);	# Q3
++	vx	(@x[$d2],@x[$d2],@x[$a2]);
++	verllf	(@x[$d2],@x[$d2],16);
++	vaf	(@x[$a3],@x[$a3],@x[$b3]);	# Q4
++	vx	(@x[$d3],@x[$d3],@x[$a3]);
++	verllf	(@x[$d3],@x[$d3],16);
++
++	vaf	(@x[$c0],@x[$c0],@x[$d0]);
++	vx	(@x[$b0],@x[$b0],@x[$c0]);
++	verllf	(@x[$b0],@x[$b0],12);
++	vaf	(@x[$c1],@x[$c1],@x[$d1]);
++	vx	(@x[$b1],@x[$b1],@x[$c1]);
++	verllf	(@x[$b1],@x[$b1],12);
++	vaf	(@x[$c2],@x[$c2],@x[$d2]);
++	vx	(@x[$b2],@x[$b2],@x[$c2]);
++	verllf	(@x[$b2],@x[$b2],12);
++	vaf	(@x[$c3],@x[$c3],@x[$d3]);
++	vx	(@x[$b3],@x[$b3],@x[$c3]);
++	verllf	(@x[$b3],@x[$b3],12);
++
++	vaf	(@x[$a0],@x[$a0],@x[$b0]);
++	vx	(@x[$d0],@x[$d0],@x[$a0]);
++	verllf	(@x[$d0],@x[$d0],8);
++	vaf	(@x[$a1],@x[$a1],@x[$b1]);
++	vx	(@x[$d1],@x[$d1],@x[$a1]);
++	verllf	(@x[$d1],@x[$d1],8);
++	vaf	(@x[$a2],@x[$a2],@x[$b2]);
++	vx	(@x[$d2],@x[$d2],@x[$a2]);
++	verllf	(@x[$d2],@x[$d2],8);
++	vaf	(@x[$a3],@x[$a3],@x[$b3]);
++	vx	(@x[$d3],@x[$d3],@x[$a3]);
++	verllf	(@x[$d3],@x[$d3],8);
++
++	vaf	(@x[$c0],@x[$c0],@x[$d0]);
++	vx	(@x[$b0],@x[$b0],@x[$c0]);
++	verllf	(@x[$b0],@x[$b0],7);
++	vaf	(@x[$c1],@x[$c1],@x[$d1]);
++	vx	(@x[$b1],@x[$b1],@x[$c1]);
++	verllf	(@x[$b1],@x[$b1],7);
++	vaf	(@x[$c2],@x[$c2],@x[$d2]);
++	vx	(@x[$b2],@x[$b2],@x[$c2]);
++	verllf	(@x[$b2],@x[$b2],7);
++	vaf	(@x[$c3],@x[$c3],@x[$d3]);
++	vx	(@x[$b3],@x[$b3],@x[$c3]);
++	verllf	(@x[$b3],@x[$b3],7);
++}
+ 
+-	print $_,"\n";
++sub VX_ROUND {
++my @a=@_[0..5];
++my @b=@_[6..11];
++my @c=@_[12..17];
++my @d=@_[18..23];
++my $odd=@_[24];
++
++	vaf		(@a[$_],@a[$_],@b[$_]) for (0..5);
++	vx		(@d[$_],@d[$_],@a[$_]) for (0..5);
++	verllf		(@d[$_],@d[$_],16) for (0..5);
++
++	vaf		(@c[$_],@c[$_],@d[$_]) for (0..5);
++	vx		(@b[$_],@b[$_],@c[$_]) for (0..5);
++	verllf		(@b[$_],@b[$_],12) for (0..5);
++
++	vaf		(@a[$_],@a[$_],@b[$_]) for (0..5);
++	vx		(@d[$_],@d[$_],@a[$_]) for (0..5);
++	verllf		(@d[$_],@d[$_],8) for (0..5);
++
++	vaf		(@c[$_],@c[$_],@d[$_]) for (0..5);
++	vx		(@b[$_],@b[$_],@c[$_]) for (0..5);
++	verllf		(@b[$_],@b[$_],7) for (0..5);
++
++	vsldb		(@c[$_],@c[$_],@c[$_],8) for (0..5);
++	vsldb		(@b[$_],@b[$_],@b[$_],$odd?12:4) for (0..5);
++	vsldb		(@d[$_],@d[$_],@d[$_],$odd?4:12) for (0..5);
+ }
+-close STDOUT;
++
++PERLASM_BEGIN($output);
++
++INCLUDE	("s390x_arch.h");
++TEXT	();
++
++################
++# void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp, size_t len,
++#                     const unsigned int key[8], const unsigned int counter[4])
++my ($out,$inp,$len,$key,$counter)=map("%r$_",(2..6));
++{
++my $frame=$stdframe+4*20;
++my @x=map("%r$_",(0..7,"x","x","x","x",(10..13)));
++my @t=map("%r$_",(8,9));
++
++GLOBL	("ChaCha20_ctr32");
++TYPE	("ChaCha20_ctr32","\@function");
++ALIGN	(32);
++LABEL	("ChaCha20_ctr32");
++	larl	("%r1","OPENSSL_s390xcap_P");
++
++	lghi	("%r0",64);
++&{$z?	\&ltgr:\&ltr}	($len,$len);		# len==0?
++	bzr	("%r14");
++	lg	("%r1","S390X_STFLE+16(%r1)");
++&{$z?	\&clgr:\&clr}	($len,"%r0");
++	jle	(".Lshort");
++
++	tmhh	("%r1",0x4000);			# check for vx bit
++	jnz	(".LChaCha20_ctr32_vx");
++
++LABEL	(".Lshort");
++&{$z?	\&aghi:\&ahi}	($len,-64);
++&{$z?	\&lghi:\&lhi}	("%r1",-$frame);
++&{$z?	\&stmg:\&stm}	("%r6","%r15","6*$SIZE_T($sp)");
++&{$z?	\&slgr:\&slr}	($out,$inp);	# difference
++	la	($len,"0($inp,$len)");	# end of input minus 64
++	larl	("%r7",".Lsigma");
++	lgr	("%r0",$sp);
++	la	($sp,"0(%r1,$sp)");
++&{$z?	\&stg:\&st}	("%r0","0($sp)");
++
++	lmg	("%r8","%r11","0($key)");	# load key
++	lmg	("%r12","%r13","0($counter)");	# load counter
++	lmg	("%r6","%r7","0(%r7)");	# load sigma constant
++
++	la	("%r14","0($inp)");
++&{$z?	\&stg:\&st}	($out,"$frame+3*$SIZE_T($sp)");
++&{$z?	\&stg:\&st}	($len,"$frame+4*$SIZE_T($sp)");
++	stmg	("%r6","%r13","$stdframe($sp)");# copy key schedule to stack
++	srlg	(@x[12],"%r12",32);	# 32-bit counter value
++	j	(".Loop_outer");
++
++ALIGN	(16);
++LABEL	(".Loop_outer");
++	lm	(@x[0],@x[7],"$stdframe+4*0($sp)");	# load x[0]-x[7]
++	lm	(@t[0],@t[1],"$stdframe+4*10($sp)");	# load x[10]-x[11]
++	lm	(@x[13],@x[15],"$stdframe+4*13($sp)");	# load x[13]-x[15]
++	stm	(@t[0],@t[1],"$stdframe+4*8+4*10($sp)");# offload x[10]-x[11]
++	lm	(@t[0],@t[1],"$stdframe+4*8($sp)");	# load x[8]-x[9]
++	st	(@x[12],"$stdframe+4*12($sp)");	# save counter
++&{$z?	\&stg:\&st}	("%r14","$frame+2*$SIZE_T($sp)");# save input pointer
++	lhi	("%r14",10);
++	j	(".Loop");
++
++ALIGN	(4);
++LABEL	(".Loop");
++	ROUND	(0, 4, 8,12);
++	ROUND	(0, 5,10,15);
++	brct	("%r14",".Loop");
++
++&{$z?	\&lg:\&l}	("%r14","$frame+2*$SIZE_T($sp)");# pull input pointer
++	stm	(@t[0],@t[1],"$stdframe+4*8+4*8($sp)");	# offload x[8]-x[9]
++&{$z?	\&lmg:\&lm}	(@t[0],@t[1],"$frame+3*$SIZE_T($sp)");
++
++	al	(@x[0],"$stdframe+4*0($sp)");	# accumulate key schedule
++	al	(@x[1],"$stdframe+4*1($sp)");
++	al	(@x[2],"$stdframe+4*2($sp)");
++	al	(@x[3],"$stdframe+4*3($sp)");
++	al	(@x[4],"$stdframe+4*4($sp)");
++	al	(@x[5],"$stdframe+4*5($sp)");
++	al	(@x[6],"$stdframe+4*6($sp)");
++	al	(@x[7],"$stdframe+4*7($sp)");
++	lrvr	(@x[0],@x[0]);
++	lrvr	(@x[1],@x[1]);
++	lrvr	(@x[2],@x[2]);
++	lrvr	(@x[3],@x[3]);
++	lrvr	(@x[4],@x[4]);
++	lrvr	(@x[5],@x[5]);
++	lrvr	(@x[6],@x[6]);
++	lrvr	(@x[7],@x[7]);
++	al	(@x[12],"$stdframe+4*12($sp)");
++	al	(@x[13],"$stdframe+4*13($sp)");
++	al	(@x[14],"$stdframe+4*14($sp)");
++	al	(@x[15],"$stdframe+4*15($sp)");
++	lrvr	(@x[12],@x[12]);
++	lrvr	(@x[13],@x[13]);
++	lrvr	(@x[14],@x[14]);
++	lrvr	(@x[15],@x[15]);
++
++	la	(@t[0],"0(@t[0],%r14)");	# reconstruct output pointer
++&{$z?	\&clgr:\&clr}	("%r14",@t[1]);
++	jh	(".Ltail");
++
++	x	(@x[0],"4*0(%r14)");	# xor with input
++	x	(@x[1],"4*1(%r14)");
++	st	(@x[0],"4*0(@t[0])");	# store output
++	x	(@x[2],"4*2(%r14)");
++	st	(@x[1],"4*1(@t[0])");
++	x	(@x[3],"4*3(%r14)");
++	st	(@x[2],"4*2(@t[0])");
++	x	(@x[4],"4*4(%r14)");
++	st	(@x[3],"4*3(@t[0])");
++	 lm	(@x[0],@x[3],"$stdframe+4*8+4*8($sp)");	# load x[8]-x[11]
++	x	(@x[5],"4*5(%r14)");
++	st	(@x[4],"4*4(@t[0])");
++	x	(@x[6],"4*6(%r14)");
++	 al	(@x[0],"$stdframe+4*8($sp)");
++	st	(@x[5],"4*5(@t[0])");
++	x	(@x[7],"4*7(%r14)");
++	 al	(@x[1],"$stdframe+4*9($sp)");
++	st	(@x[6],"4*6(@t[0])");
++	x	(@x[12],"4*12(%r14)");
++	 al	(@x[2],"$stdframe+4*10($sp)");
++	st	(@x[7],"4*7(@t[0])");
++	x	(@x[13],"4*13(%r14)");
++	 al	(@x[3],"$stdframe+4*11($sp)");
++	st	(@x[12],"4*12(@t[0])");
++	x	(@x[14],"4*14(%r14)");
++	st	(@x[13],"4*13(@t[0])");
++	x	(@x[15],"4*15(%r14)");
++	st	(@x[14],"4*14(@t[0])");
++	 lrvr	(@x[0],@x[0]);
++	st	(@x[15],"4*15(@t[0])");
++	 lrvr	(@x[1],@x[1]);
++	 lrvr	(@x[2],@x[2]);
++	 lrvr	(@x[3],@x[3]);
++	lhi	(@x[12],1);
++	 x	(@x[0],"4*8(%r14)");
++	al	(@x[12],"$stdframe+4*12($sp)");	# increment counter
++	 x	(@x[1],"4*9(%r14)");
++	 st	(@x[0],"4*8(@t[0])");
++	 x	(@x[2],"4*10(%r14)");
++	 st	(@x[1],"4*9(@t[0])");
++	 x	(@x[3],"4*11(%r14)");
++	 st	(@x[2],"4*10(@t[0])");
++	 st	(@x[3],"4*11(@t[0])");
++
++&{$z?	\&clgr:\&clr}	("%r14",@t[1]);	# done yet?
++	la	("%r14","64(%r14)");
++	jl	(".Loop_outer");
++
++LABEL	(".Ldone");
++	xgr	("%r0","%r0");
++	xgr	("%r1","%r1");
++	xgr	("%r2","%r2");
++	xgr	("%r3","%r3");
++	stmg	("%r0","%r3","$stdframe+4*4($sp)");	# wipe key copy
++	stmg	("%r0","%r3","$stdframe+4*12($sp)");
++
++&{$z?	\&lmg:\&lm}	("%r6","%r15","$frame+6*$SIZE_T($sp)");
++	br	("%r14");
++
++ALIGN	(16);
++LABEL	(".Ltail");
++	la	(@t[1],"64($t[1])");
++	stm	(@x[0],@x[7],"$stdframe+4*0($sp)");
++&{$z?	\&slgr:\&slr}	(@t[1],"%r14");
++	lm	(@x[0],@x[3],"$stdframe+4*8+4*8($sp)");
++&{$z?	\&lghi:\&lhi}	(@x[6],0);
++	stm	(@x[12],@x[15],"$stdframe+4*12($sp)");
++	al	(@x[0],"$stdframe+4*8($sp)");
++	al	(@x[1],"$stdframe+4*9($sp)");
++	al	(@x[2],"$stdframe+4*10($sp)");
++	al	(@x[3],"$stdframe+4*11($sp)");
++	lrvr	(@x[0],@x[0]);
++	lrvr	(@x[1],@x[1]);
++	lrvr	(@x[2],@x[2]);
++	lrvr	(@x[3],@x[3]);
++	stm	(@x[0],@x[3],"$stdframe+4*8($sp)");
++
++LABEL	(".Loop_tail");
++	llgc	(@x[4],"0(@x[6],%r14)");
++	llgc	(@x[5],"$stdframe(@x[6],$sp)");
++	xr	(@x[5],@x[4]);
++	stc	(@x[5],"0(@x[6],@t[0])");
++	la	(@x[6],"1(@x[6])");
++	brct	(@t[1],".Loop_tail");
++
++	j	(".Ldone");
++SIZE	("ChaCha20_ctr32",".-ChaCha20_ctr32");
++}
++
++########################################################################
++# 4x"vertical" layout minimizes amount of instructions, but pipeline
++# runs underutilized [because of vector instructions' high latency].
++# On the other hand minimum amount of data it takes to fully utilize
++# the pipeline is higher, so that effectively, short inputs would be
++# processed slower. Hence this code path targeting <=256 bytes lengths.
++#
++{
++my ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
++    $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3)=map("%v$_",(0..15));
++my @K=map("%v$_",(16..19));
++my $CTR="%v26";
++my ($xt0,$xt1,$xt2,$xt3)=map("%v$_",(27..30));
++my $beperm="%v31";
++my ($x00,$x10,$x20,$x30)=(0,map("r$_",(8..10)));
++my $FRAME=$stdframe+4*16;
++
++ALIGN	(32);
++LABEL	("ChaCha20_ctr32_4x");
++LABEL	(".LChaCha20_ctr32_4x");
++&{$z?	\&stmg:\&stm}	("%r6","%r7","6*$SIZE_T($sp)");
++if (!$z) {
++	std	("%f4","16*$SIZE_T+2*8($sp)");
++	std	("%f6","16*$SIZE_T+3*8($sp)");
++}
++&{$z?	\&lghi:\&lhi}	("%r1",-$FRAME);
++	lgr	("%r0",$sp);
++	la	($sp,"0(%r1,$sp)");
++&{$z?	\&stg:\&st}	("%r0","0($sp)");	# back-chain
++if ($z) {
++	std	("%f8","$stdframe+8*0($sp)");
++	std	("%f9","$stdframe+8*1($sp)");
++	std	("%f10","$stdframe+8*2($sp)");
++	std	("%f11","$stdframe+8*3($sp)");
++	std	("%f12","$stdframe+8*4($sp)");
++	std	("%f13","$stdframe+8*5($sp)");
++	std	("%f14","$stdframe+8*6($sp)");
++	std	("%f15","$stdframe+8*7($sp)");
++}
++	larl	("%r7",".Lsigma");
++	lhi	("%r0",10);
++	lhi	("%r1",0);
++
++	vl	(@K[0],"0(%r7)");		# load sigma
++	vl	(@K[1],"0($key)");		# load key
++	vl	(@K[2],"16($key)");
++	vl	(@K[3],"0($counter)");		# load counter
++
++	vl	($beperm,"0x40(%r7)");
++	vl	($xt1,"0x50(%r7)");
++	vrepf	($CTR,@K[3],0);
++	vlvgf	(@K[3],"%r1",0);		# clear @K[3].word[0]
++	vaf	($CTR,$CTR,$xt1);
++
++#LABEL	(".Loop_outer_4x");
++	vlm	($xa0,$xa3,"0x60(%r7)");	# load [smashed] sigma
++
++	vrepf	($xb0,@K[1],0);			# smash the key
++	vrepf	($xb1,@K[1],1);
++	vrepf	($xb2,@K[1],2);
++	vrepf	($xb3,@K[1],3);
++
++	vrepf	($xc0,@K[2],0);
++	vrepf	($xc1,@K[2],1);
++	vrepf	($xc2,@K[2],2);
++	vrepf	($xc3,@K[2],3);
++
++	vlr	($xd0,$CTR);
++	vrepf	($xd1,@K[3],1);
++	vrepf	($xd2,@K[3],2);
++	vrepf	($xd3,@K[3],3);
++
++LABEL	(".Loop_4x");
++	VX_lane_ROUND(0, 4, 8,12);
++	VX_lane_ROUND(0, 5,10,15);
++	brct	("%r0",".Loop_4x");
++
++	vaf	($xd0,$xd0,$CTR);
++
++	vmrhf	($xt0,$xa0,$xa1);		# transpose data
++	vmrhf	($xt1,$xa2,$xa3);
++	vmrlf	($xt2,$xa0,$xa1);
++	vmrlf	($xt3,$xa2,$xa3);
++	vpdi	($xa0,$xt0,$xt1,0b0000);
++	vpdi	($xa1,$xt0,$xt1,0b0101);
++	vpdi	($xa2,$xt2,$xt3,0b0000);
++	vpdi	($xa3,$xt2,$xt3,0b0101);
++
++	vmrhf	($xt0,$xb0,$xb1);
++	vmrhf	($xt1,$xb2,$xb3);
++	vmrlf	($xt2,$xb0,$xb1);
++	vmrlf	($xt3,$xb2,$xb3);
++	vpdi	($xb0,$xt0,$xt1,0b0000);
++	vpdi	($xb1,$xt0,$xt1,0b0101);
++	vpdi	($xb2,$xt2,$xt3,0b0000);
++	vpdi	($xb3,$xt2,$xt3,0b0101);
++
++	vmrhf	($xt0,$xc0,$xc1);
++	vmrhf	($xt1,$xc2,$xc3);
++	vmrlf	($xt2,$xc0,$xc1);
++	vmrlf	($xt3,$xc2,$xc3);
++	vpdi	($xc0,$xt0,$xt1,0b0000);
++	vpdi	($xc1,$xt0,$xt1,0b0101);
++	vpdi	($xc2,$xt2,$xt3,0b0000);
++	vpdi	($xc3,$xt2,$xt3,0b0101);
++
++	vmrhf	($xt0,$xd0,$xd1);
++	vmrhf	($xt1,$xd2,$xd3);
++	vmrlf	($xt2,$xd0,$xd1);
++	vmrlf	($xt3,$xd2,$xd3);
++	vpdi	($xd0,$xt0,$xt1,0b0000);
++	vpdi	($xd1,$xt0,$xt1,0b0101);
++	vpdi	($xd2,$xt2,$xt3,0b0000);
++	vpdi	($xd3,$xt2,$xt3,0b0101);
++
++	#vrepif	($xt0,4);
++	#vaf	($CTR,$CTR,$xt0);		# next counter value
++
++	vaf	($xa0,$xa0,@K[0]);
++	vaf	($xb0,$xb0,@K[1]);
++	vaf	($xc0,$xc0,@K[2]);
++	vaf	($xd0,$xd0,@K[3]);
++
++	vperm	($xa0,$xa0,$xa0,$beperm);
++	vperm	($xb0,$xb0,$xb0,$beperm);
++	vperm	($xc0,$xc0,$xc0,$beperm);
++	vperm	($xd0,$xd0,$xd0,$beperm);
++
++	#&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	#jl	(".Ltail_4x");
++
++	vlm	($xt0,$xt3,"0($inp)");
++
++	vx	($xt0,$xt0,$xa0);
++	vx	($xt1,$xt1,$xb0);
++	vx	($xt2,$xt2,$xc0);
++	vx	($xt3,$xt3,$xd0);
++
++	vstm	($xt0,$xt3,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	#je	(".Ldone_4x");
++
++	vaf	($xa0,$xa1,@K[0]);
++	vaf	($xb0,$xb1,@K[1]);
++	vaf	($xc0,$xc1,@K[2]);
++	vaf	($xd0,$xd1,@K[3]);
++
++	vperm	($xa0,$xa0,$xa0,$beperm);
++	vperm	($xb0,$xb0,$xb0,$beperm);
++	vperm	($xc0,$xc0,$xc0,$beperm);
++	vperm	($xd0,$xd0,$xd0,$beperm);
++
++&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	jl	(".Ltail_4x");
++
++	vlm	($xt0,$xt3,"0($inp)");
++
++	vx	($xt0,$xt0,$xa0);
++	vx	($xt1,$xt1,$xb0);
++	vx	($xt2,$xt2,$xc0);
++	vx	($xt3,$xt3,$xd0);
++
++	vstm	($xt0,$xt3,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_4x");
++
++	vaf	($xa0,$xa2,@K[0]);
++	vaf	($xb0,$xb2,@K[1]);
++	vaf	($xc0,$xc2,@K[2]);
++	vaf	($xd0,$xd2,@K[3]);
++
++	vperm	($xa0,$xa0,$xa0,$beperm);
++	vperm	($xb0,$xb0,$xb0,$beperm);
++	vperm	($xc0,$xc0,$xc0,$beperm);
++	vperm	($xd0,$xd0,$xd0,$beperm);
++
++&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	jl	(".Ltail_4x");
++
++	vlm	($xt0,$xt3,"0($inp)");
++
++	vx	($xt0,$xt0,$xa0);
++	vx	($xt1,$xt1,$xb0);
++	vx	($xt2,$xt2,$xc0);
++	vx	($xt3,$xt3,$xd0);
++
++	vstm	($xt0,$xt3,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_4x");
++
++	vaf	($xa0,$xa3,@K[0]);
++	vaf	($xb0,$xb3,@K[1]);
++	vaf	($xc0,$xc3,@K[2]);
++	vaf	($xd0,$xd3,@K[3]);
++
++	vperm	($xa0,$xa0,$xa0,$beperm);
++	vperm	($xb0,$xb0,$xb0,$beperm);
++	vperm	($xc0,$xc0,$xc0,$beperm);
++	vperm	($xd0,$xd0,$xd0,$beperm);
++
++&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	jl	(".Ltail_4x");
++
++	vlm	($xt0,$xt3,"0($inp)");
++
++	vx	($xt0,$xt0,$xa0);
++	vx	($xt1,$xt1,$xb0);
++	vx	($xt2,$xt2,$xc0);
++	vx	($xt3,$xt3,$xd0);
++
++	vstm	($xt0,$xt3,"0($out)");
++
++	#la	$inp,0x40($inp));
++	#la	$out,0x40($out));
++	#lhi	%r0,10);
++	#&{$z?	\&aghi:\&ahi}	$len,-0x40);
++	#jne	.Loop_outer_4x);
++
++LABEL	(".Ldone_4x");
++if (!$z) {
++	ld	("%f4","$FRAME+16*$SIZE_T+2*8($sp)");
++	ld	("%f6","$FRAME+16*$SIZE_T+3*8($sp)");
++} else {
++	ld	("%f8","$stdframe+8*0($sp)");
++	ld	("%f9","$stdframe+8*1($sp)");
++	ld	("%f10","$stdframe+8*2($sp)");
++	ld	("%f11","$stdframe+8*3($sp)");
++	ld	("%f12","$stdframe+8*4($sp)");
++	ld	("%f13","$stdframe+8*5($sp)");
++	ld	("%f14","$stdframe+8*6($sp)");
++	ld	("%f15","$stdframe+8*7($sp)");
++}
++&{$z?	\&lmg:\&lm}	("%r6","%r7","$FRAME+6*$SIZE_T($sp)");
++	la	($sp,"$FRAME($sp)");
++	br	("%r14");
++
++ALIGN	(16);
++LABEL	(".Ltail_4x");
++if (!$z) {
++	vlr	($xt0,$xb0);
++	ld	("%f4","$FRAME+16*$SIZE_T+2*8($sp)");
++	ld	("%f6","$FRAME+16*$SIZE_T+3*8($sp)");
++
++	vst	($xa0,"$stdframe+0x00($sp)");
++	vst	($xt0,"$stdframe+0x10($sp)");
++	vst	($xc0,"$stdframe+0x20($sp)");
++	vst	($xd0,"$stdframe+0x30($sp)");
++} else {
++	vlr	($xt0,$xc0);
++	ld	("%f8","$stdframe+8*0($sp)");
++	ld	("%f9","$stdframe+8*1($sp)");
++	ld	("%f10","$stdframe+8*2($sp)");
++	ld	("%f11","$stdframe+8*3($sp)");
++	vlr	($xt1,$xd0);
++	ld	("%f12","$stdframe+8*4($sp)");
++	ld	("%f13","$stdframe+8*5($sp)");
++	ld	("%f14","$stdframe+8*6($sp)");
++	ld	("%f15","$stdframe+8*7($sp)");
++
++	vst	($xa0,"$stdframe+0x00($sp)");
++	vst	($xb0,"$stdframe+0x10($sp)");
++	vst	($xt0,"$stdframe+0x20($sp)");
++	vst	($xt1,"$stdframe+0x30($sp)");
++}
++	lghi	("%r1",0);
++
++LABEL	(".Loop_tail_4x");
++	llgc	("%r5","0(%r1,$inp)");
++	llgc	("%r6","$stdframe(%r1,$sp)");
++	xr	("%r6","%r5");
++	stc	("%r6","0(%r1,$out)");
++	la	("%r1","1(%r1)");
++	brct	($len,".Loop_tail_4x");
++
++&{$z?	\&lmg:\&lm}	("%r6","%r7","$FRAME+6*$SIZE_T($sp)");
++	la	($sp,"$FRAME($sp)");
++	br	("%r14");
++SIZE	("ChaCha20_ctr32_4x",".-ChaCha20_ctr32_4x");
++}
++
++########################################################################
++# 6x"horizontal" layout is optimal fit for the platform in its current
++# shape, more specifically for given vector instructions' latency. Well,
++# computational part of 8x"vertical" would be faster, but it consumes
++# all registers and dealing with that will diminish the return...
++#
++{
++my ($a0,$b0,$c0,$d0, $a1,$b1,$c1,$d1,
++    $a2,$b2,$c2,$d2, $a3,$b3,$c3,$d3,
++    $a4,$b4,$c4,$d4, $a5,$b5,$c5,$d5)=map("%v$_",(0..23));
++my @K=map("%v$_",(27,24..26));
++my ($t0,$t1,$t2,$t3)=map("%v$_",27..30);
++my $beperm="%v31";
++my $FRAME=$stdframe + 4*16;
++
++GLOBL	("ChaCha20_ctr32_vx");
++ALIGN	(32);
++LABEL	("ChaCha20_ctr32_vx");
++LABEL	(".LChaCha20_ctr32_vx");
++&{$z?	\&clgfi:\&clfi}	($len,256);
++	jle	(".LChaCha20_ctr32_4x");
++&{$z?	\&stmg:\&stm}	("%r6","%r7","6*$SIZE_T($sp)");
++if (!$z) {
++	std	("%f4","16*$SIZE_T+2*8($sp)");
++	std	("%f6","16*$SIZE_T+3*8($sp)");
++}
++&{$z?	\&lghi:\&lhi}	("%r1",-$FRAME);
++	lgr	("%r0",$sp);
++	la	($sp,"0(%r1,$sp)");
++&{$z?	\&stg:\&st}	("%r0","0($sp)");	# back-chain
++if ($z) {
++	std	("%f8","$FRAME-8*8($sp)");
++	std	("%f9","$FRAME-8*7($sp)");
++	std	("%f10","$FRAME-8*6($sp)");
++	std	("%f11","$FRAME-8*5($sp)");
++	std	("%f12","$FRAME-8*4($sp)");
++	std	("%f13","$FRAME-8*3($sp)");
++	std	("%f14","$FRAME-8*2($sp)");
++	std	("%f15","$FRAME-8*1($sp)");
++}
++	larl	("%r7",".Lsigma");
++	lhi	("%r0",10);
++
++	vlm	(@K[1],@K[2],"0($key)");	# load key
++	vl	(@K[3],"0($counter)");		# load counter
++
++	vlm	(@K[0],"$beperm","0(%r7)");	# load sigma, increments, ...
++
++LABEL	(".Loop_outer_vx");
++	vlr	($a0,@K[0]);
++	vlr	($b0,@K[1]);
++	vlr	($a1,@K[0]);
++	vlr	($b1,@K[1]);
++	vlr	($a2,@K[0]);
++	vlr	($b2,@K[1]);
++	vlr	($a3,@K[0]);
++	vlr	($b3,@K[1]);
++	vlr	($a4,@K[0]);
++	vlr	($b4,@K[1]);
++	vlr	($a5,@K[0]);
++	vlr	($b5,@K[1]);
++
++	vlr	($d0,@K[3]);
++	vaf	($d1,@K[3],$t1);		# K[3]+1
++	vaf	($d2,@K[3],$t2);		# K[3]+2
++	vaf	($d3,@K[3],$t3);		# K[3]+3
++	vaf	($d4,$d2,$t2);			# K[3]+4
++	vaf	($d5,$d2,$t3);			# K[3]+5
++
++	vlr	($c0,@K[2]);
++	vlr	($c1,@K[2]);
++	vlr	($c2,@K[2]);
++	vlr	($c3,@K[2]);
++	vlr	($c4,@K[2]);
++	vlr	($c5,@K[2]);
++
++	vlr	($t1,$d1);
++	vlr	($t2,$d2);
++	vlr	($t3,$d3);
++
++ALIGN	(4);
++LABEL	(".Loop_vx");
++
++	VX_ROUND($a0,$a1,$a2,$a3,$a4,$a5,
++		 $b0,$b1,$b2,$b3,$b4,$b5,
++		 $c0,$c1,$c2,$c3,$c4,$c5,
++		 $d0,$d1,$d2,$d3,$d4,$d5,
++		 0);
++
++	VX_ROUND($a0,$a1,$a2,$a3,$a4,$a5,
++		 $b0,$b1,$b2,$b3,$b4,$b5,
++		 $c0,$c1,$c2,$c3,$c4,$c5,
++		 $d0,$d1,$d2,$d3,$d4,$d5,
++		 1);
++
++	brct	("%r0",".Loop_vx");
++
++	vaf	($a0,$a0,@K[0]);
++	vaf	($b0,$b0,@K[1]);
++	vaf	($c0,$c0,@K[2]);
++	vaf	($d0,$d0,@K[3]);
++	vaf	($a1,$a1,@K[0]);
++	vaf	($d1,$d1,$t1);			# +K[3]+1
++
++	vperm	($a0,$a0,$a0,$beperm);
++	vperm	($b0,$b0,$b0,$beperm);
++	vperm	($c0,$c0,$c0,$beperm);
++	vperm	($d0,$d0,$d0,$beperm);
++
++&{$z?	\&clgfi:\&clfi}	($len,0x40);
++	jl	(".Ltail_vx");
++
++	vaf	($d2,$d2,$t2);			# +K[3]+2
++	vaf	($d3,$d3,$t3);			# +K[3]+3
++	vlm	($t0,$t3,"0($inp)");
++
++	vx	($a0,$a0,$t0);
++	vx	($b0,$b0,$t1);
++	vx	($c0,$c0,$t2);
++	vx	($d0,$d0,$t3);
++
++	vlm	(@K[0],$t3,"0(%r7)");		# re-load sigma and increments
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_vx");
++
++	vaf	($b1,$b1,@K[1]);
++	vaf	($c1,$c1,@K[2]);
++
++	vperm	($a0,$a1,$a1,$beperm);
++	vperm	($b0,$b1,$b1,$beperm);
++	vperm	($c0,$c1,$c1,$beperm);
++	vperm	($d0,$d1,$d1,$beperm);
++
++&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	jl	(".Ltail_vx");
++
++	vlm	($a1,$d1,"0($inp)");
++
++	vx	($a0,$a0,$a1);
++	vx	($b0,$b0,$b1);
++	vx	($c0,$c0,$c1);
++	vx	($d0,$d0,$d1);
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_vx");
++
++	vaf	($a2,$a2,@K[0]);
++	vaf	($b2,$b2,@K[1]);
++	vaf	($c2,$c2,@K[2]);
++
++	vperm	($a0,$a2,$a2,$beperm);
++	vperm	($b0,$b2,$b2,$beperm);
++	vperm	($c0,$c2,$c2,$beperm);
++	vperm	($d0,$d2,$d2,$beperm);
++
++&{$z?	\&clgfi:\&clfi}	($len,0x40);
++	jl	(".Ltail_vx");
++
++	vlm	($a1,$d1,"0($inp)");
++
++	vx	($a0,$a0,$a1);
++	vx	($b0,$b0,$b1);
++	vx	($c0,$c0,$c1);
++	vx	($d0,$d0,$d1);
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_vx");
++
++	vaf	($a3,$a3,@K[0]);
++	vaf	($b3,$b3,@K[1]);
++	vaf	($c3,$c3,@K[2]);
++	vaf	($d2,@K[3],$t3);		# K[3]+3
++
++	vperm	($a0,$a3,$a3,$beperm);
++	vperm	($b0,$b3,$b3,$beperm);
++	vperm	($c0,$c3,$c3,$beperm);
++	vperm	($d0,$d3,$d3,$beperm);
++
++&{$z?	\&clgfi:\&clfi}	($len,0x40);
++	jl	(".Ltail_vx");
++
++	vaf	($d3,$d2,$t1);			# K[3]+4
++	vlm	($a1,$d1,"0($inp)");
++
++	vx	($a0,$a0,$a1);
++	vx	($b0,$b0,$b1);
++	vx	($c0,$c0,$c1);
++	vx	($d0,$d0,$d1);
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_vx");
++
++	vaf	($a4,$a4,@K[0]);
++	vaf	($b4,$b4,@K[1]);
++	vaf	($c4,$c4,@K[2]);
++	vaf	($d4,$d4,$d3);			# +K[3]+4
++	vaf	($d3,$d3,$t1);			# K[3]+5
++	vaf	(@K[3],$d2,$t3);		# K[3]+=6
++
++	vperm	($a0,$a4,$a4,$beperm);
++	vperm	($b0,$b4,$b4,$beperm);
++	vperm	($c0,$c4,$c4,$beperm);
++	vperm	($d0,$d4,$d4,$beperm);
++
++&{$z?	\&clgfi:\&clfi}	($len,0x40);
++	jl	(".Ltail_vx");
++
++	vlm	($a1,$d1,"0($inp)");
++
++	vx	($a0,$a0,$a1);
++	vx	($b0,$b0,$b1);
++	vx	($c0,$c0,$c1);
++	vx	($d0,$d0,$d1);
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	je	(".Ldone_vx");
++
++	vaf	($a5,$a5,@K[0]);
++	vaf	($b5,$b5,@K[1]);
++	vaf	($c5,$c5,@K[2]);
++	vaf	($d5,$d5,$d3);			# +K[3]+5
++
++	vperm	($a0,$a5,$a5,$beperm);
++	vperm	($b0,$b5,$b5,$beperm);
++	vperm	($c0,$c5,$c5,$beperm);
++	vperm	($d0,$d5,$d5,$beperm);
++
++&{$z?	\&clgfi:\&clfi} ($len,0x40);
++	jl	(".Ltail_vx");
++
++	vlm	($a1,$d1,"0($inp)");
++
++	vx	($a0,$a0,$a1);
++	vx	($b0,$b0,$b1);
++	vx	($c0,$c0,$c1);
++	vx	($d0,$d0,$d1);
++
++	vstm	($a0,$d0,"0($out)");
++
++	la	($inp,"0x40($inp)");
++	la	($out,"0x40($out)");
++	lhi	("%r0",10);
++&{$z?	\&aghi:\&ahi}	($len,-0x40);
++	jne	(".Loop_outer_vx");
++
++LABEL	(".Ldone_vx");
++if (!$z) {
++	ld	("%f4","$FRAME+16*$SIZE_T+2*8($sp)");
++	ld	("%f6","$FRAME+16*$SIZE_T+3*8($sp)");
++} else {
++	ld	("%f8","$FRAME-8*8($sp)");
++	ld	("%f9","$FRAME-8*7($sp)");
++	ld	("%f10","$FRAME-8*6($sp)");
++	ld	("%f11","$FRAME-8*5($sp)");
++	ld	("%f12","$FRAME-8*4($sp)");
++	ld	("%f13","$FRAME-8*3($sp)");
++	ld	("%f14","$FRAME-8*2($sp)");
++	ld	("%f15","$FRAME-8*1($sp)");
++}
++&{$z?	\&lmg:\&lm}	("%r6","%r7","$FRAME+6*$SIZE_T($sp)");
++	la	($sp,"$FRAME($sp)");
++	br	("%r14");
++
++ALIGN	(16);
++LABEL	(".Ltail_vx");
++if (!$z) {
++	ld	("%f4","$FRAME+16*$SIZE_T+2*8($sp)");
++	ld	("%f6","$FRAME+16*$SIZE_T+3*8($sp)");
++} else {
++	ld	("%f8","$FRAME-8*8($sp)");
++	ld	("%f9","$FRAME-8*7($sp)");
++	ld	("%f10","$FRAME-8*6($sp)");
++	ld	("%f11","$FRAME-8*5($sp)");
++	ld	("%f12","$FRAME-8*4($sp)");
++	ld	("%f13","$FRAME-8*3($sp)");
++	ld	("%f14","$FRAME-8*2($sp)");
++	ld	("%f15","$FRAME-8*1($sp)");
++}
++	vstm	($a0,$d0,"$stdframe($sp)");
++	lghi	("%r1",0);
++
++LABEL	(".Loop_tail_vx");
++	llgc	("%r5","0(%r1,$inp)");
++	llgc	("%r6","$stdframe(%r1,$sp)");
++	xr	("%r6","%r5");
++	stc	("%r6","0(%r1,$out)");
++	la	("%r1","1(%r1)");
++	brct	($len,".Loop_tail_vx");
++
++&{$z?	\&lmg:\&lm}	("%r6","%r7","$FRAME+6*$SIZE_T($sp)");
++	la	($sp,"$FRAME($sp)");
++	br	("%r14");
++SIZE	("ChaCha20_ctr32_vx",".-ChaCha20_ctr32_vx");
++}
++################
++
++ALIGN	(32);
++LABEL	(".Lsigma");
++LONG	(0x61707865,0x3320646e,0x79622d32,0x6b206574);	# endian-neutral sigma
++LONG	(1,0,0,0);
++LONG	(2,0,0,0);
++LONG	(3,0,0,0);
++LONG	(0x03020100,0x07060504,0x0b0a0908,0x0f0e0d0c);	# byte swap
++
++LONG	(0,1,2,3);
++LONG	(0x61707865,0x61707865,0x61707865,0x61707865);	# smashed sigma
++LONG	(0x3320646e,0x3320646e,0x3320646e,0x3320646e);
++LONG	(0x79622d32,0x79622d32,0x79622d32,0x79622d32);
++LONG	(0x6b206574,0x6b206574,0x6b206574,0x6b206574);
++
++ASCIZ	("\"ChaCha20 for s390x, CRYPTOGAMS by <appro\@openssl.org>\"");
++ALIGN	(4);
++
++PERLASM_END();
+diff -up openssl-1.1.1b/crypto/perlasm/s390x.pm.s390x-update openssl-1.1.1b/crypto/perlasm/s390x.pm
+--- openssl-1.1.1b/crypto/perlasm/s390x.pm.s390x-update	2019-05-06 10:54:00.037367571 +0200
++++ openssl-1.1.1b/crypto/perlasm/s390x.pm	2019-05-06 10:59:30.859784823 +0200
+@@ -0,0 +1,3142 @@
++#!/usr/bin/env perl
++# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
++#
++# Licensed under the OpenSSL license (the "License").  You may not use
++# this file except in compliance with the License.  You can obtain a copy
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# Copyright IBM Corp. 2018-2019
++# Author: Patrick Steuer <patrick.steuer@de.ibm.com>
++
++package perlasm::s390x;
++
++use strict;
++use warnings;
++use bigint;
++use Carp qw(confess);
++use Exporter qw(import);
++
++our @EXPORT=qw(PERLASM_BEGIN PERLASM_END);
++our @EXPORT_OK=qw(AUTOLOAD LABEL INCLUDE stfle);
++our %EXPORT_TAGS=(
++	# long-displacement facility
++	LD => [qw(clgfi)],
++	# general-instruction-extension facility
++	GE => [qw(risbg)],
++	# extended-immediate facility
++	EI => [qw(lt)],
++	# miscellaneous-instruction-extensions facility 1
++	MI1 => [qw(risbgn)],
++	# message-security assist
++	MSA => [qw(kmac km kmc kimd klmd)],
++	# message-security-assist extension 4
++	MSA4 => [qw(kmf kmo pcc kmctr)],
++	# message-security-assist extension 5
++	MSA5 => [qw(ppno prno)],
++	# message-security-assist extension 8
++	MSA8 => [qw(kma)],
++	# vector facility
++	VX => [qw(vgef vgeg vgbm vzero vone vgm vgmb vgmh vgmf vgmg
++	    vl vlr vlrep vlrepb vlreph vlrepf vlrepg vleb vleh vlef vleg vleib
++	    vleih vleif vleig vlgv vlgvb vlgvh vlgvf vlgvg vllez vllezb vllezh
++	    vllezf vllezg vlm vlbb vlvg vlvgb vlvgh vlvgf vlvgg vlvgp
++	    vll vmrh vmrhb vmrhh vmrhf vmrhg vmrl vmrlb vmrlh vmrlf vmrlg vpk
++	    vpkh vpkf vpkg vpks vpksh vpksf vpksg vpkshs vpksfs vpksgs vpkls
++	    vpklsh vpklsf vpklsg vpklshs vpklsfs vpklsgs vperm vpdi vrep vrepb
++	    vreph vrepf vrepg vrepi vrepib vrepih vrepif vrepig vscef vsceg
++	    vsel vseg vsegb vsegh vsegf vst vsteb vsteh vstef vsteg vstm vstl
++	    vuph vuphb vuphh vuphf vuplh vuplhb vuplhh vuplhf vupl vuplb vuplhw
++	    vuplf vupll vupllb vupllh vupllf va vab vah vaf vag vaq vacc vaccb
++	    vacch vaccf vaccg vaccq vac vacq vaccc vacccq vn vnc vavg vavgb
++	    vavgh vavgf vavgg vavgl vavglb vavglh vavglf vavglg vcksm vec_ vecb
++	    vech vecf vecg vecl veclb veclh veclf veclg vceq vceqb vceqh vceqf
++	    vceqg vceqbs vceqhs vceqfs vceqgs vch vchb vchh vchf vchg vchbs
++	    vchhs vchfs vchgs vchl vchlb vchlh vchlf vchlg vchlbs vchlhs vchlfs
++	    vchlgs vclz vclzb vclzh vclzf vclzg vctz vctzb vctzh vctzf vctzg
++	    vx vgfm vgfmb vgfmh vgfmf vgfmg vgfma vgfmab vgfmah vgfmaf vgfmag
++	    vlc vlcb vlch vlcf vlcg vlp vlpb vlph vlpf vlpg vmx vmxb vmxh vmxf
++	    vmxg vmxl vmxlb vmxlh vmxlf vmxlg vmn vmnb vmnh vmnf vmng vmnl
++	    vmnlb vmnlh vmnlf vmnlg vmal vmalb vmalhw vmalf vmah vmahb vmahh
++	    vmahf vmalh vmalhb vmalhh vmalhf vmae vmaeb vmaeh vmaef vmale
++	    vmaleb vmaleh vmalef vmao vmaob vmaoh vmaof vmalo vmalob vmaloh
++	    vmalof vmh vmhb vmhh vmhf vmlh vmlhb vmlhh vmlhf vml vmlb vmlhw
++	    vmlf vme vmeb vmeh vmef vmle vmleb vmleh vmlef vmo vmob vmoh vmof
++	    vmlo vmlob vmloh vmlof vno vnot vo vpopct verllv verllvb verllvh
++	    verllvf verllvg verll verllb verllh verllf verllg verim verimb
++	    verimh verimf verimg veslv veslvb veslvh veslvf veslvg vesl veslb
++	    veslh veslf veslg vesrav vesravb vesravh vesravf vesravg vesra
++	    vesrab vesrah vesraf vesrag vesrlv vesrlvb vesrlvh vesrlvf vesrlvg
++	    vesrl vesrlb vesrlh vesrlf vesrlg vsl vslb vsldb vsra vsrab vsrl
++	    vsrlb vs vsb vsh vsf vsg vsq vscbi vscbib vscbih vscbif vscbig
++	    vscbiq vsbi vsbiq vsbcbi vsbcbiq vsumg vsumgh vsumgf vsumq vsumqf
++	    vsumqg vsum vsumb vsumh vtm vfae vfaeb vfaeh vfaef vfaebs vfaehs
++	    vfaefs vfaezb vfaezh vfaezf vfaezbs vfaezhs vfaezfs vfee vfeeb
++	    vfeeh vfeef vfeebs vfeehs vfeefs vfeezb vfeezh vfeezf vfeezbs
++	    vfeezhs vfeezfs vfene vfeneb vfeneh vfenef vfenebs vfenehs vfenefs
++	    vfenezb vfenezh vfenezf vfenezbs vfenezhs vfenezfs vistr vistrb
++	    vistrh vistrf vistrbs vistrhs vistrfs vstrc vstrcb vstrch vstrcf
++	    vstrcbs vstrchs vstrcfs vstrczb vstrczh vstrczf vstrczbs vstrczhs
++	    vstrczfs vfa vfadb wfadb wfc wfcdb wfk wfkdb vfce vfcedb wfcedb
++	    vfcedbs wfcedbs vfch vfchdb wfchdb vfchdbs wfchdbs vfche vfchedb
++	    wfchedb vfchedbs wfchedbs vcdg vcdgb wcdgb vcdlg vcdlgb wcdlgb vcgd
++	    vcgdb wcgdb vclgd vclgdb wclgdb vfd vfddb wfddb vfi vfidb wfidb
++	    vlde vldeb wldeb vled vledb wledb vfm vfmdb wfmdb vfma vfmadb
++	    wfmadb vfms vfmsdb wfmsdb vfpso vfpsodb wfpsodb vflcdb wflcdb
++	    vflndb wflndb vflpdb wflpdb vfsq vfsqdb wfsqdb vfs vfsdb wfsdb
++	    vftci vftcidb wftcidb)],
++	# vector-enhancements facility 1
++	VXE => [qw(vbperm vllezlf vmsl vmslg vnx vnn voc vpopctb vpopcth
++	    vpopctf vpopctg vfasb wfasb wfaxb wfcsb wfcxb wfksb wfkxb vfcesb
++	    vfcesbs wfcesb wfcesbs wfcexb wfcexbs vfchsb vfchsbs wfchsb wfchsbs
++	    wfchxb wfchxbs vfchesb vfchesbs wfchesb wfchesbs wfchexb wfchexbs
++	    vfdsb wfdsb wfdxb vfisb wfisb wfixb vfll vflls wflls wflld vflr
++	    vflrd wflrd wflrx vfmax vfmaxsb vfmaxdb wfmaxsb wfmaxdb wfmaxxb
++	    vfmin vfminsb vfmindb wfminsb wfmindb wfminxb vfmsb wfmsb wfmxb
++	    vfnma vfnms vfmasb wfmasb wfmaxb vfmssb wfmssb wfmsxb vfnmasb
++	    vfnmadb wfnmasb wfnmadb wfnmaxb vfnmssb vfnmsdb wfnmssb wfnmsdb
++	    wfnmsxb vfpsosb wfpsosb vflcsb wflcsb vflnsb wflnsb vflpsb wflpsb
++	    vfpsoxb wfpsoxb vflcxb wflcxb vflnxb wflnxb vflpxb wflpxb vfsqsb
++	    wfsqsb wfsqxb vfssb wfssb wfsxb vftcisb wftcisb wftcixb)],
++	# vector-packed-decimal facility
++	VXD => [qw(vlrlr vlrl vstrlr vstrl vap vcp vcvb vcvbg vcvd vcvdg vdp
++	    vlip vmp vmsp vpkz vpsop vrp vsdp vsrp vsp vtp vupkz)],
++);
++Exporter::export_ok_tags(qw(LD GE EI MI1 MSA MSA4 MSA5 MSA8 VX VXE VXD));
++
++our $AUTOLOAD;
++
++my $GR='(?:%r)?([0-9]|1[0-5])';
++my $VR='(?:%v)?([0-9]|1[0-9]|2[0-9]|3[0-1])';
++
++my ($file,$out);
++
++sub PERLASM_BEGIN
++{
++	($file,$out)=(shift,"");
++}
++sub PERLASM_END
++{
++	if (defined($file)) {
++		open(my $fd,'>',$file)||die("can't open $file: $!");
++		print({$fd}$out);
++		close($fd);
++	} else {
++		print($out);
++	}
++}
++
++sub AUTOLOAD {
++	confess(err("PARSE")) if (grep(!defined($_),@_));
++	my $token;
++	for ($AUTOLOAD) {
++		$token=".$1" if (/^.*::([A-Z_]+)$/);	# uppercase: directive
++		$token="\t$1" if (/^.*::([a-z]+)$/);	# lowercase: mnemonic
++		confess(err("PARSE")) if (!defined($token));
++	}
++	$token.="\t" if ($#_>=0);
++	$out.=$token.join(',',@_)."\n";
++}
++
++sub LABEL {						# label directive
++	confess(err("ARGNUM")) if ($#_!=0);
++	my ($label)=@_;
++	$out.="$label:\n";
++}
++
++sub INCLUDE {
++	confess(err("ARGNUM")) if ($#_!=0);
++	my ($file)=@_;
++	$out.="#include \"$file\"\n";
++}
++
++#
++# Mnemonics
++#
++
++sub stfle {
++	confess(err("ARGNUM")) if ($#_!=0);
++	S(0xb2b0,@_);
++}
++
++# MISC
++
++sub clgfi {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RILa(0xc2e,@_);
++}
++
++sub lt {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RXYa(0xe312,@_);
++}
++
++sub risbg {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	RIEf(0xec55,@_);
++}
++
++sub risbgn {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	RIEf(0xec59,@_);
++}
++
++# MSA
++
++sub kmac {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb91e,@_);
++}
++
++sub km {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb92e,@_);
++}
++
++sub kmc {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb92f,@_);
++}
++
++sub kimd {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb93e,@_);
++}
++
++sub klmd {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb93f,@_);
++}
++
++# MSA4
++
++sub kmf {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb92a,@_);
++}
++
++sub kmo {
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb92b,@_);
++}
++
++sub pcc {
++	confess(err("ARGNUM")) if ($#_!=-1);
++	RRE(0xb92c,@_);
++}
++
++sub kmctr {
++	confess(err("ARGNUM")) if ($#_!=2);
++	RRFb(0xb92d,@_);
++}
++
++# MSA5
++
++sub prno {
++	ppno(@_);
++}
++
++sub ppno {						# deprecated, use prno
++	confess(err("ARGNUM")) if ($#_!=1);
++	RRE(0xb93c,@_);
++}
++
++# MSA8
++
++sub kma {
++	confess(err("ARGNUM")) if ($#_!=2);
++	RRFb(0xb929,@_);
++}
++
++# VX - Support Instructions
++
++sub vgef {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRV(0xe713,@_);
++}
++sub vgeg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRV(0xe712,@_);
++}
++
++sub vgbm {
++	confess(err("ARGNUM")) if ($#_!=1);
++	VRIa(0xe744,@_);
++}
++sub vzero {
++	vgbm(@_,0);
++}
++sub vone {
++	vgbm(@_,0xffff);
++}
++
++sub vgm {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRIb(0xe746,@_);
++}
++sub vgmb {
++	vgm(@_,0);
++}
++sub vgmh {
++	vgm(@_,1);
++}
++sub vgmf {
++	vgm(@_,2);
++}
++sub vgmg {
++	vgm(@_,3);
++}
++
++sub vl {
++	confess(err("ARGNUM")) if ($#_<1||$#_>2);
++	VRX(0xe706,@_);
++}
++
++sub vlr {
++	confess(err("ARGNUM")) if ($#_!=1);
++	VRRa(0xe756,@_);
++}
++
++sub vlrep {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe705,@_);
++}
++sub vlrepb {
++	vlrep(@_,0);
++}
++sub vlreph {
++	vlrep(@_,1);
++}
++sub vlrepf {
++	vlrep(@_,2);
++}
++sub vlrepg {
++	vlrep(@_,3);
++}
++
++sub vleb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe700,@_);
++}
++sub vleh {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe701,@_);
++}
++sub vlef {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe703,@_);
++}
++sub vleg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe702,@_);
++}
++
++sub vleib {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIa(0xe740,@_);
++}
++sub vleih {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIa(0xe741,@_);
++}
++sub vleif {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIa(0xe743,@_);
++}
++sub vleig {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIa(0xe742,@_);
++}
++
++sub vlgv {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSc(0xe721,@_);
++}
++sub vlgvb {
++	vlgv(@_,0);
++}
++sub vlgvh {
++	vlgv(@_,1);
++}
++sub vlgvf {
++	vlgv(@_,2);
++}
++sub vlgvg {
++	vlgv(@_,3);
++}
++
++sub vllez {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe704,@_);
++}
++sub vllezb {
++	vllez(@_,0);
++}
++sub vllezh {
++	vllez(@_,1);
++}
++sub vllezf {
++	vllez(@_,2);
++}
++sub vllezg {
++	vllez(@_,3);
++}
++
++sub vlm {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	VRSa(0xe736,@_);
++}
++
++sub vlbb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe707,@_);
++}
++
++sub vlvg {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSb(0xe722,@_);
++}
++sub vlvgb {
++	vlvg(@_,0);
++}
++sub vlvgh {
++	vlvg(@_,1);
++}
++sub vlvgf {
++	vlvg(@_,2);
++}
++sub vlvgg {
++	vlvg(@_,3);
++}
++
++sub vlvgp {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRf(0xe762,@_);
++}
++
++sub vll {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRSb(0xe737,@_);
++}
++
++sub vmrh {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe761,@_);
++}
++sub vmrhb {
++	vmrh(@_,0);
++}
++sub vmrhh {
++	vmrh(@_,1);
++}
++sub vmrhf {
++	vmrh(@_,2);
++}
++sub vmrhg {
++	vmrh(@_,3);
++}
++
++sub vmrl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe760,@_);
++}
++sub vmrlb {
++	vmrl(@_,0);
++}
++sub vmrlh {
++	vmrl(@_,1);
++}
++sub vmrlf {
++	vmrl(@_,2);
++}
++sub vmrlg {
++	vmrl(@_,3);
++}
++
++sub vpk {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe794,@_);
++}
++sub vpkh {
++	vpk(@_,1);
++}
++sub vpkf {
++	vpk(@_,2);
++}
++sub vpkg {
++	vpk(@_,3);
++}
++
++sub vpks {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRb(0xe797,@_);
++}
++sub vpksh {
++	vpks(@_,1,0);
++}
++sub vpksf {
++	vpks(@_,2,0);
++}
++sub vpksg {
++	vpks(@_,3,0);
++}
++sub vpkshs {
++	vpks(@_,1,1);
++}
++sub vpksfs {
++	vpks(@_,2,1);
++}
++sub vpksgs {
++	vpks(@_,3,1);
++}
++
++sub vpkls {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRb(0xe795,@_);
++}
++sub vpklsh {
++	vpkls(@_,1,0);
++}
++sub vpklsf {
++	vpkls(@_,2,0);
++}
++sub vpklsg {
++	vpkls(@_,3,0);
++}
++sub vpklshs {
++	vpkls(@_,1,1);
++}
++sub vpklsfs {
++	vpkls(@_,2,1);
++}
++sub vpklsgs {
++	vpkls(@_,3,1);
++}
++
++sub vperm {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRe(0xe78c,@_);
++}
++
++sub vpdi {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe784,@_);
++}
++
++sub vrep {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRIc(0xe74d,@_);
++}
++sub vrepb {
++	vrep(@_,0);
++}
++sub vreph {
++	vrep(@_,1);
++}
++sub vrepf {
++	vrep(@_,2);
++}
++sub vrepg {
++	vrep(@_,3);
++}
++
++sub vrepi {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIa(0xe745,@_);
++}
++sub vrepib {
++	vrepi(@_,0);
++}
++sub vrepih {
++	vrepi(@_,1);
++}
++sub vrepif {
++	vrepi(@_,2);
++}
++sub vrepig {
++	vrepi(@_,3);
++}
++
++sub vscef {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRV(0xe71b,@_);
++}
++sub vsceg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRV(0xe71a,@_);
++}
++
++sub vsel {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRe(0xe78d,@_);
++}
++
++sub vseg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe75f,@_);
++}
++sub vsegb {
++	vseg(@_,0);
++}
++sub vsegh {
++	vseg(@_,1);
++}
++sub vsegf {
++	vseg(@_,2);
++}
++
++sub vst {
++	confess(err("ARGNUM")) if ($#_<1||$#_>2);
++	VRX(0xe70e,@_);
++}
++
++sub vsteb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe708,@_);
++}
++sub vsteh {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe709,@_);
++}
++sub vstef {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe70b,@_);
++}
++sub vsteg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRX(0xe70a,@_);
++}
++
++sub vstm {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	VRSa(0xe73e,@_);
++}
++
++sub vstl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRSb(0xe73f,@_);
++}
++
++sub vuph {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7d7,@_);
++}
++sub vuphb {
++	vuph(@_,0);
++}
++sub vuphh {
++	vuph(@_,1);
++}
++sub vuphf {
++	vuph(@_,2);
++}
++
++sub vuplh {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7d5,@_);
++}
++sub vuplhb {
++	vuplh(@_,0);
++}
++sub vuplhh {
++	vuplh(@_,1);
++}
++sub vuplhf {
++	vuplh(@_,2);
++}
++
++sub vupl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7d6,@_);
++}
++sub vuplb {
++	vupl(@_,0);
++}
++sub vuplhw {
++	vupl(@_,1);
++}
++sub vuplf {
++	vupl(@_,2);
++}
++
++sub vupll {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7d4,@_);
++}
++sub vupllb {
++	vupll(@_,0);
++}
++sub vupllh {
++	vupll(@_,1);
++}
++sub vupllf {
++	vupll(@_,2);
++}
++
++# VX - Integer Instructions
++
++sub va {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f3,@_);
++}
++sub vab {
++	va(@_,0);
++}
++sub vah {
++	va(@_,1);
++}
++sub vaf {
++	va(@_,2);
++}
++sub vag {
++	va(@_,3);
++}
++sub vaq {
++	va(@_,4);
++}
++
++sub vacc {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f1,@_);
++}
++sub vaccb {
++	vacc(@_,0);
++}
++sub vacch {
++	vacc(@_,1);
++}
++sub vaccf {
++	vacc(@_,2);
++}
++sub vaccg {
++	vacc(@_,3);
++}
++sub vaccq {
++	vacc(@_,4);
++}
++
++sub vac {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7bb,@_);
++}
++sub vacq {
++	vac(@_,4);
++}
++
++sub vaccc {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7b9,@_);
++}
++sub vacccq {
++	vaccc(@_,4);
++}
++
++sub vn {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe768,@_);
++}
++
++sub vnc {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe769,@_);
++}
++
++sub vavg {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f2,@_);
++}
++sub vavgb {
++	vavg(@_,0);
++}
++sub vavgh {
++	vavg(@_,1);
++}
++sub vavgf {
++	vavg(@_,2);
++}
++sub vavgg {
++	vavg(@_,3);
++}
++
++sub vavgl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f0,@_);
++}
++sub vavglb {
++	vavgl(@_,0);
++}
++sub vavglh {
++	vavgl(@_,1);
++}
++sub vavglf {
++	vavgl(@_,2);
++}
++sub vavglg {
++	vavgl(@_,3);
++}
++
++sub vcksm {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe766,@_);
++}
++
++sub vec_ {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7db,@_);
++}
++sub vecb {
++	vec_(@_,0);
++}
++sub vech {
++	vec_(@_,1);
++}
++sub vecf {
++	vec_(@_,2);
++}
++sub vecg {
++	vec_(@_,3);
++}
++
++sub vecl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7d9,@_);
++}
++sub veclb {
++	vecl(@_,0);
++}
++sub veclh {
++	vecl(@_,1);
++}
++sub veclf {
++	vecl(@_,2);
++}
++sub veclg {
++	vecl(@_,3);
++}
++
++sub vceq {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRb(0xe7f8,@_);
++}
++sub vceqb {
++	vceq(@_,0,0);
++}
++sub vceqh {
++	vceq(@_,1,0);
++}
++sub vceqf {
++	vceq(@_,2,0);
++}
++sub vceqg {
++	vceq(@_,3,0);
++}
++sub vceqbs {
++	vceq(@_,0,1);
++}
++sub vceqhs {
++	vceq(@_,1,1);
++}
++sub vceqfs {
++	vceq(@_,2,1);
++}
++sub vceqgs {
++	vceq(@_,3,1);
++}
++
++sub vch {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRb(0xe7fb,@_);
++}
++sub vchb {
++	vch(@_,0,0);
++}
++sub vchh {
++	vch(@_,1,0);
++}
++sub vchf {
++	vch(@_,2,0);
++}
++sub vchg {
++	vch(@_,3,0);
++}
++sub vchbs {
++	vch(@_,0,1);
++}
++sub vchhs {
++	vch(@_,1,1);
++}
++sub vchfs {
++	vch(@_,2,1);
++}
++sub vchgs {
++	vch(@_,3,1);
++}
++
++sub vchl {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRb(0xe7f9,@_);
++}
++sub vchlb {
++	vchl(@_,0,0);
++}
++sub vchlh {
++	vchl(@_,1,0);
++}
++sub vchlf {
++	vchl(@_,2,0);
++}
++sub vchlg {
++	vchl(@_,3,0);
++}
++sub vchlbs {
++	vchl(@_,0,1);
++}
++sub vchlhs {
++	vchl(@_,1,1);
++}
++sub vchlfs {
++	vchl(@_,2,1);
++}
++sub vchlgs {
++	vchl(@_,3,1);
++}
++
++sub vclz {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe753,@_);
++}
++sub vclzb {
++	vclz(@_,0);
++}
++sub vclzh {
++	vclz(@_,1);
++}
++sub vclzf {
++	vclz(@_,2);
++}
++sub vclzg {
++	vclz(@_,3);
++}
++
++sub vctz {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe752,@_);
++}
++sub vctzb {
++	vctz(@_,0);
++}
++sub vctzh {
++	vctz(@_,1);
++}
++sub vctzf {
++	vctz(@_,2);
++}
++sub vctzg {
++	vctz(@_,3);
++}
++
++sub vx {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76d,@_);
++}
++
++sub vgfm {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7b4,@_);
++}
++sub vgfmb {
++	vgfm(@_,0);
++}
++sub vgfmh {
++	vgfm(@_,1);
++}
++sub vgfmf {
++	vgfm(@_,2);
++}
++sub vgfmg {
++	vgfm(@_,3);
++}
++
++sub vgfma {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7bc,@_);
++}
++sub vgfmab {
++	vgfma(@_,0);
++}
++sub vgfmah {
++	vgfma(@_,1);
++}
++sub vgfmaf {
++	vgfma(@_,2);
++}
++sub vgfmag {
++	vgfma(@_,3);
++}
++
++sub vlc {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7de,@_);
++}
++sub vlcb {
++	vlc(@_,0);
++}
++sub vlch {
++	vlc(@_,1);
++}
++sub vlcf {
++	vlc(@_,2);
++}
++sub vlcg {
++	vlc(@_,3);
++}
++
++sub vlp {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe7df,@_);
++}
++sub vlpb {
++	vlp(@_,0);
++}
++sub vlph {
++	vlp(@_,1);
++}
++sub vlpf {
++	vlp(@_,2);
++}
++sub vlpg {
++	vlp(@_,3);
++}
++
++sub vmx {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7ff,@_);
++}
++sub vmxb {
++	vmx(@_,0);
++}
++sub vmxh {
++	vmx(@_,1);
++}
++sub vmxf {
++	vmx(@_,2);
++}
++sub vmxg {
++	vmx(@_,3);
++}
++
++sub vmxl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7fd,@_);
++}
++sub vmxlb {
++	vmxl(@_,0);
++}
++sub vmxlh {
++	vmxl(@_,1);
++}
++sub vmxlf {
++	vmxl(@_,2);
++}
++sub vmxlg {
++	vmxl(@_,3);
++}
++
++sub vmn {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7fe,@_);
++}
++sub vmnb {
++	vmn(@_,0);
++}
++sub vmnh {
++	vmn(@_,1);
++}
++sub vmnf {
++	vmn(@_,2);
++}
++sub vmng {
++	vmn(@_,3);
++}
++
++sub vmnl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7fc,@_);
++}
++sub vmnlb {
++	vmnl(@_,0);
++}
++sub vmnlh {
++	vmnl(@_,1);
++}
++sub vmnlf {
++	vmnl(@_,2);
++}
++sub vmnlg {
++	vmnl(@_,3);
++}
++
++sub vmal {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7aa,@_);
++}
++sub vmalb {
++	vmal(@_,0);
++}
++sub vmalhw {
++	vmal(@_,1);
++}
++sub vmalf {
++	vmal(@_,2);
++}
++
++sub vmah {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7ab,@_);
++}
++sub vmahb {
++	vmah(@_,0);
++}
++sub vmahh {
++	vmah(@_,1);
++}
++sub vmahf {
++	vmah(@_,2);
++}
++
++sub vmalh {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7a9,@_);
++}
++sub vmalhb {
++	vmalh(@_,0);
++}
++sub vmalhh {
++	vmalh(@_,1);
++}
++sub vmalhf {
++	vmalh(@_,2);
++}
++
++sub vmae {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7ae,@_);
++}
++sub vmaeb {
++	vmae(@_,0);
++}
++sub vmaeh {
++	vmae(@_,1);
++}
++sub vmaef {
++	vmae(@_,2);
++}
++
++sub vmale {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7ac,@_);
++}
++sub vmaleb {
++	vmale(@_,0);
++}
++sub vmaleh {
++	vmale(@_,1);
++}
++sub vmalef {
++	vmale(@_,2);
++}
++
++sub vmao {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7af,@_);
++}
++sub vmaob {
++	vmao(@_,0);
++}
++sub vmaoh {
++	vmao(@_,1);
++}
++sub vmaof {
++	vmao(@_,2);
++}
++
++sub vmalo {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7ad,@_);
++}
++sub vmalob {
++	vmalo(@_,0);
++}
++sub vmaloh {
++	vmalo(@_,1);
++}
++sub vmalof {
++	vmalo(@_,2);
++}
++
++sub vmh {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a3,@_);
++}
++sub vmhb {
++	vmh(@_,0);
++}
++sub vmhh {
++	vmh(@_,1);
++}
++sub vmhf {
++	vmh(@_,2);
++}
++
++sub vmlh {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a1,@_);
++}
++sub vmlhb {
++	vmlh(@_,0);
++}
++sub vmlhh {
++	vmlh(@_,1);
++}
++sub vmlhf {
++	vmlh(@_,2);
++}
++
++sub vml {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a2,@_);
++}
++sub vmlb {
++	vml(@_,0);
++}
++sub vmlhw {
++	vml(@_,1);
++}
++sub vmlf {
++	vml(@_,2);
++}
++
++sub vme {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a6,@_);
++}
++sub vmeb {
++	vme(@_,0);
++}
++sub vmeh {
++	vme(@_,1);
++}
++sub vmef {
++	vme(@_,2);
++}
++
++sub vmle {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a4,@_);
++}
++sub vmleb {
++	vmle(@_,0);
++}
++sub vmleh {
++	vmle(@_,1);
++}
++sub vmlef {
++	vmle(@_,2);
++}
++
++sub vmo {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a7,@_);
++}
++sub vmob {
++	vmo(@_,0);
++}
++sub vmoh {
++	vmo(@_,1);
++}
++sub vmof {
++	vmo(@_,2);
++}
++
++sub vmlo {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7a5,@_);
++}
++sub vmlob {
++	vmlo(@_,0);
++}
++sub vmloh {
++	vmlo(@_,1);
++}
++sub vmlof {
++	vmlo(@_,2);
++}
++
++sub vno {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76b,@_);
++}
++sub vnot {
++	vno(@_,$_[1]);
++}
++
++sub vo {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76a,@_);
++}
++
++sub vpopct {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRa(0xe750,@_);
++}
++
++sub verllv {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe773,@_);
++}
++sub verllvb {
++	verllv(@_,0);
++}
++sub verllvh {
++	verllv(@_,1);
++}
++sub verllvf {
++	verllv(@_,2);
++}
++sub verllvg {
++	verllv(@_,3);
++}
++
++sub verll {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSa(0xe733,@_);
++}
++sub verllb {
++	verll(@_,0);
++}
++sub verllh {
++	verll(@_,1);
++}
++sub verllf {
++	verll(@_,2);
++}
++sub verllg {
++	verll(@_,3);
++}
++
++sub verim {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRId(0xe772,@_);
++}
++sub verimb {
++	verim(@_,0);
++}
++sub verimh {
++	verim(@_,1);
++}
++sub verimf {
++	verim(@_,2);
++}
++sub verimg {
++	verim(@_,3);
++}
++
++sub veslv {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe770,@_);
++}
++sub veslvb {
++	veslv(@_,0);
++}
++sub veslvh {
++	veslv(@_,1);
++}
++sub veslvf {
++	veslv(@_,2);
++}
++sub veslvg {
++	veslv(@_,3);
++}
++
++sub vesl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSa(0xe730,@_);
++}
++sub veslb {
++	vesl(@_,0);
++}
++sub veslh {
++	vesl(@_,1);
++}
++sub veslf {
++	vesl(@_,2);
++}
++sub veslg {
++	vesl(@_,3);
++}
++
++sub vesrav {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe77a,@_);
++}
++sub vesravb {
++	vesrav(@_,0);
++}
++sub vesravh {
++	vesrav(@_,1);
++}
++sub vesravf {
++	vesrav(@_,2);
++}
++sub vesravg {
++	vesrav(@_,3);
++}
++
++sub vesra {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSa(0xe73a,@_);
++}
++sub vesrab {
++	vesra(@_,0);
++}
++sub vesrah {
++	vesra(@_,1);
++}
++sub vesraf {
++	vesra(@_,2);
++}
++sub vesrag {
++	vesra(@_,3);
++}
++
++sub vesrlv {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe778,@_);
++}
++sub vesrlvb {
++	vesrlv(@_,0);
++}
++sub vesrlvh {
++	vesrlv(@_,1);
++}
++sub vesrlvf {
++	vesrlv(@_,2);
++}
++sub vesrlvg {
++	vesrlv(@_,3);
++}
++
++sub vesrl {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRSa(0xe738,@_);
++}
++sub vesrlb {
++	vesrl(@_,0);
++}
++sub vesrlh {
++	vesrl(@_,1);
++}
++sub vesrlf {
++	vesrl(@_,2);
++}
++sub vesrlg {
++	vesrl(@_,3);
++}
++
++sub vsl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe774,@_);
++}
++
++sub vslb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe775,@_);
++}
++
++sub vsldb {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRId(0xe777,@_);
++}
++
++sub vsra {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe77e,@_);
++}
++
++sub vsrab {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe77f,@_);
++}
++
++sub vsrl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe77c,@_);
++}
++
++sub vsrlb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe77d,@_);
++}
++
++sub vs {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f7,@_);
++}
++sub vsb {
++	vs(@_,0);
++}
++sub vsh {
++	vs(@_,1);
++}
++sub vsf {
++	vs(@_,2);
++}
++sub vsg {
++	vs(@_,3);
++}
++sub vsq {
++	vs(@_,4);
++}
++
++sub vscbi {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe7f5,@_);
++}
++sub vscbib {
++	vscbi(@_,0);
++}
++sub vscbih {
++	vscbi(@_,1);
++}
++sub vscbif {
++	vscbi(@_,2);
++}
++sub vscbig {
++	vscbi(@_,3);
++}
++sub vscbiq {
++	vscbi(@_,4);
++}
++
++sub vsbi {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7bf,@_);
++}
++sub vsbiq {
++	vsbi(@_,4);
++}
++
++sub vsbcbi {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRd(0xe7bd,@_);
++}
++sub vsbcbiq {
++	vsbcbi(@_,4);
++}
++
++sub vsumg {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe765,@_);
++}
++sub vsumgh {
++	vsumg(@_,1);
++}
++sub vsumgf {
++	vsumg(@_,2);
++}
++
++sub vsumq {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe767,@_);
++}
++sub vsumqf {
++	vsumq(@_,2);
++}
++sub vsumqg {
++	vsumq(@_,3);
++}
++
++sub vsum {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRc(0xe764,@_);
++}
++sub vsumb {
++	vsum(@_,0);
++}
++sub vsumh {
++	vsum(@_,1);
++}
++
++sub vtm {
++	confess(err("ARGNUM")) if ($#_!=1);
++	VRRa(0xe7d8,@_);
++}
++
++# VX - String Instructions
++
++sub vfae {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	VRRb(0xe782,@_);
++}
++sub vfaeb {
++	vfae(@_[0..2],0,$_[3]);
++}
++sub vfaeh {
++	vfae(@_[0..2],1,$_[3]);
++}
++sub vfaef {
++	vfae(@_[0..2],2,$_[3]);
++}
++sub vfaebs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],0,0x1|$_[3]);
++}
++sub vfaehs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],1,0x1|$_[3]);
++}
++sub vfaefs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],2,0x1|$_[3]);
++}
++sub vfaezb {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],0,0x2|$_[3]);
++}
++sub vfaezh {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],1,0x2|$_[3]);
++}
++sub vfaezf {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],2,0x2|$_[3]);
++}
++sub vfaezbs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],0,0x3|$_[3]);
++}
++sub vfaezhs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],1,0x3|$_[3]);
++}
++sub vfaezfs {
++	$_[3]=0 if (!defined($_[3]));
++	vfae(@_[0..2],2,0x3|$_[3]);
++}
++
++sub vfee {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	VRRb(0xe780,@_);
++}
++sub vfeeb {
++	vfee(@_[0..2],0,$_[3]);
++}
++sub vfeeh {
++	vfee(@_[0..2],1,$_[3]);
++}
++sub vfeef {
++	vfee(@_[0..2],2,$_[3]);
++}
++sub vfeebs {
++	vfee(@_,0,1);
++}
++sub vfeehs {
++	vfee(@_,1,1);
++}
++sub vfeefs {
++	vfee(@_,2,1);
++}
++sub vfeezb {
++	vfee(@_,0,2);
++}
++sub vfeezh {
++	vfee(@_,1,2);
++}
++sub vfeezf {
++	vfee(@_,2,2);
++}
++sub vfeezbs {
++	vfee(@_,0,3);
++}
++sub vfeezhs {
++	vfee(@_,1,3);
++}
++sub vfeezfs {
++	vfee(@_,2,3);
++}
++
++sub vfene {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	VRRb(0xe781,@_);
++}
++sub vfeneb {
++	vfene(@_[0..2],0,$_[3]);
++}
++sub vfeneh {
++	vfene(@_[0..2],1,$_[3]);
++}
++sub vfenef {
++	vfene(@_[0..2],2,$_[3]);
++}
++sub vfenebs {
++	vfene(@_,0,1);
++}
++sub vfenehs {
++	vfene(@_,1,1);
++}
++sub vfenefs {
++	vfene(@_,2,1);
++}
++sub vfenezb {
++	vfene(@_,0,2);
++}
++sub vfenezh {
++	vfene(@_,1,2);
++}
++sub vfenezf {
++	vfene(@_,2,2);
++}
++sub vfenezbs {
++	vfene(@_,0,3);
++}
++sub vfenezhs {
++	vfene(@_,1,3);
++}
++sub vfenezfs {
++	vfene(@_,2,3);
++}
++
++sub vistr {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	VRRa(0xe75c,@_[0..2],0,$_[3]);
++}
++sub vistrb {
++	vistr(@_[0..1],0,$_[2]);
++}
++sub vistrh {
++	vistr(@_[0..1],1,$_[2]);
++}
++sub vistrf {
++	vistr(@_[0..1],2,$_[2]);
++}
++sub vistrbs {
++	vistr(@_,0,1);
++}
++sub vistrhs {
++	vistr(@_,1,1);
++}
++sub vistrfs {
++	vistr(@_,2,1);
++}
++
++sub vstrc {
++	confess(err("ARGNUM")) if ($#_<4||$#_>5);
++	VRRd(0xe78a,@_);
++}
++sub vstrcb {
++	vstrc(@_[0..3],0,$_[4]);
++}
++sub vstrch {
++	vstrc(@_[0..3],1,$_[4]);
++}
++sub vstrcf {
++	vstrc(@_[0..3],2,$_[4]);
++}
++sub vstrcbs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],0,0x1|$_[4]);
++}
++sub vstrchs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],1,0x1|$_[4]);
++}
++sub vstrcfs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],2,0x1|$_[4]);
++}
++sub vstrczb {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],0,0x2|$_[4]);
++}
++sub vstrczh {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],1,0x2|$_[4]);
++}
++sub vstrczf {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],2,0x2|$_[4]);
++}
++sub vstrczbs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],0,0x3|$_[4]);
++}
++sub vstrczhs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],1,0x3|$_[4]);
++}
++sub vstrczfs {
++	$_[4]=0 if (!defined($_[4]));
++	vstrc(@_[0..3],2,0x3|$_[4]);
++}
++
++# VX - Floating-point Instructions
++
++sub vfa {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRc(0xe7e3,@_);
++}
++sub vfadb {
++	vfa(@_,3,0);
++}
++sub wfadb {
++	vfa(@_,3,8);
++}
++
++sub wfc {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRa(0xe7cb,@_);
++}
++sub wfcdb {
++	wfc(@_,3,0);
++}
++
++sub wfk {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRa(0xe7ca,@_);
++}
++sub wfksb {
++	wfk(@_,2,0);
++}
++sub wfkdb {
++	wfk(@_,3,0);
++}
++sub wfkxb {
++	wfk(@_,4,0);
++}
++
++sub vfce {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRc(0xe7e8,@_);
++}
++sub vfcedb {
++	vfce(@_,3,0,0);
++}
++sub vfcedbs {
++	vfce(@_,3,0,1);
++}
++sub wfcedb {
++	vfce(@_,3,8,0);
++}
++sub wfcedbs {
++	vfce(@_,3,8,1);
++}
++
++sub vfch {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRc(0xe7eb,@_);
++}
++sub vfchdb {
++	vfch(@_,3,0,0);
++}
++sub vfchdbs {
++	vfch(@_,3,0,1);
++}
++sub wfchdb {
++	vfch(@_,3,8,0);
++}
++sub wfchdbs {
++	vfch(@_,3,8,1);
++}
++
++sub vfche {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRc(0xe7ea,@_);
++}
++sub vfchedb {
++	vfche(@_,3,0,0);
++}
++sub vfchedbs {
++	vfche(@_,3,0,1);
++}
++sub wfchedb {
++	vfche(@_,3,8,0);
++}
++sub wfchedbs {
++	vfche(@_,3,8,1);
++}
++
++sub vcdg {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c3,@_);
++}
++sub vcdgb {
++	vcdg(@_[0..1],3,@_[2..3]);
++}
++sub wcdgb {
++	vcdg(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vcdlg {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c1,@_);
++}
++sub vcdlgb {
++	vcdlg(@_[0..1],3,@_[2..3]);
++}
++sub wcdlgb {
++	vcdlg(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vcgd {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c2,@_);
++}
++sub vcgdb {
++	vcgd(@_[0..1],3,@_[2..3]);
++}
++sub wcgdb {
++	vcgd(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vclgd {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c0,@_);
++}
++sub vclgdb {
++	vclgd(@_[0..1],3,@_[2..3]);
++}
++sub wclgdb {
++	vclgd(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vfd {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRc(0xe7e5,@_);
++}
++sub vfddb {
++	vfd(@_,3,0);
++}
++sub wfddb {
++	vfd(@_,3,8);
++}
++
++sub vfi {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c7,@_);
++}
++sub vfidb {
++	vfi(@_[0..1],3,@_[2..3]);
++}
++sub wfidb {
++	vfi(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vlde {	# deprecated, use vfll
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRa(0xe7c4,@_);
++}
++sub vldeb {	# deprecated, use vflls
++	vlde(@_,2,0);
++}
++sub wldeb {	# deprecated, use wflls
++	vlde(@_,2,8);
++}
++
++sub vled {	# deprecated, use vflr
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7c5,@_);
++}
++sub vledb {	# deprecated, use vflrd
++	vled(@_[0..1],3,@_[2..3]);
++}
++sub wledb {	# deprecated, use wflrd
++	vled(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++
++sub vfm {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRc(0xe7e7,@_);
++}
++sub vfmdb {
++	vfm(@_,3,0);
++}
++sub wfmdb {
++	vfm(@_,3,8);
++}
++
++sub vfma {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRe(0xe78f,@_);
++}
++sub vfmadb {
++	vfma(@_,0,3);
++}
++sub wfmadb {
++	vfma(@_,8,3);
++}
++
++sub vfms {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRe(0xe78e,@_);
++}
++sub vfmsdb {
++	vfms(@_,0,3);
++}
++sub wfmsdb {
++	vfms(@_,8,3);
++}
++
++sub vfpso {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRa(0xe7cc,@_);
++}
++sub vfpsodb {
++	vfpso(@_[0..1],3,0,$_[2]);
++}
++sub wfpsodb {
++	vfpso(@_[0..1],3,8,$_[2]);
++}
++sub vflcdb {
++	vfpso(@_,3,0,0);
++}
++sub wflcdb {
++	vfpso(@_,3,8,0);
++}
++sub vflndb {
++	vfpso(@_,3,0,1);
++}
++sub wflndb {
++	vfpso(@_,3,8,1);
++}
++sub vflpdb {
++	vfpso(@_,3,0,2);
++}
++sub wflpdb {
++	vfpso(@_,3,8,2);
++}
++
++sub vfsq {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRRa(0xe7ce,@_);
++}
++sub vfsqdb {
++	vfsq(@_,3,0);
++}
++sub wfsqdb {
++	vfsq(@_,3,8);
++}
++
++sub vfs {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRRc(0xe7e2,@_);
++}
++sub vfsdb {
++	vfs(@_,3,0);
++}
++sub wfsdb {
++	vfs(@_,3,8);
++}
++
++sub vftci {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIe(0xe74a,@_);
++}
++sub vftcidb {
++	vftci(@_,3,0);
++}
++sub wftcidb {
++	vftci(@_,3,8);
++}
++
++# VXE - Support Instructions
++
++sub vbperm {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe785,@_);
++}
++
++sub vllezlf {
++	vllez(@_,6);
++}
++
++# VXE - Integer Instructions
++
++sub vmsl {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRd(0xe7b8,@_);
++}
++sub vmslg {
++	vmsl(@_[0..3],3,$_[4]);
++}
++
++sub vnx {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76c,@_);
++}
++
++sub vnn {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76e,@_);
++}
++
++sub voc {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRc(0xe76f,@_);
++}
++
++sub vpopctb {
++	vpopct(@_,0);
++}
++sub vpopcth {
++	vpopct(@_,1);
++}
++sub vpopctf {
++	vpopct(@_,2);
++}
++sub vpopctg {
++	vpopct(@_,3);
++}
++
++# VXE - Floating-Point Instructions
++
++sub vfasb {
++	vfa(@_,2,0);
++}
++sub wfasb {
++	vfa(@_,2,8);
++}
++sub wfaxb {
++	vfa(@_,4,8);
++}
++
++sub wfcsb {
++	wfc(@_,2,0);
++}
++sub wfcxb {
++	wfc(@_,4,0);
++}
++
++sub vfcesb {
++	vfce(@_,2,0,0);
++}
++sub vfcesbs {
++	vfce(@_,2,0,1);
++}
++sub wfcesb {
++	vfce(@_,2,8,0);
++}
++sub wfcesbs {
++	vfce(@_,2,8,1);
++}
++sub wfcexb {
++	vfce(@_,4,8,0);
++}
++sub wfcexbs {
++	vfce(@_,4,8,1);
++}
++
++sub vfchsb {
++	vfch(@_,2,0,0);
++}
++sub vfchsbs {
++	vfch(@_,2,0,1);
++}
++sub wfchsb {
++	vfch(@_,2,8,0);
++}
++sub wfchsbs {
++	vfch(@_,2,8,1);
++}
++sub wfchxb {
++	vfch(@_,4,8,0);
++}
++sub wfchxbs {
++	vfch(@_,4,8,1);
++}
++
++sub vfchesb {
++	vfche(@_,2,0,0);
++}
++sub vfchesbs {
++	vfche(@_,2,0,1);
++}
++sub wfchesb {
++	vfche(@_,2,8,0);
++}
++sub wfchesbs {
++	vfche(@_,2,8,1);
++}
++sub wfchexb {
++	vfche(@_,4,8,0);
++}
++sub wfchexbs {
++	vfche(@_,4,8,1);
++}
++
++sub vfdsb {
++	vfd(@_,2,0);
++}
++sub wfdsb {
++	vfd(@_,2,8);
++}
++sub wfdxb {
++	vfd(@_,4,8);
++}
++
++sub vfisb {
++	vfi(@_[0..1],2,@_[2..3]);
++}
++sub wfisb {
++	vfi(@_[0..1],2,0x8|$_[2],$_[3]);
++}
++sub wfixb {
++	vfi(@_[0..1],4,0x8|$_[2],$_[3]);
++}
++
++sub vfll {
++	vlde(@_);
++}
++sub vflls {
++	vfll(@_,2,0);
++}
++sub wflls {
++	vfll(@_,2,8);
++}
++sub wflld {
++	vfll(@_,3,8);
++}
++
++sub vflr {
++	vled(@_);
++}
++sub vflrd {
++	vflr(@_[0..1],3,@_[2..3]);
++}
++sub wflrd {
++	vflr(@_[0..1],3,0x8|$_[2],$_[3]);
++}
++sub wflrx {
++	vflr(@_[0..1],4,0x8|$_[2],$_[3]);
++}
++
++sub vfmax {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRc(0xe7ef,@_);
++}
++sub vfmaxsb {
++	vfmax(@_[0..2],2,0,$_[3]);
++}
++sub vfmaxdb {
++	vfmax(@_[0..2],3,0,$_[3]);
++}
++sub wfmaxsb {
++	vfmax(@_[0..2],2,8,$_[3]);
++}
++sub wfmaxdb {
++	vfmax(@_[0..2],3,8,$_[3]);
++}
++sub wfmaxxb {
++	vfmax(@_[0..2],4,8,$_[3]);
++}
++
++sub vfmin {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRc(0xe7ee,@_);
++}
++sub vfminsb {
++	vfmin(@_[0..2],2,0,$_[5]);
++}
++sub vfmindb {
++	vfmin(@_[0..2],3,0,$_[5]);
++}
++sub wfminsb {
++	vfmin(@_[0..2],2,8,$_[5]);
++}
++sub wfmindb {
++	vfmin(@_[0..2],3,8,$_[5]);
++}
++sub wfminxb {
++	vfmin(@_[0..2],4,8,$_[5]);
++}
++
++sub vfmsb {
++	vfm(@_,2,0);
++}
++sub wfmsb {
++	vfm(@_,2,8);
++}
++sub wfmxb {
++	vfm(@_,4,8);
++}
++
++sub vfmasb {
++	vfma(@_,0,2);
++}
++sub wfmasb {
++	vfma(@_,8,2);
++}
++sub wfmaxb {
++	vfma(@_,8,4);
++}
++
++sub vfmssb {
++	vfms(@_,0,2);
++}
++sub wfmssb {
++	vfms(@_,8,2);
++}
++sub wfmsxb {
++	vfms(@_,8,4);
++}
++
++sub vfnma {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRe(0xe79f,@_);
++}
++sub vfnmasb {
++	vfnma(@_,0,2);
++}
++sub vfnmadb {
++	vfnma(@_,0,3);
++}
++sub wfnmasb {
++	vfnma(@_,8,2);
++}
++sub wfnmadb {
++	vfnma(@_,8,3);
++}
++sub wfnmaxb {
++	vfnma(@_,8,4);
++}
++
++sub vfnms {
++	confess(err("ARGNUM")) if ($#_!=5);
++	VRRe(0xe79e,@_);
++}
++sub vfnmssb {
++	vfnms(@_,0,2);
++}
++sub vfnmsdb {
++	vfnms(@_,0,3);
++}
++sub wfnmssb {
++	vfnms(@_,8,2);
++}
++sub wfnmsdb {
++	vfnms(@_,8,3);
++}
++sub wfnmsxb {
++	vfnms(@_,8,4);
++}
++
++sub vfpsosb {
++	vfpso(@_[0..1],2,0,$_[2]);
++}
++sub wfpsosb {
++	vfpso(@_[0..1],2,8,$_[2]);
++}
++sub vflcsb {
++	vfpso(@_,2,0,0);
++}
++sub wflcsb {
++	vfpso(@_,2,8,0);
++}
++sub vflnsb {
++	vfpso(@_,2,0,1);
++}
++sub wflnsb {
++	vfpso(@_,2,8,1);
++}
++sub vflpsb {
++	vfpso(@_,2,0,2);
++}
++sub wflpsb {
++	vfpso(@_,2,8,2);
++}
++sub vfpsoxb {
++	vfpso(@_[0..1],4,0,$_[2]);
++}
++sub wfpsoxb {
++	vfpso(@_[0..1],4,8,$_[2]);
++}
++sub vflcxb {
++	vfpso(@_,4,0,0);
++}
++sub wflcxb {
++	vfpso(@_,4,8,0);
++}
++sub vflnxb {
++	vfpso(@_,4,0,1);
++}
++sub wflnxb {
++	vfpso(@_,4,8,1);
++}
++sub vflpxb {
++	vfpso(@_,4,0,2);
++}
++sub wflpxb {
++	vfpso(@_,4,8,2);
++}
++
++sub vfsqsb {
++	vfsq(@_,2,0);
++}
++sub wfsqsb {
++	vfsq(@_,2,8);
++}
++sub wfsqxb {
++	vfsq(@_,4,8);
++}
++
++sub vfssb {
++	vfs(@_,2,0);
++}
++sub wfssb {
++	vfs(@_,2,8);
++}
++sub wfsxb {
++	vfs(@_,4,8);
++}
++
++sub vftcisb {
++	vftci(@_,2,0);
++}
++sub wftcisb {
++	vftci(@_,2,8);
++}
++sub wftcixb {
++	vftci(@_,4,8);
++}
++
++# VXD - Support Instructions
++
++sub vlrlr {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRSd(0xe637,@_);
++}
++
++sub vlrl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VSI(0xe635,@_);
++}
++
++sub vstrlr {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRSd(0xe63f,@_);
++}
++
++sub vstrl {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VSI(0xe63d,@_);
++}
++
++sub vap {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe671,@_);
++}
++
++sub vcp {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRh(0xe677,@_);
++}
++
++sub vcvb {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRi(0xe650,@_);
++}
++
++sub vcvbg {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRRi(0xe652,@_);
++}
++
++sub vcvd {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRIi(0xe658,@_);
++}
++
++sub vcvdg {
++	confess(err("ARGNUM")) if ($#_!=3);
++	VRIi(0xe65a,@_);
++}
++
++sub vdp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe67a,@_);
++}
++
++sub vlip {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VRIh(0xe649,@_);
++}
++
++sub vmp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe678,@_);
++}
++
++sub vmsp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe679,@_);
++}
++
++sub vpkz {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VSI(0xe634,@_);
++}
++
++sub vpsop {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIg(0xe65b,@_);
++}
++
++sub vrp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe67b,@_);
++}
++
++sub vsdp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe67e,@_);
++}
++
++sub vsrp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIg(0xe659,@_);
++}
++
++sub vsp {
++	confess(err("ARGNUM")) if ($#_!=4);
++	VRIf(0xe673,@_);
++}
++
++sub vtp {
++	confess(err("ARGNUM")) if ($#_!=0);
++	VRRg(0xe65f,@_);
++}
++
++sub vupkz {
++	confess(err("ARGNUM")) if ($#_!=2);
++	VSI(0xe63c,@_);
++}
++
++#
++# Instruction Formats
++#
++
++sub RIEf {
++	confess(err("ARGNUM")) if ($#_<4||5<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$r2,$i3,$i4,$i5)=(shift,get_R(shift),get_R(shift),
++					  get_I(shift,8),get_I(shift,8),
++					  get_I(shift,8));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",(($opcode>>8)<<8|$r1<<4|$r2)).",";
++	$out.=sprintf("%#06x",($i3<<8)|$i4).",";
++	$out.=sprintf("%#06x",($i5<<8)|($opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub RILa {
++	confess(err("ARGNUM")) if ($#_!=2);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$i2)=(shift,get_R(shift),get_I(shift,32));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",(($opcode>>4)<<8|$r1<<4|($opcode&0xf))).",";
++	$out.=sprintf("%#06x",($i2>>16)).",";
++	$out.=sprintf("%#06x",($i2&0xffff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub RRE {
++	confess(err("ARGNUM")) if ($#_<0||2<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$r2)=(shift,get_R(shift),get_R(shift));
++
++	$out.="\t.long\t".sprintf("%#010x",($opcode<<16|$r1<<4|$r2));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub RRFb {
++	confess(err("ARGNUM")) if ($#_<3||4<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$r3,$r2,$m4)=(shift,get_R(shift),get_R(shift)
++	    ,get_R(shift),get_M(shift));
++
++	$out.="\t.long\t"
++	    .sprintf("%#010x",($opcode<<16|$r3<<12|$m4<<8|$r1<<4|$r2));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub RXYa {
++	confess(err("ARGNUM")) if ($#_!=2);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$d2,$x2,$b2)=(shift,get_R(shift),get_DXB(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",(($opcode>>8)<<8|$r1<<4|$x2)).",";
++	$out.=sprintf("%#06x",($b2<<12|($d2&0xfff))).",";
++	$out.=sprintf("%#06x",(($d2>>12)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub S {
++	confess(err("ARGNUM")) if ($#_<0||1<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$d2,$b2)=(shift,get_DB(shift));
++
++	$out.="\t.long\t".sprintf("%#010x",($opcode<<16|$b2<<12|$d2));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIa {
++	confess(err("ARGNUM")) if ($#_<2||3<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$i2,$m3)=(shift,get_V(shift),get_I(shift,16),
++	    get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)).",";
++	$out.=sprintf("%#06x",$i2).",";
++	$out.=sprintf("%#06x",($m3<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIb {
++	confess(err("ARGNUM")) if ($#_!=4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$i2,$i3,$m4)=(shift,get_V(shift),get_I(shift,8),
++	    ,get_I(shift,8),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)).",";
++	$out.=sprintf("%#06x",($i2<<8|$i3)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIc {
++	confess(err("ARGNUM")) if ($#_!=4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v3,$i2,$m4)=(shift,get_V(shift),get_V(shift),
++	    ,get_I(shift,16),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|($v3&0xf)).",";
++	$out.=sprintf("%#06x",$i2).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRId {
++	confess(err("ARGNUM")) if ($#_<4||$#_>5);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$i4,$m5)=(shift,get_V(shift),get_V(shift),
++	    ,get_V(shift),get_I(shift,8),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|($v2&0xf)).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$i4)).",";
++	$out.=sprintf("%#06x",($m5<<12|RXB($v1,$v2,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIe {
++	confess(err("ARGNUM")) if ($#_!=5);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$i3,$m4,$m5)=(shift,get_V(shift),get_V(shift),
++	    ,get_I(shift,12),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|($v2&0xf)).",";
++	$out.=sprintf("%#06x",($i3<<4|$m5)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIf {
++	confess(err("ARGNUM")) if ($#_!=5);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$i4,$m5)=(shift,get_V(shift),get_V(shift),
++	    ,get_V(shift),get_I(shift,8),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|($v2&0xf)).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$m5<<4)|$i4>>4).",";
++	$out.=sprintf("%#06x",(($i4&0xf)<<12|RXB($v1,$v2,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIg {
++	confess(err("ARGNUM")) if ($#_!=5);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$i3,$i4,$m5)=(shift,get_V(shift),get_V(shift),
++	    ,get_I(shift,8),get_I(shift,8),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|($v2&0xf)).",";
++	$out.=sprintf("%#06x",($i4<<8|$m5<<4|$i3>>4)).",";
++	$out.=sprintf("%#06x",(($i3&0xf)<<12|RXB($v1,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIh {
++	confess(err("ARGNUM")) if ($#_!=3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$i2,$i3)=(shift,get_V(shift),get_I(shift,16),
++	    get_I(shift,4));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)).",";
++	$out.=sprintf("%#06x",$i2).",";
++	$out.=sprintf("%#06x",($i3<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRIi {
++	confess(err("ARGNUM")) if ($#_!=4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$r2,$i3,$m4)=(shift,get_V(shift),get_R(shift),
++	    ,get_I(shift,8),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4)|$r2).",";
++	$out.=sprintf("%#06x",($m4<<4|$i3>>4)).",";
++	$out.=sprintf("%#06x",(($i3&0xf)<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRa {
++	confess(err("ARGNUM")) if ($#_<2||5<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$m3,$m4,$m5)=(shift,get_V(shift),get_V(shift),
++	    get_M(shift),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",($m5<<4|$m4)).",";
++	$out.=sprintf("%#06x",($m3<<12|RXB($v1,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRb {
++	confess(err("ARGNUM")) if ($#_<3||5<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$m4,$m5)=(shift,get_V(shift),get_V(shift),
++	    get_V(shift),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$m5<<4)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1,$v2,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRc {
++	confess(err("ARGNUM")) if ($#_<3||6<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$m4,$m5,$m6)=(shift,get_V(shift),get_V(shift),
++	    get_V(shift),get_M(shift),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$m6<<4|$m5)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1,$v2,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRd {
++	confess(err("ARGNUM")) if ($#_<4||6<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$v4,$m5,$m6)=(shift,get_V(shift),get_V(shift),
++	    get_V(shift),get_V(shift),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$m5<<8|$m6<<4)).",";
++	$out.=sprintf("%#06x",(($v4&0xf)<<12|RXB($v1,$v2,$v3,$v4)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRe {
++	confess(err("ARGNUM")) if ($#_<4||6<$#_);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$v3,$v4,$m5,$m6)=(shift,get_V(shift),get_V(shift),
++	    get_V(shift),get_V(shift),get_M(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",(($v3&0xf)<<12|$m6<<8|$m5)).",";
++	$out.=sprintf("%#06x",(($v4&0xf)<<12|RXB($v1,$v2,$v3,$v4)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRf {
++	confess(err("ARGNUM")) if ($#_!=3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$r2,$r3)=(shift,get_V(shift),get_R(shift),
++	    get_R(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|$r2)).",";
++	$out.=sprintf("%#06x",($r3<<12)).",";
++	$out.=sprintf("%#06x",(RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRg {
++	confess(err("ARGNUM")) if ($#_!=1);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1)=(shift,get_V(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf))).",";
++	$out.=sprintf("%#06x",0x0000).",";
++	$out.=sprintf("%#06x",(RXB(0,$v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRh {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v2,$m3)=(shift,get_V(shift),get_V(shift),
++	    get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf))).",";
++	$out.=sprintf("%#06x",(($v2&0xf)<<12|$m3<<4)).",";
++	$out.=sprintf("%#06x",(RXB(0,$v1,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRRi {
++	confess(err("ARGNUM")) if ($#_!=3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$v2,$m3)=(shift,get_R(shift),get_V(shift),
++	    get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|$r1<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",($m3<<4))."\,";
++	$out.=sprintf("%#06x",(RXB(0,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRSa {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$v3,$d2,$b2,$m4)=(shift,get_V(shift),get_V(shift),
++	    get_DB(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v3&0xf))).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRSb {
++	confess(err("ARGNUM")) if ($#_<3||$#_>4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$r3,$d2,$b2,$m4)=(shift,get_V(shift),get_R(shift),
++	    get_DB(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|$r3)).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRSc {
++	confess(err("ARGNUM")) if ($#_!=4);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$r1,$v3,$d2,$b2,$m4)=(shift,get_R(shift),get_V(shift),
++	    get_DB(shift),get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|$r1<<4|($v3&0xf))).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",($m4<<12|RXB(0,$v3)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRSd {
++	confess(err("ARGNUM")) if ($#_!=3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$r3,$d2,$b2)=(shift,get_V(shift),get_R(shift),
++	    get_DB(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|$r3)).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",(($v1&0xf)<<12|RXB(0,0,0,$v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRV {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$d2,$v2,$b2,$m3)=(shift,get_V(shift),get_DVB(shift),
++	    get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($v2&0xf))).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",($m3<<12|RXB($v1,$v2)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VRX {
++	confess(err("ARGNUM")) if ($#_<2||$#_>3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$d2,$x2,$b2,$m3)=(shift,get_V(shift),get_DXB(shift),
++	    get_M(shift));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|($v1&0xf)<<4|($x2))).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",($m3<<12|RXB($v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++sub VSI {
++	confess(err("ARGNUM")) if ($#_!=3);
++	my $ops=join(',',@_[1..$#_]);
++	my $memn=(caller(1))[3];
++	$memn=~s/^.*:://;
++	my ($opcode,$v1,$d2,$b2,$i3)=(shift,get_V(shift),get_DB(shift),
++	    get_I(shift,8));
++
++	$out.="\t.word\t";
++	$out.=sprintf("%#06x",($opcode&0xff00|$i3)).",";
++	$out.=sprintf("%#06x",($b2<<12|$d2)).",";
++	$out.=sprintf("%#06x",(($v1&0xf)<<12|RXB(0,0,0,$v1)<<8|$opcode&0xff));
++	$out.="\t# $memn\t$ops\n"
++}
++
++#
++# Internal
++#
++
++sub get_R {
++	confess(err("ARGNUM")) if ($#_!=0);
++	my $r;
++
++	for (shift) {
++		if (!defined) {
++			$r=0;
++		} elsif (/^$GR$/) {
++			$r=$1;
++		} else {
++			confess(err("PARSE"));
++		}
++	}
++	confess(err("ARGRANGE")) if ($r&~0xf);
++
++	return $r;
++}
++
++sub get_V {
++	confess(err("ARGNUM")) if ($#_!=0);
++	my $v;
++
++	for (shift) {
++		if (!defined) {
++			$v=0;
++		} elsif (/^$VR$/) {
++			$v=$1;
++		} else {
++			confess(err("PARSE"));
++		}
++	}
++	confess(err("ARGRANGE")) if ($v&~0x1f);
++
++	return $v;
++}
++
++sub get_I {
++	confess(err("ARGNUM")) if ($#_!=1);
++	my ($i,$bits)=(shift,shift);
++
++	$i=defined($i)?(eval($i)):(0);
++	confess(err("PARSE")) if (!defined($i));
++	confess(err("ARGRANGE")) if (abs($i)&~(2**$bits-1));
++
++	return $i&(2**$bits-1);
++}
++
++sub get_M {
++	confess(err("ARGNUM")) if ($#_!=0);
++	my $m=shift;
++
++	$m=defined($m)?(eval($m)):(0);
++	confess(err("PARSE")) if (!defined($m));
++	confess(err("ARGRANGE")) if ($m&~0xf);
++
++	return $m;
++}
++
++sub get_DB
++{
++	confess(err("ARGNUM")) if ($#_!=0);
++	my ($d,$b);
++
++	for (shift) {
++		if (!defined) {
++			($d,$b)=(0,0);
++		} elsif (/^(.+)\($GR\)$/) {
++			($d,$b)=(eval($1),$2);
++			confess(err("PARSE")) if (!defined($d));
++		} elsif (/^(.+)$/) {
++			($d,$b)=(eval($1),0);
++			confess(err("PARSE")) if (!defined($d));
++		} else {
++			confess(err("PARSE"));
++		}
++	}
++	confess(err("ARGRANGE")) if ($d&~0xfff||$b&~0xf);
++
++	return ($d,$b);
++}
++
++sub get_DVB
++{
++	confess(err("ARGNUM")) if ($#_!=0);
++	my ($d,$v,$b);
++
++	for (shift) {
++		if (!defined) {
++			($d,$v,$b)=(0,0,0);
++		} elsif (/^(.+)\($VR,$GR\)$/) {
++			($d,$v,$b)=(eval($1),$2,$3);
++			confess(err("PARSE")) if (!defined($d));
++		} elsif (/^(.+)\($GR\)$/) {
++			($d,$v,$b)=(eval($1),0,$2);
++			confess(err("PARSE")) if (!defined($d));
++		} elsif (/^(.+)$/) {
++			($d,$v,$b)=(eval($1),0,0);
++			confess(err("PARSE")) if (!defined($d));
++		} else {
++			confess(err("PARSE"));
++		}
++	}
++	confess(err("ARGRANGE")) if ($d&~0xfff||$v&~0x1f||$b&~0xf);
++
++	return ($d,$v,$b);
++}
++
++sub get_DXB
++{
++	confess(err("ARGNUM")) if ($#_!=0);
++	my ($d,$x,$b);
++
++	for (shift) {
++		if (!defined) {
++			($d,$x,$b)=(0,0,0);
++		} elsif (/^(.+)\($GR,$GR\)$/) {
++			($d,$x,$b)=(eval($1),$2,$3);
++			confess(err("PARSE")) if (!defined($d));
++		} elsif (/^(.+)\($GR\)$/) {
++			($d,$x,$b)=(eval($1),0,$2);
++			confess(err("PARSE")) if (!defined($d));
++		} elsif (/^(.+)$/) {
++			($d,$x,$b)=(eval($1),0,0);
++			confess(err("PARSE")) if (!defined($d));
++		} else {
++			confess(err("PARSE"));
++		}
++	}
++	confess(err("ARGRANGE")) if ($d&~0xfff||$x&~0xf||$b&~0xf);
++
++	return ($d,$x,$b);
++}
++
++sub RXB
++{
++	confess(err("ARGNUM")) if ($#_<0||3<$#_);
++	my $rxb=0;
++
++	$rxb|=0x08 if (defined($_[0])&&($_[0]&0x10));
++	$rxb|=0x04 if (defined($_[1])&&($_[1]&0x10));
++	$rxb|=0x02 if (defined($_[2])&&($_[2]&0x10));
++	$rxb|=0x01 if (defined($_[3])&&($_[3]&0x10));
++
++	return $rxb;
++}
++
++sub err {
++	my %ERR		=
++	(
++		ARGNUM	=>	'Wrong number of arguments',
++		ARGRANGE=>	'Argument out of range',
++		PARSE	=>	'Parse error',
++	);
++	confess($ERR{ARGNUM}) if ($#_!=0);
++
++	return $ERR{$_[0]};
++}
++
++1;
+diff -up openssl-1.1.1b/crypto/poly1305/asm/poly1305-s390x.pl.s390x-update openssl-1.1.1b/crypto/poly1305/asm/poly1305-s390x.pl
+--- openssl-1.1.1b/crypto/poly1305/asm/poly1305-s390x.pl.s390x-update	2019-02-26 15:15:30.000000000 +0100
++++ openssl-1.1.1b/crypto/poly1305/asm/poly1305-s390x.pl	2019-05-06 10:59:30.860784805 +0200
+@@ -24,204 +24,961 @@
+ #
+ # On side note, z13 enables vector base 2^26 implementation...
+ 
+-$flavour = shift;
++#
++# January 2019
++#
++# Add vx code path (base 2^26).
++#
++# Copyright IBM Corp. 2019
++# Author: Patrick Steuer <patrick.steuer@de.ibm.com>
++
++#
++# January 2019
++#
++# Add vector base 2^26 implementation. It's problematic to accurately
++# measure performance, because reference system is hardly idle. But
++# it's sub-cycle, i.e. less than 1 cycle per processed byte, and it's
++# >=20% faster than IBM's submission on long inputs, and much faster on
++# short ones, because calculation of key powers is postponed till we
++# know that input is long enough to justify the additional overhead.
++
++use strict;
++use FindBin qw($Bin);
++use lib "$Bin/../..";
++use perlasm::s390x qw(:DEFAULT :LD :GE :EI :MI1 :VX AUTOLOAD LABEL INCLUDE);
++
++my $flavour = shift;
+ 
++my ($z,$SIZE_T);
+ if ($flavour =~ /3[12]/) {
++	$z=0;	# S/390 ABI
+ 	$SIZE_T=4;
+-	$g="";
+ } else {
++	$z=1;	# zSeries ABI
+ 	$SIZE_T=8;
+-	$g="g";
+ }
+ 
++my $output;
+ while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
+-open STDOUT,">$output";
+ 
+-$sp="%r15";
++my $stdframe=16*$SIZE_T+4*8;
++my $sp="%r15";
+ 
+ my ($ctx,$inp,$len,$padbit) = map("%r$_",(2..5));
+ 
+-$code.=<<___;
+-.text
++PERLASM_BEGIN($output);
+ 
+-.globl	poly1305_init
+-.type	poly1305_init,\@function
+-.align	16
+-poly1305_init:
+-	lghi	%r0,0
+-	lghi	%r1,-1
+-	stg	%r0,0($ctx)		# zero hash value
+-	stg	%r0,8($ctx)
+-	stg	%r0,16($ctx)
+-
+-	cl${g}r	$inp,%r0
+-	je	.Lno_key
+-
+-	lrvg	%r4,0($inp)		# load little-endian key
+-	lrvg	%r5,8($inp)
+-
+-	nihl	%r1,0xffc0		# 0xffffffc0ffffffff
+-	srlg	%r0,%r1,4		# 0x0ffffffc0fffffff
+-	srlg	%r1,%r1,4
+-	nill	%r1,0xfffc		# 0x0ffffffc0ffffffc
+-
+-	ngr	%r4,%r0
+-	ngr	%r5,%r1
+-
+-	stg	%r4,32($ctx)
+-	stg	%r5,40($ctx)
+-
+-.Lno_key:
+-	lghi	%r2,0
+-	br	%r14
+-.size	poly1305_init,.-poly1305_init
+-___
++INCLUDE	("s390x_arch.h");
++TEXT	();
++
++################
++# static void poly1305_init(void *ctx, const unsigned char key[16])
++{
++GLOBL	("poly1305_init");
++TYPE	("poly1305_init","\@function");
++ALIGN	(16);
++LABEL	("poly1305_init");
++	lghi	("%r0",0);
++	lghi	("%r1",-1);
++	stg	("%r0","0($ctx)");		# zero hash value
++	stg	("%r0","8($ctx)");
++	stg	("%r0","16($ctx)");
++	st	("%r0","24($ctx)");		# clear is_base2_26
++	lgr	("%r5",$ctx);			# reassign $ctx
++	lghi	("%r2",0);
++
++&{$z?	\&clgr:\&clr}	($inp,"%r0");
++	je	(".Lno_key");
++
++	lrvg	("%r2","0($inp)");		# load little-endian key
++	lrvg	("%r3","8($inp)");
++
++	nihl	("%r1",0xffc0);			# 0xffffffc0ffffffff
++	srlg	("%r0","%r1",4);		# 0x0ffffffc0fffffff
++	srlg	("%r1","%r1",4);
++	nill	("%r1",0xfffc);			# 0x0ffffffc0ffffffc
++
++	ngr	("%r2","%r0");
++	ngr	("%r3","%r1");
++
++	stmg	("%r2","%r3","32(%r5)");
++
++	larl	("%r1","OPENSSL_s390xcap_P");
++	lg	("%r0","16(%r1)");
++	srlg	("%r0","%r0",62);
++	nill	("%r0",1);			# extract vx bit
++	lcgr	("%r0","%r0");
++	larl	("%r1",".Lpoly1305_blocks");
++	larl	("%r2",".Lpoly1305_blocks_vx");
++	larl	("%r3",".Lpoly1305_emit");
++&{$z?	\&xgr:\&xr}	("%r2","%r1");		# select between scalar and vector
++&{$z?	\&ngr:\&nr}	("%r2","%r0");
++&{$z?	\&xgr:\&xr}	("%r2","%r1");
++&{$z?	\&stmg:\&stm}	("%r2","%r3","0(%r4)");
++	lghi	("%r2",1);
++LABEL	(".Lno_key");
++	br	("%r14");
++SIZE	("poly1305_init",".-poly1305_init");
++}
++
++################
++# static void poly1305_blocks(void *ctx, const unsigned char *inp,
++#                             size_t len, u32 padbit)
+ {
+ my ($d0hi,$d0lo,$d1hi,$d1lo,$t0,$h0,$t1,$h1,$h2) = map("%r$_",(6..14));
+ my ($r0,$r1,$s1) = map("%r$_",(0..2));
+ 
+-$code.=<<___;
+-.globl	poly1305_blocks
+-.type	poly1305_blocks,\@function
+-.align	16
+-poly1305_blocks:
+-	srl${g}	$len,4			# fixed-up in 64-bit build
+-	lghi	%r0,0
+-	cl${g}r	$len,%r0
+-	je	.Lno_data
+-
+-	stm${g}	%r6,%r14,`6*$SIZE_T`($sp)
+-
+-	llgfr   $padbit,$padbit		# clear upper half, much needed with
+-					# non-64-bit ABI
+-	lg	$r0,32($ctx)		# load key
+-	lg	$r1,40($ctx)
+-
+-	lg	$h0,0($ctx)		# load hash value
+-	lg	$h1,8($ctx)
+-	lg	$h2,16($ctx)
+-
+-	st$g	$ctx,`2*$SIZE_T`($sp)	# off-load $ctx
+-	srlg	$s1,$r1,2
+-	algr	$s1,$r1			# s1 = r1 + r1>>2
+-	j	.Loop
+-
+-.align	16
+-.Loop:
+-	lrvg	$d0lo,0($inp)		# load little-endian input
+-	lrvg	$d1lo,8($inp)
+-	la	$inp,16($inp)
+-
+-	algr	$d0lo,$h0		# accumulate input
+-	alcgr	$d1lo,$h1
+-
+-	lgr	$h0,$d0lo
+-	mlgr	$d0hi,$r0		# h0*r0	  -> $d0hi:$d0lo
+-	lgr	$h1,$d1lo
+-	mlgr	$d1hi,$s1		# h1*5*r1 -> $d1hi:$d1lo
+-
+-	mlgr	$t0,$r1			# h0*r1   -> $t0:$h0
+-	mlgr	$t1,$r0			# h1*r0   -> $t1:$h1
+-	alcgr	$h2,$padbit
+-
+-	algr	$d0lo,$d1lo
+-	lgr	$d1lo,$h2
+-	alcgr	$d0hi,$d1hi
+-	lghi	$d1hi,0
+-
+-	algr	$h1,$h0
+-	alcgr	$t1,$t0
+-
+-	msgr	$d1lo,$s1		# h2*s1
+-	msgr	$h2,$r0			# h2*r0
+-
+-	algr	$h1,$d1lo
+-	alcgr	$t1,$d1hi		# $d1hi is zero
+-
+-	algr	$h1,$d0hi
+-	alcgr	$h2,$t1
+-
+-	lghi	$h0,-4			# final reduction step
+-	ngr	$h0,$h2
+-	srlg	$t0,$h2,2
+-	algr	$h0,$t0
+-	lghi	$t1,3
+-	ngr	$h2,$t1
+-
+-	algr	$h0,$d0lo
+-	alcgr	$h1,$d1hi		# $d1hi is still zero
+-	alcgr	$h2,$d1hi		# $d1hi is still zero
+-
+-	brct$g	$len,.Loop
+-
+-	l$g	$ctx,`2*$SIZE_T`($sp)	# restore $ctx
+-
+-	stg	$h0,0($ctx)		# store hash value
+-	stg	$h1,8($ctx)
+-	stg	$h2,16($ctx)
+-
+-	lm${g}	%r6,%r14,`6*$SIZE_T`($sp)
+-.Lno_data:
+-	br	%r14
+-.size	poly1305_blocks,.-poly1305_blocks
+-___
++GLOBL	("poly1305_blocks");
++TYPE	("poly1305_blocks","\@function");
++ALIGN	(16);
++LABEL	("poly1305_blocks");
++LABEL	(".Lpoly1305_blocks");
++&{$z?	\&ltgr:\&ltr}	("%r0",$len);
++	jz	(".Lno_data");
++
++&{$z?	\&stmg:\&stm}	("%r6","%r14","6*$SIZE_T($sp)");
++
++	lg	($h0,"0($ctx)");		# load hash value
++	lg	($h1,"8($ctx)");
++	lg	($h2,"16($ctx)");
++
++LABEL	(".Lpoly1305_blocks_entry");
++if ($z) {
++	srlg	($len,$len,4);
++} else {
++	srl	($len,4);
++}
++	llgfr   ($padbit,$padbit);		# clear upper half, much needed with
++						# non-64-bit ABI
++	lg	($r0,"32($ctx)");		# load key
++	lg	($r1,"40($ctx)");
++
++&{$z?	\&stg:\&st}	($ctx,"2*$SIZE_T($sp)");	# off-load $ctx
++	srlg	($s1,$r1,2);
++	algr	($s1,$r1);			# s1 = r1 + r1>>2
++	j	(".Loop");
++
++ALIGN	(16);
++LABEL	(".Loop");
++	lrvg	($d0lo,"0($inp)");		# load little-endian input
++	lrvg	($d1lo,"8($inp)");
++	la	($inp,"16($inp)");
++
++	algr	($d0lo,$h0);			# accumulate input
++	alcgr	($d1lo,$h1);
++	alcgr	($h2,$padbit);
++
++	lgr	($h0,$d0lo);
++	mlgr	($d0hi,$r0);			# h0*r0	  -> $d0hi:$d0lo
++	lgr	($h1,$d1lo);
++	mlgr	($d1hi,$s1);			# h1*5*r1 -> $d1hi:$d1lo
++
++	mlgr	($t0,$r1);			# h0*r1   -> $t0:$h0
++	mlgr	($t1,$r0);			# h1*r0   -> $t1:$h1
++
++	algr	($d0lo,$d1lo);
++	lgr	($d1lo,$h2);
++	alcgr	($d0hi,$d1hi);
++	lghi	($d1hi,0);
++
++	algr	($h1,$h0);
++	alcgr	($t1,$t0);
++
++	msgr	($d1lo,$s1);			# h2*s1
++	msgr	($h2,$r0);			# h2*r0
++
++	algr	($h1,$d1lo);
++	alcgr	($t1,$d1hi);			# $d1hi is zero
++
++	algr	($h1,$d0hi);
++	alcgr	($h2,$t1);
++
++	lghi	($h0,-4);			# final reduction step
++	ngr	($h0,$h2);
++	srlg	($t0,$h2,2);
++	algr	($h0,$t0);
++	lghi	($t1,3);
++	ngr	($h2,$t1);
++
++	algr	($h0,$d0lo);
++	alcgr	($h1,$d1hi);			# $d1hi is still zero
++	alcgr	($h2,$d1hi);			# $d1hi is still zero
++
++&{$z?	\&brctg:\&brct}	($len,".Loop");
++
++&{$z?	\&lg:\&l}	($ctx,"2*$SIZE_T($sp)");# restore $ctx
++
++	stg	($h0,"0($ctx)");		# store hash value
++	stg	($h1,"8($ctx)");
++	stg	($h2,"16($ctx)");
++
++&{$z?	\&lmg:\&lm}	("%r6","%r14","6*$SIZE_T($sp)");
++LABEL	(".Lno_data");
++	br	("%r14");
++SIZE	("poly1305_blocks",".-poly1305_blocks");
+ }
++
++################
++# static void poly1305_blocks_vx(void *ctx, const unsigned char *inp,
++#                                size_t len, u32 padbit)
++{
++my ($H0, $H1, $H2, $H3, $H4) = map("%v$_",(0..4));
++my ($I0, $I1, $I2, $I3, $I4) = map("%v$_",(5..9));
++my ($R0, $R1, $S1, $R2, $S2) = map("%v$_",(10..14));
++my      ($R3, $S3, $R4, $S4) = map("%v$_",(15..18));
++my ($ACC0, $ACC1, $ACC2, $ACC3, $ACC4) = map("%v$_",(19..23));
++my      ($T1, $T2, $T3, $T4) = map("%v$_",(24..27));
++my ($mask26,$bswaplo,$bswaphi,$bswapmi) = map("%v$_",(28..31));
++
++my ($d2,$d0,$h0,$d1,$h1,$h2)=map("%r$_",(9..14));
++
++TYPE	("poly1305_blocks_vx","\@function");
++ALIGN	(16);
++LABEL	("poly1305_blocks_vx");
++LABEL	(".Lpoly1305_blocks_vx");
++&{$z?	\&clgfi:\&clfi} ($len,128);
++	jhe	("__poly1305_blocks_vx");
++
++&{$z?	\&stmg:\&stm}	("%r6","%r14","6*$SIZE_T($sp)");
++
++	lg	($d0,"0($ctx)");
++	lg	($d1,"8($ctx)");
++	lg	($d2,"16($ctx)");
++
++	llgfr	("%r0",$d0);			# base 2^26 -> base 2^64
++	srlg	($h0,$d0,32);
++	llgfr	("%r1",$d1);
++	srlg	($h1,$d1,32);
++	srlg	($h2,$d2,32);
++
++	sllg	("%r0","%r0",26);
++	algr	($h0,"%r0");
++	sllg	("%r0",$h1,52);
++	srlg	($h1,$h1,12);
++	sllg	("%r1","%r1",14);
++	algr	($h0,"%r0");
++	alcgr	($h1,"%r1");
++	sllg	("%r0",$h2,40);
++	srlg	($h2,$h2,24);
++	lghi	("%r1",0);
++	algr	($h1,"%r0");
++	alcgr	($h2,"%r1");
++
++	llgf	("%r0","24($ctx)");		# is_base2_26
++	lcgr	("%r0","%r0");
++
++	xgr	($h0,$d0);			# choose between radixes
++	xgr	($h1,$d1);
++	xgr	($h2,$d2);
++	ngr	($h0,"%r0");
++	ngr	($h1,"%r0");
++	ngr	($h2,"%r0");
++	xgr	($h0,$d0);
++	xgr	($h1,$d1);
++	xgr	($h2,$d2);
++
++	lhi	("%r0",0);
++	st	("%r0","24($ctx)");		# clear is_base2_26
++
++	j	(".Lpoly1305_blocks_entry");
++SIZE	("poly1305_blocks_vx",".-poly1305_blocks_vx");
++
++TYPE	("__poly1305_mul","\@function");
++ALIGN	(16);
++LABEL	("__poly1305_mul");
++	vmlof		($ACC0,$H0,$R0);
++	vmlof		($ACC1,$H0,$R1);
++	vmlof		($ACC2,$H0,$R2);
++	vmlof		($ACC3,$H0,$R3);
++	vmlof		($ACC4,$H0,$R4);
++
++	vmalof		($ACC0,$H1,$S4,$ACC0);
++	vmalof		($ACC1,$H1,$R0,$ACC1);
++	vmalof		($ACC2,$H1,$R1,$ACC2);
++	vmalof		($ACC3,$H1,$R2,$ACC3);
++	vmalof		($ACC4,$H1,$R3,$ACC4);
++
++	vmalof		($ACC0,$H2,$S3,$ACC0);
++	vmalof		($ACC1,$H2,$S4,$ACC1);
++	vmalof		($ACC2,$H2,$R0,$ACC2);
++	vmalof		($ACC3,$H2,$R1,$ACC3);
++	vmalof		($ACC4,$H2,$R2,$ACC4);
++
++	vmalof		($ACC0,$H3,$S2,$ACC0);
++	vmalof		($ACC1,$H3,$S3,$ACC1);
++	vmalof		($ACC2,$H3,$S4,$ACC2);
++	vmalof		($ACC3,$H3,$R0,$ACC3);
++	vmalof		($ACC4,$H3,$R1,$ACC4);
++
++	vmalof		($ACC0,$H4,$S1,$ACC0);
++	vmalof		($ACC1,$H4,$S2,$ACC1);
++	vmalof		($ACC2,$H4,$S3,$ACC2);
++	vmalof		($ACC3,$H4,$S4,$ACC3);
++	vmalof		($ACC4,$H4,$R0,$ACC4);
++
++	################################################################
++	# lazy reduction
++
++	vesrlg		($H4,$ACC3,26);
++	vesrlg		($H1,$ACC0,26);
++	vn		($H3,$ACC3,$mask26);
++	vn		($H0,$ACC0,$mask26);
++	vag		($H4,$H4,$ACC4);	# h3 -> h4
++	vag		($H1,$H1,$ACC1);	# h0 -> h1
++
++	vesrlg		($ACC4,$H4,26);
++	vesrlg		($ACC1,$H1,26);
++	vn		($H4,$H4,$mask26);
++	vn		($H1,$H1,$mask26);
++	vag		($H0,$H0,$ACC4);
++	vag		($H2,$ACC2,$ACC1);	# h1 -> h2
++
++	veslg		($ACC4,$ACC4,2);	# <<2
++	vesrlg		($ACC2,$H2,26);
++	vn		($H2,$H2,$mask26);
++	vag		($H0,$H0,$ACC4);	# h4 -> h0
++	vag		($H3,$H3,$ACC2);	# h2 -> h3
++
++	vesrlg		($ACC0,$H0,26);
++	vesrlg		($ACC3,$H3,26);
++	vn		($H0,$H0,$mask26);
++	vn		($H3,$H3,$mask26);
++	vag		($H1,$H1,$ACC0);	# h0 -> h1
++	vag		($H4,$H4,$ACC3);	# h3 -> h4
++	br		("%r14");
++SIZE	("__poly1305_mul",".-__poly1305_mul");
++
++TYPE	("__poly1305_blocks_vx","\@function");
++ALIGN	(16);
++LABEL	("__poly1305_blocks_vx");
++&{$z?	\&lgr:\&lr}	("%r0",$sp);
++&{$z?	\&stmg:\&stm}	("%r10","%r15","10*$SIZE_T($sp)");
++if (!$z) {
++	std	("%f4","16*$SIZE_T+2*8($sp)");
++	std	("%f6","16*$SIZE_T+3*8($sp)");
++	ahi	($sp,-$stdframe);
++	st	("%r0","0($sp)");		# back-chain
++
++	llgfr	($len,$len);			# so that srlg works on $len
++} else {
++	aghi	($sp,"-($stdframe+8*8)");
++	stg	("%r0","0($sp)");		# back-chain
++
++	std	("%f8","$stdframe+0*8($sp)");
++	std	("%f9","$stdframe+1*8($sp)");
++	std	("%f10","$stdframe+2*8($sp)");
++	std	("%f11","$stdframe+3*8($sp)");
++	std	("%f12","$stdframe+4*8($sp)");
++	std	("%f13","$stdframe+5*8($sp)");
++	std	("%f14","$stdframe+6*8($sp)");
++	std	("%f15","$stdframe+7*8($sp)");
++}
++	larl	("%r1",".Lconst");
++	vgmg	($mask26,38,63);
++	vlm	($bswaplo,$bswapmi,"16(%r1)");
++
++	&lt	("%r0","24($ctx)");		# is_base2_26?
++	jnz	(".Lskip_init");
++
++	lg	($h0,"32($ctx)");		# load key base 2^64
++	lg	($h1,"40($ctx)");
++
++	risbg	($d0,$h0,38,0x80+63,38);	# base 2^64 -> 2^26
++	srlg	($d1,$h0,52);
++	risbg	($h0,$h0,38,0x80+63,0);
++	vlvgg	($R0,$h0,0);
++	risbg	($d1,$h1,38,51,12);
++	vlvgg	($R1,$d0,0);
++	risbg	($d0,$h1,38,63,50);
++	vlvgg	($R2,$d1,0);
++	srlg	($d1,$h1,40);
++	vlvgg	($R3,$d0,0);
++	vlvgg	($R4,$d1,0);
++
++	veslg	($S1,$R1,2);
++	veslg	($S2,$R2,2);
++	veslg	($S3,$R3,2);
++	veslg	($S4,$R4,2);
++	vlr	($H0,$R0);
++	vlr	($H1,$R1);
++	vlr	($H2,$R2);
++	vlr	($H3,$R3);
++	vlr	($H4,$R4);
++	vag	($S1,$S1,$R1);			# * 5
++	vag	($S2,$S2,$R2);
++	vag	($S3,$S3,$R3);
++	vag	($S4,$S4,$R4);
++
++	brasl	("%r14","__poly1305_mul");	# r^1:- * r^1:-
++
++	vpdi	($R0,$H0,$R0,0);		# r^2:r^1
++	vpdi	($R1,$H1,$R1,0);
++	vpdi	($R2,$H2,$R2,0);
++	vpdi	($R3,$H3,$R3,0);
++	vpdi	($R4,$H4,$R4,0);
++	vpdi	($H0,$H0,$H0,0);		# r^2:r^2
++	vpdi	($H1,$H1,$H1,0);
++	vpdi	($H2,$H2,$H2,0);
++	vpdi	($H3,$H3,$H3,0);
++	vpdi	($H4,$H4,$H4,0);
++	veslg	($S1,$R1,2);
++	veslg	($S2,$R2,2);
++	veslg	($S3,$R3,2);
++	veslg	($S4,$R4,2);
++	vag	($S1,$S1,$R1);			# * 5
++	vag	($S2,$S2,$R2);
++	vag	($S3,$S3,$R3);
++	vag	($S4,$S4,$R4);
++
++	brasl	("%r14,__poly1305_mul");	# r^2:r^2 * r^2:r^1
++
++	vl	($I0,"0(%r1)");			# borrow $I0
++	vperm	($R0,$R0,$H0,$I0);		# r^2:r^4:r^1:r^3
++	vperm	($R1,$R1,$H1,$I0);
++	vperm	($R2,$R2,$H2,$I0);
++	vperm	($R3,$R3,$H3,$I0);
++	vperm	($R4,$R4,$H4,$I0);
++	veslf	($S1,$R1,2);
++	veslf	($S2,$R2,2);
++	veslf	($S3,$R3,2);
++	veslf	($S4,$R4,2);
++	vaf	($S1,$S1,$R1);			# * 5
++	vaf	($S2,$S2,$R2);
++	vaf	($S3,$S3,$R3);
++	vaf	($S4,$S4,$R4);
++
++	lg	($h0,"0($ctx)");		# load hash base 2^64
++	lg	($h1,"8($ctx)");
++	lg	($h2,"16($ctx)");
++
++	vzero	($H0);
++	vzero	($H1);
++	vzero	($H2);
++	vzero	($H3);
++	vzero	($H4);
++
++	risbg	($d0,$h0,38,0x80+63,38);	# base 2^64 -> 2^26
++	srlg	($d1,$h0,52);
++	risbg	($h0,$h0,38,0x80+63,0);
++	vlvgg	($H0,$h0,0);
++	risbg	($d1,$h1,38,51,12);
++	vlvgg	($H1,$d0,0);
++	risbg	($d0,$h1,38,63,50);
++	vlvgg	($H2,$d1,0);
++	srlg	($d1,$h1,40);
++	vlvgg	($H3,$d0,0);
++	risbg	($d1,$h2,37,39,24);
++	vlvgg	($H4,$d1,0);
++
++	lhi	("%r0",1);
++	st	("%r0","24($ctx)");		# set is_base2_26
++
++	vstm	($R0,$S4,"48($ctx)");		# save key schedule base 2^26
++
++	vpdi	($R0,$R0,$R0,0);		# broadcast r^2:r^4
++	vpdi	($R1,$R1,$R1,0);
++	vpdi	($S1,$S1,$S1,0);
++	vpdi	($R2,$R2,$R2,0);
++	vpdi	($S2,$S2,$S2,0);
++	vpdi	($R3,$R3,$R3,0);
++	vpdi	($S3,$S3,$S3,0);
++	vpdi	($R4,$R4,$R4,0);
++	vpdi	($S4,$S4,$S4,0);
++
++	j	(".Loaded_hash");
++
++ALIGN	(16);
++LABEL	(".Lskip_init");
++	vllezf	($H0,"0($ctx)");		# load hash base 2^26
++	vllezf	($H1,"4($ctx)");
++	vllezf	($H2,"8($ctx)");
++	vllezf	($H3,"12($ctx)");
++	vllezf	($H4,"16($ctx)");
++
++	vlrepg	($R0,"0x30($ctx)");		# broadcast r^2:r^4
++	vlrepg	($R1,"0x40($ctx)");
++	vlrepg	($S1,"0x50($ctx)");
++	vlrepg	($R2,"0x60($ctx)");
++	vlrepg	($S2,"0x70($ctx)");
++	vlrepg	($R3,"0x80($ctx)");
++	vlrepg	($S3,"0x90($ctx)");
++	vlrepg	($R4,"0xa0($ctx)");
++	vlrepg	($S4,"0xb0($ctx)");
++
++LABEL	(".Loaded_hash");
++	vzero	($I1);
++	vzero	($I3);
++
++	vlm	($T1,$T4,"0x00($inp)");		# load first input block
++	la	($inp,"0x40($inp)");
++	vgmg	($mask26,6,31);
++	vgmf	($I4,5,5);			# padbit<<2
++
++	vperm	($I0,$T3,$T4,$bswaplo);
++	vperm	($I2,$T3,$T4,$bswapmi);
++	vperm	($T3,$T3,$T4,$bswaphi);
++
++	verimg	($I1,$I0,$mask26,6);		# >>26
++	veslg	($I0,$I0,32);
++	veslg	($I2,$I2,28);			# >>4
++	verimg	($I3,$T3,$mask26,18);		# >>14
++	verimg	($I4,$T3,$mask26,58);		# >>38
++	vn	($I0,$I0,$mask26);
++	vn	($I2,$I2,$mask26);
++	vesrlf	($I4,$I4,2);			# >>2
++
++	vgmg	($mask26,38,63);
++	vperm	($T3,$T1,$T2,$bswaplo);
++	vperm	($T4,$T1,$T2,$bswaphi);
++	vperm	($T2,$T1,$T2,$bswapmi);
++
++	verimg	($I0,$T3,$mask26,0);
++	verimg	($I1,$T3,$mask26,38);		# >>26
++	verimg	($I2,$T2,$mask26,60);		# >>4
++	verimg	($I3,$T4,$mask26,50);		# >>14
++	vesrlg	($T4,$T4,40);
++	vo	($I4,$I4,$T4);
++
++	srlg	("%r0",$len,6);
++&{$z?	\&aghi:\&ahi}	("%r0",-1);
++
++ALIGN	(16);
++LABEL	(".Loop_vx");
++	vmlef		($ACC0,$I0,$R0);
++	vmlef		($ACC1,$I0,$R1);
++	vmlef		($ACC2,$I0,$R2);
++	vmlef		($ACC3,$I0,$R3);
++	vmlef		($ACC4,$I0,$R4);
++
++	vmalef		($ACC0,$I1,$S4,$ACC0);
++	vmalef		($ACC1,$I1,$R0,$ACC1);
++	vmalef		($ACC2,$I1,$R1,$ACC2);
++	vmalef		($ACC3,$I1,$R2,$ACC3);
++	vmalef		($ACC4,$I1,$R3,$ACC4);
++
++	 vaf		($H2,$H2,$I2);
++	 vaf		($H0,$H0,$I0);
++	 vaf		($H3,$H3,$I3);
++	 vaf		($H1,$H1,$I1);
++	 vaf		($H4,$H4,$I4);
++
++	vmalef		($ACC0,$I2,$S3,$ACC0);
++	vmalef		($ACC1,$I2,$S4,$ACC1);
++	vmalef		($ACC2,$I2,$R0,$ACC2);
++	vmalef		($ACC3,$I2,$R1,$ACC3);
++	vmalef		($ACC4,$I2,$R2,$ACC4);
++
++	 vlm		($T1,$T4,"0x00($inp)");	# load next input block
++	 la		($inp,"0x40($inp)");
++	 vgmg		($mask26,6,31);
++
++	vmalef		($ACC0,$I3,$S2,$ACC0);
++	vmalef		($ACC1,$I3,$S3,$ACC1);
++	vmalef		($ACC2,$I3,$S4,$ACC2);
++	vmalef		($ACC3,$I3,$R0,$ACC3);
++	vmalef		($ACC4,$I3,$R1,$ACC4);
++
++	 vperm		($I0,$T3,$T4,$bswaplo);
++	 vperm		($I2,$T3,$T4,$bswapmi);
++	 vperm		($T3,$T3,$T4,$bswaphi);
++
++	vmalef		($ACC0,$I4,$S1,$ACC0);
++	vmalef		($ACC1,$I4,$S2,$ACC1);
++	vmalef		($ACC2,$I4,$S3,$ACC2);
++	vmalef		($ACC3,$I4,$S4,$ACC3);
++	vmalef		($ACC4,$I4,$R0,$ACC4);
++
++	 verimg		($I1,$I0,$mask26,6);	# >>26
++	 veslg		($I0,$I0,32);
++	 veslg		($I2,$I2,28);		# >>4
++	 verimg		($I3,$T3,$mask26,18);	# >>14
++
++	vmalof		($ACC0,$H0,$R0,$ACC0);
++	vmalof		($ACC1,$H0,$R1,$ACC1);
++	vmalof		($ACC2,$H0,$R2,$ACC2);
++	vmalof		($ACC3,$H0,$R3,$ACC3);
++	vmalof		($ACC4,$H0,$R4,$ACC4);
++
++	 vgmf		($I4,5,5);		# padbit<<2
++	 verimg		($I4,$T3,$mask26,58);	# >>38
++	 vn		($I0,$I0,$mask26);
++	 vn		($I2,$I2,$mask26);
++	 vesrlf		($I4,$I4,2);		# >>2
++
++	vmalof		($ACC0,$H1,$S4,$ACC0);
++	vmalof		($ACC1,$H1,$R0,$ACC1);
++	vmalof		($ACC2,$H1,$R1,$ACC2);
++	vmalof		($ACC3,$H1,$R2,$ACC3);
++	vmalof		($ACC4,$H1,$R3,$ACC4);
++
++	 vgmg		($mask26,38,63);
++	 vperm		($T3,$T1,$T2,$bswaplo);
++	 vperm		($T4,$T1,$T2,$bswaphi);
++	 vperm		($T2,$T1,$T2,$bswapmi);
++
++	vmalof		($ACC0,$H2,$S3,$ACC0);
++	vmalof		($ACC1,$H2,$S4,$ACC1);
++	vmalof		($ACC2,$H2,$R0,$ACC2);
++	vmalof		($ACC3,$H2,$R1,$ACC3);
++	vmalof		($ACC4,$H2,$R2,$ACC4);
++
++	 verimg		($I0,$T3,$mask26,0);
++	 verimg		($I1,$T3,$mask26,38);	# >>26
++	 verimg		($I2,$T2,$mask26,60);	# >>4
++
++	vmalof		($ACC0,$H3,$S2,$ACC0);
++	vmalof		($ACC1,$H3,$S3,$ACC1);
++	vmalof		($ACC2,$H3,$S4,$ACC2);
++	vmalof		($ACC3,$H3,$R0,$ACC3);
++	vmalof		($ACC4,$H3,$R1,$ACC4);
++
++	 verimg		($I3,$T4,$mask26,50);	# >>14
++	 vesrlg		($T4,$T4,40);
++	 vo		($I4,$I4,$T4);
++
++	vmalof		($ACC0,$H4,$S1,$ACC0);
++	vmalof		($ACC1,$H4,$S2,$ACC1);
++	vmalof		($ACC2,$H4,$S3,$ACC2);
++	vmalof		($ACC3,$H4,$S4,$ACC3);
++	vmalof		($ACC4,$H4,$R0,$ACC4);
++
++	################################################################
++	# lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	# and P. Schwabe
++
++	vesrlg		($H4,$ACC3,26);
++	vesrlg		($H1,$ACC0,26);
++	vn		($H3,$ACC3,$mask26);
++	vn		($H0,$ACC0,$mask26);
++	vag		($H4,$H4,$ACC4);	# h3 -> h4
++	vag		($H1,$H1,$ACC1);	# h0 -> h1
++
++	vesrlg		($ACC4,$H4,26);
++	vesrlg		($ACC1,$H1,26);
++	vn		($H4,$H4,$mask26);
++	vn		($H1,$H1,$mask26);
++	vag		($H0,$H0,$ACC4);
++	vag		($H2,$ACC2,$ACC1);	# h1 -> h2
++
++	veslg		($ACC4,$ACC4,2);	# <<2
++	vesrlg		($ACC2,$H2,26);
++	vn		($H2,$H2,$mask26);
++	vag		($H0,$H0,$ACC4);	# h4 -> h0
++	vag		($H3,$H3,$ACC2);	# h2 -> h3
++
++	vesrlg		($ACC0,$H0,26);
++	vesrlg		($ACC3,$H3,26);
++	vn		($H0,$H0,$mask26);
++	vn		($H3,$H3,$mask26);
++	vag		($H1,$H1,$ACC0);	# h0 -> h1
++	vag		($H4,$H4,$ACC3);	# h3 -> h4
++
++&{$z?	\&brctg:\&brct}	("%r0",".Loop_vx");
++
++	vlm	($R0,$S4,"48($ctx)");		# load all powers
++
++	lghi	("%r0",0x30);
++&{$z?	\&lcgr:\&lcr}	($len,$len);
++&{$z?	\&ngr:\&nr}	($len,"%r0");
++&{$z?	\&slgr:\&slr}	($inp,$len);
++
++LABEL	(".Last");
++	vmlef	($ACC0,$I0,$R0);
++	vmlef	($ACC1,$I0,$R1);
++	vmlef	($ACC2,$I0,$R2);
++	vmlef	($ACC3,$I0,$R3);
++	vmlef	($ACC4,$I0,$R4);
++
++	vmalef	($ACC0,$I1,$S4,$ACC0);
++	vmalef	($ACC1,$I1,$R0,$ACC1);
++	vmalef	($ACC2,$I1,$R1,$ACC2);
++	vmalef	($ACC3,$I1,$R2,$ACC3);
++	vmalef	($ACC4,$I1,$R3,$ACC4);
++
++	 vaf	($H0,$H0,$I0);
++	 vaf	($H1,$H1,$I1);
++	 vaf	($H2,$H2,$I2);
++	 vaf	($H3,$H3,$I3);
++	 vaf	($H4,$H4,$I4);
++
++	vmalef	($ACC0,$I2,$S3,$ACC0);
++	vmalef	($ACC1,$I2,$S4,$ACC1);
++	vmalef	($ACC2,$I2,$R0,$ACC2);
++	vmalef	($ACC3,$I2,$R1,$ACC3);
++	vmalef	($ACC4,$I2,$R2,$ACC4);
++
++	vmalef	($ACC0,$I3,$S2,$ACC0);
++	vmalef	($ACC1,$I3,$S3,$ACC1);
++	vmalef	($ACC2,$I3,$S4,$ACC2);
++	vmalef	($ACC3,$I3,$R0,$ACC3);
++	vmalef	($ACC4,$I3,$R1,$ACC4);
++
++	vmalef	($ACC0,$I4,$S1,$ACC0);
++	vmalef	($ACC1,$I4,$S2,$ACC1);
++	vmalef	($ACC2,$I4,$S3,$ACC2);
++	vmalef	($ACC3,$I4,$S4,$ACC3);
++	vmalef	($ACC4,$I4,$R0,$ACC4);
++
++	vmalof	($ACC0,$H0,$R0,$ACC0);
++	vmalof	($ACC1,$H0,$R1,$ACC1);
++	vmalof	($ACC2,$H0,$R2,$ACC2);
++	vmalof	($ACC3,$H0,$R3,$ACC3);
++	vmalof	($ACC4,$H0,$R4,$ACC4);
++
++	vmalof	($ACC0,$H1,$S4,$ACC0);
++	vmalof	($ACC1,$H1,$R0,$ACC1);
++	vmalof	($ACC2,$H1,$R1,$ACC2);
++	vmalof	($ACC3,$H1,$R2,$ACC3);
++	vmalof	($ACC4,$H1,$R3,$ACC4);
++
++	vmalof	($ACC0,$H2,$S3,$ACC0);
++	vmalof	($ACC1,$H2,$S4,$ACC1);
++	vmalof	($ACC2,$H2,$R0,$ACC2);
++	vmalof	($ACC3,$H2,$R1,$ACC3);
++	vmalof	($ACC4,$H2,$R2,$ACC4);
++
++	vmalof	($ACC0,$H3,$S2,$ACC0);
++	vmalof	($ACC1,$H3,$S3,$ACC1);
++	vmalof	($ACC2,$H3,$S4,$ACC2);
++	vmalof	($ACC3,$H3,$R0,$ACC3);
++	vmalof	($ACC4,$H3,$R1,$ACC4);
++
++	vmalof	($ACC0,$H4,$S1,$ACC0);
++	vmalof	($ACC1,$H4,$S2,$ACC1);
++	vmalof	($ACC2,$H4,$S3,$ACC2);
++	vmalof	($ACC3,$H4,$S4,$ACC3);
++	vmalof	($ACC4,$H4,$R0,$ACC4);
++
++	################################################################
++	# horizontal addition
++
++	vzero	($H0);
++	vsumqg	($ACC0,$ACC0,$H0);
++	vsumqg	($ACC1,$ACC1,$H0);
++	vsumqg	($ACC2,$ACC2,$H0);
++	vsumqg	($ACC3,$ACC3,$H0);
++	vsumqg	($ACC4,$ACC4,$H0);
++
++	################################################################
++	# lazy reduction
++
++	vesrlg	($H4,$ACC3,26);
++	vesrlg	($H1,$ACC0,26);
++	vn	($H3,$ACC3,$mask26);
++	vn	($H0,$ACC0,$mask26);
++	vag	($H4,$H4,$ACC4);		# h3 -> h4
++	vag	($H1,$H1,$ACC1);		# h0 -> h1
++
++	vesrlg	($ACC4,$H4,26);
++	vesrlg	($ACC1,$H1,26);
++	vn	($H4,$H4,$mask26);
++	vn	($H1,$H1,$mask26);
++	vag	($H0,$H0,$ACC4);
++	vag	($H2,$ACC2,$ACC1);		# h1 -> h2
++
++	veslg	($ACC4,$ACC4,2);		# <<2
++	vesrlg	($ACC2,$H2,26);
++	vn	($H2,$H2,$mask26);
++	vag	($H0,$H0,$ACC4);		# h4 -> h0
++	vag	($H3,$H3,$ACC2);		# h2 -> h3
++
++	vesrlg	($ACC0,$H0,26);
++	vesrlg	($ACC3,$H3,26);
++	vn	($H0,$H0,$mask26);
++	vn	($H3,$H3,$mask26);
++	vag	($H1,$H1,$ACC0);		# h0 -> h1
++	vag	($H4,$H4,$ACC3);		# h3 -> h4
++
++&{$z?	\&clgfi:\&clfi} ($len,0);
++	je	(".Ldone");
++
++	vlm	($T1,$T4,"0x00($inp)");		# load last partial block
++	vgmg	($mask26,6,31);
++	vgmf	($I4,5,5);			# padbit<<2
++
++	vperm	($I0,$T3,$T4,$bswaplo);
++	vperm	($I2,$T3,$T4,$bswapmi);
++	vperm	($T3,$T3,$T4,$bswaphi);
++
++	vl	($ACC0,"0x30($len,%r1)");	# borrow $ACC0,1
++	vl	($ACC1,"0x60($len,%r1)");
++
++	verimg	($I1,$I0,$mask26,6);		# >>26
++	veslg	($I0,$I0,32);
++	veslg	($I2,$I2,28);			# >>4
++	verimg	($I3,$T3,$mask26,18);		# >>14
++	verimg	($I4,$T3,$mask26,58);		# >>38
++	vn	($I0,$I0,$mask26);
++	vn	($I2,$I2,$mask26);
++	vesrlf	($I4,$I4,2);			# >>2
++
++	vgmg	($mask26,38,63);
++	vperm	($T3,$T1,$T2,$bswaplo);
++	vperm	($T4,$T1,$T2,$bswaphi);
++	vperm	($T2,$T1,$T2,$bswapmi);
++
++	verimg	($I0,$T3,$mask26,0);
++	verimg	($I1,$T3,$mask26,38);		# >>26
++	verimg	($I2,$T2,$mask26,60);		# >>4
++	verimg	($I3,$T4,$mask26,50);		# >>14
++	vesrlg	($T4,$T4,40);
++	vo	($I4,$I4,$T4);
++
++	vperm	($H0,$H0,$H0,$ACC0);		# move hash to right lane
++	vn	($I0,$I0,$ACC1);		# mask redundant lane[s]
++	vperm	($H1,$H1,$H1,$ACC0);
++	vn	($I1,$I1,$ACC1);
++	vperm	($H2,$H2,$H2,$ACC0);
++	vn	($I2,$I2,$ACC1);
++	vperm	($H3,$H3,$H3,$ACC0);
++	vn	($I3,$I3,$ACC1);
++	vperm	($H4,$H4,$H4,$ACC0);
++	vn	($I4,$I4,$ACC1);
++
++	vaf	($I0,$I0,$H0);			# accumulate hash
++	vzero	($H0);				# wipe hash value
++	vaf	($I1,$I1,$H1);
++	vzero	($H1);
++	vaf	($I2,$I2,$H2);
++	vzero	($H2);
++	vaf	($I3,$I3,$H3);
++	vzero	($H3);
++	vaf	($I4,$I4,$H4);
++	vzero	($H4);
++
++&{$z?	\&lghi:\&lhi}	($len,0);
++	j	(".Last");
++	# I don't bother to tell apart cases when only one multiplication
++	# pass is sufficient, because I argue that mispredicted branch
++	# penalties are comparable to overhead of sometimes redundant
++	# multiplication pass...
++
++LABEL	(".Ldone");
++	vstef	($H0,"0($ctx)",3);		# store hash base 2^26
++	vstef	($H1,"4($ctx)",3);
++	vstef	($H2,"8($ctx)",3);
++	vstef	($H3,"12($ctx)",3);
++	vstef	($H4,"16($ctx)",3);
++
++if ($z) {
++	ld	("%f8","$stdframe+0*8($sp)");
++	ld	("%f9","$stdframe+1*8($sp)");
++	ld	("%f10","$stdframe+2*8($sp)");
++	ld	("%f11","$stdframe+3*8($sp)");
++	ld	("%f12","$stdframe+4*8($sp)");
++	ld	("%f13","$stdframe+5*8($sp)");
++	ld	("%f14","$stdframe+6*8($sp)");
++	ld	("%f15","$stdframe+7*8($sp)");
++&{$z?	\&lmg:\&lm}	("%r10","%r15","$stdframe+8*8+10*$SIZE_T($sp)");
++} else {
++	ld	("%f4","$stdframe+16*$SIZE_T+2*8($sp)");
++	ld	("%f6","$stdframe+16*$SIZE_T+3*8($sp)");
++&{$z?	\&lmg:\&lm}	("%r10","%r15","$stdframe+10*$SIZE_T($sp)");
++}
++	br	("%r14");
++SIZE	("__poly1305_blocks_vx",".-__poly1305_blocks_vx");
++}
++
++################
++# static void poly1305_emit(void *ctx, unsigned char mac[16],
++#                           const u32 nonce[4])
+ {
+ my ($mac,$nonce)=($inp,$len);
+-my ($h0,$h1,$h2,$d0,$d1)=map("%r$_",(5..9));
++my ($h0,$h1,$h2,$d0,$d1,$d2)=map("%r$_",(5..10));
+ 
+-$code.=<<___;
+-.globl	poly1305_emit
+-.type	poly1305_emit,\@function
+-.align	16
+-poly1305_emit:
+-	stm${g}	%r6,%r9,`6*$SIZE_T`($sp)
+-
+-	lg	$h0,0($ctx)
+-	lg	$h1,8($ctx)
+-	lg	$h2,16($ctx)
+-
+-	lghi	%r0,5
+-	lghi	%r1,0
+-	lgr	$d0,$h0
+-	lgr	$d1,$h1
+-
+-	algr	$h0,%r0			# compare to modulus
+-	alcgr	$h1,%r1
+-	alcgr	$h2,%r1
+-
+-	srlg	$h2,$h2,2		# did it borrow/carry?
+-	slgr	%r1,$h2			# 0-$h2>>2
+-	lg	$h2,0($nonce)		# load nonce
+-	lghi	%r0,-1
+-	lg	$ctx,8($nonce)
+-	xgr	%r0,%r1			# ~%r1
+-
+-	ngr	$h0,%r1
+-	ngr	$d0,%r0
+-	ngr	$h1,%r1
+-	ngr	$d1,%r0
+-	ogr	$h0,$d0
+-	rllg	$d0,$h2,32		# flip nonce words
+-	ogr	$h1,$d1
+-	rllg	$d1,$ctx,32
+-
+-	algr	$h0,$d0			# accumulate nonce
+-	alcgr	$h1,$d1
+-
+-	strvg	$h0,0($mac)		# write little-endian result
+-	strvg	$h1,8($mac)
+-
+-	lm${g}	%r6,%r9,`6*$SIZE_T`($sp)
+-	br	%r14
+-.size	poly1305_emit,.-poly1305_emit
+-
+-.string	"Poly1305 for s390x, CRYPTOGAMS by <appro\@openssl.org>"
+-___
++GLOBL	("poly1305_emit");
++TYPE	("poly1305_emit","\@function");
++ALIGN	(16);
++LABEL	("poly1305_emit");
++LABEL	(".Lpoly1305_emit");
++&{$z?	\&stmg:\&stm}	("%r6","%r10","6*$SIZE_T($sp)");
++
++	lg	($d0,"0($ctx)");
++	lg	($d1,"8($ctx)");
++	lg	($d2,"16($ctx)");
++
++	llgfr	("%r0",$d0);			# base 2^26 -> base 2^64
++	srlg	($h0,$d0,32);
++	llgfr	("%r1",$d1);
++	srlg	($h1,$d1,32);
++	srlg	($h2,$d2,32);
++
++	sllg	("%r0","%r0",26);
++	algr	($h0,"%r0");
++	sllg	("%r0",$h1,52);
++	srlg	($h1,$h1,12);
++	sllg	("%r1","%r1",14);
++	algr	($h0,"%r0");
++	alcgr	($h1,"%r1");
++	sllg	("%r0",$h2,40);
++	srlg	($h2,$h2,24);
++	lghi	("%r1",0);
++	algr	($h1,"%r0");
++	alcgr	($h2,"%r1");
++
++	llgf	("%r0","24($ctx)");		# is_base2_26
++	lcgr	("%r0","%r0");
++
++	xgr	($h0,$d0);			# choose between radixes
++	xgr	($h1,$d1);
++	xgr	($h2,$d2);
++	ngr	($h0,"%r0");
++	ngr	($h1,"%r0");
++	ngr	($h2,"%r0");
++	xgr	($h0,$d0);
++	xgr	($h1,$d1);
++	xgr	($h2,$d2);
++
++	lghi	("%r0",5);
++	lgr	($d0,$h0);
++	lgr	($d1,$h1);
++
++	algr	($h0,"%r0");			# compare to modulus
++	alcgr	($h1,"%r1");
++	alcgr	($h2,"%r1");
++
++	srlg	($h2,$h2,2);			# did it borrow/carry?
++	slgr	("%r1",$h2);				# 0-$h2>>2
++	lg	($d2,"0($nonce)");		# load nonce
++	lg	($ctx,"8($nonce)");
++
++	xgr	($h0,$d0);
++	xgr	($h1,$d1);
++	ngr	($h0,"%r1");
++	ngr	($h1,"%r1");
++	xgr	($h0,$d0);
++	rllg	($d0,$d2,32);			# flip nonce words
++	xgr	($h1,$d1);
++	rllg	($d1,$ctx,32);
++
++	algr	($h0,$d0);			# accumulate nonce
++	alcgr	($h1,$d1);
++
++	strvg	($h0,"0($mac)");		# write little-endian result
++	strvg	($h1,"8($mac)");
++
++&{$z?	\&lmg:\&lm}	("%r6","%r10","6*$SIZE_T($sp)");
++	br	("%r14");
++SIZE	("poly1305_emit",".-poly1305_emit");
+ }
+ 
+-$code =~ s/\`([^\`]*)\`/eval $1/gem;
+-$code =~ s/\b(srlg\s+)(%r[0-9]+\s*,)\s*([0-9]+)/$1$2$2$3/gm;
++################
++
++ALIGN	(16);
++LABEL	(".Lconst");
++LONG	(0x04050607,0x14151617,0x0c0d0e0f,0x1c1d1e1f);	# merge odd
++LONG	(0x07060504,0x03020100,0x17161514,0x13121110);	# byte swap masks
++LONG	(0x0f0e0d0c,0x0b0a0908,0x1f1e1d1c,0x1b1a1918);
++LONG	(0x00000000,0x09080706,0x00000000,0x19181716);
++
++LONG	(0x00000000,0x00000000,0x00000000,0x0c0d0e0f);	# magic tail masks
++LONG	(0x0c0d0e0f,0x00000000,0x00000000,0x00000000);
++LONG	(0x00000000,0x00000000,0x0c0d0e0f,0x00000000);
++
++LONG	(0xffffffff,0x00000000,0xffffffff,0xffffffff);
++LONG	(0xffffffff,0x00000000,0xffffffff,0x00000000);
++LONG	(0x00000000,0x00000000,0xffffffff,0x00000000);
++
++STRING	("\"Poly1305 for s390x, CRYPTOGAMS by <appro\@openssl.org>\"");
+ 
+-print $code;
+-close STDOUT;
++PERLASM_END();
+diff -up openssl-1.1.1b/crypto/poly1305/build.info.s390x-update openssl-1.1.1b/crypto/poly1305/build.info
+--- openssl-1.1.1b/crypto/poly1305/build.info.s390x-update	2019-05-06 10:54:00.036367588 +0200
++++ openssl-1.1.1b/crypto/poly1305/build.info	2019-05-06 10:56:14.964105164 +0200
+@@ -18,6 +18,7 @@ INCLUDE[poly1305-armv8.o]=..
+ GENERATE[poly1305-mips.S]=asm/poly1305-mips.pl $(PERLASM_SCHEME)
+ INCLUDE[poly1305-mips.o]=..
+ GENERATE[poly1305-s390x.S]=asm/poly1305-s390x.pl $(PERLASM_SCHEME)
++INCLUDE[poly1305-s390x.o]=..
+ 
+ BEGINRAW[Makefile(unix)]
+ {- $builddir -}/poly1305-%.S:	{- $sourcedir -}/asm/poly1305-%.pl

diff --git a/openssl.spec b/openssl.spec
index 5c0c014..2e3cbdb 100644
--- a/openssl.spec
+++ b/openssl.spec
@@ -22,7 +22,7 @@
 Summary: Utilities from the general purpose cryptography library with TLS implementation
 Name: openssl
 Version: 1.1.1b
-Release: 6%{?dist}
+Release: 7%{?dist}
 Epoch: 1
 # We have to remove certain patented algorithms from the openssl source
 # tarball with the hobble-openssl script which is included below.
@@ -63,6 +63,7 @@ Patch49: openssl-1.1.1-evp-kdf.patch
 Patch50: openssl-1.1.1-ssh-kdf.patch
 # Backported fixes including security fixes
 Patch51: openssl-1.1.1-upstream-sync.patch
+Patch52: openssl-1.1.1-s390x-update.patch
 
 License: OpenSSL
 URL: http://www.openssl.org/
@@ -160,6 +161,7 @@ cp %{SOURCE13} test/
 %patch49 -p1 -b .evp-kdf
 %patch50 -p1 -b .ssh-kdf
 %patch51 -p1 -b .upstream-sync
+%patch52 -p1 -b .s390x-update
 
 
 %build
@@ -446,6 +448,9 @@ export LD_LIBRARY_PATH
 %ldconfig_scriptlets libs
 
 %changelog
+* Mon May  6 2019 Tomáš Mráz <tmraz@redhat.com> 1.1.1b-7
+- add S390x chacha20-poly1305 assembler support from master branch
+
 * Fri May  3 2019 Tomáš Mráz <tmraz@redhat.com> 1.1.1b-6
 - apply new bugfixes from upstream 1.1.1 branch
 

                 reply	other threads:[~2026-06-09 12:44 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178100906903.1.12836358596486699200.rpms-openssl-569a3cb91727@fedoraproject.org \
    --to=tmraz@fedoraproject.org \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox