Blame crypto/bn/asm/ppc64-mont.pl

Packit c4476c
#! /usr/bin/env perl
Packit c4476c
# Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
Packit c4476c
#
Packit c4476c
# Licensed under the OpenSSL license (the "License").  You may not use
Packit c4476c
# this file except in compliance with the License.  You can obtain a copy
Packit c4476c
# in the file LICENSE in the source distribution or at
Packit c4476c
# https://www.openssl.org/source/license.html
Packit c4476c
Packit c4476c
Packit c4476c
# ====================================================================
Packit c4476c
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
Packit c4476c
# project. The module is, however, dual licensed under OpenSSL and
Packit c4476c
# CRYPTOGAMS licenses depending on where you obtain it. For further
Packit c4476c
# details see http://www.openssl.org/~appro/cryptogams/.
Packit c4476c
# ====================================================================
Packit c4476c
Packit c4476c
# December 2007
Packit c4476c
Packit c4476c
# The reason for undertaken effort is basically following. Even though
Packit c4476c
# Power 6 CPU operates at incredible 4.7GHz clock frequency, its PKI
Packit c4476c
# performance was observed to be less than impressive, essentially as
Packit c4476c
# fast as 1.8GHz PPC970, or 2.6 times(!) slower than one would hope.
Packit c4476c
# Well, it's not surprising that IBM had to make some sacrifices to
Packit c4476c
# boost the clock frequency that much, but no overall improvement?
Packit c4476c
# Having observed how much difference did switching to FPU make on
Packit c4476c
# UltraSPARC, playing same stunt on Power 6 appeared appropriate...
Packit c4476c
# Unfortunately the resulting performance improvement is not as
Packit c4476c
# impressive, ~30%, and in absolute terms is still very far from what
Packit c4476c
# one would expect from 4.7GHz CPU. There is a chance that I'm doing
Packit c4476c
# something wrong, but in the lack of assembler level micro-profiling
Packit c4476c
# data or at least decent platform guide I can't tell... Or better
Packit c4476c
# results might be achieved with VMX... Anyway, this module provides
Packit c4476c
# *worse* performance on other PowerPC implementations, ~40-15% slower
Packit c4476c
# on PPC970 depending on key length and ~40% slower on Power 5 for all
Packit c4476c
# key lengths. As it's obviously inappropriate as "best all-round"
Packit c4476c
# alternative, it has to be complemented with run-time CPU family
Packit c4476c
# detection. Oh! It should also be noted that unlike other PowerPC
Packit c4476c
# implementation IALU ppc-mont.pl module performs *suboptimally* on
Packit c4476c
# >=1024-bit key lengths on Power 6. It should also be noted that
Packit c4476c
# *everything* said so far applies to 64-bit builds! As far as 32-bit
Packit c4476c
# application executed on 64-bit CPU goes, this module is likely to
Packit c4476c
# become preferred choice, because it's easy to adapt it for such
Packit c4476c
# case and *is* faster than 32-bit ppc-mont.pl on *all* processors.
Packit c4476c
Packit c4476c
# February 2008
Packit c4476c
Packit c4476c
# Micro-profiling assisted optimization results in ~15% improvement
Packit c4476c
# over original ppc64-mont.pl version, or overall ~50% improvement
Packit c4476c
# over ppc.pl module on Power 6. If compared to ppc-mont.pl on same
Packit c4476c
# Power 6 CPU, this module is 5-150% faster depending on key length,
Packit c4476c
# [hereafter] more for longer keys. But if compared to ppc-mont.pl
Packit c4476c
# on 1.8GHz PPC970, it's only 5-55% faster. Still far from impressive
Packit c4476c
# in absolute terms, but it's apparently the way Power 6 is...
Packit c4476c
Packit c4476c
# December 2009
Packit c4476c
Packit c4476c
# Adapted for 32-bit build this module delivers 25-120%, yes, more
Packit c4476c
# than *twice* for longer keys, performance improvement over 32-bit
Packit c4476c
# ppc-mont.pl on 1.8GHz PPC970. However! This implementation utilizes
Packit c4476c
# even 64-bit integer operations and the trouble is that most PPC
Packit c4476c
# operating systems don't preserve upper halves of general purpose
Packit c4476c
# registers upon 32-bit signal delivery. They do preserve them upon
Packit c4476c
# context switch, but not signalling:-( This means that asynchronous
Packit c4476c
# signals have to be blocked upon entry to this subroutine. Signal
Packit c4476c
# masking (and of course complementary unmasking) has quite an impact
Packit c4476c
# on performance, naturally larger for shorter keys. It's so severe
Packit c4476c
# that 512-bit key performance can be as low as 1/3 of expected one.
Packit c4476c
# This is why this routine can be engaged for longer key operations
Packit c4476c
# only on these OSes, see crypto/ppccap.c for further details. MacOS X
Packit c4476c
# is an exception from this and doesn't require signal masking, and
Packit c4476c
# that's where above improvement coefficients were collected. For
Packit c4476c
# others alternative would be to break dependence on upper halves of
Packit c4476c
# GPRs by sticking to 32-bit integer operations...
Packit c4476c
Packit c4476c
# December 2012
Packit c4476c
Packit c4476c
# Remove above mentioned dependence on GPRs' upper halves in 32-bit
Packit c4476c
# build. No signal masking overhead, but integer instructions are
Packit c4476c
# *more* numerous... It's still "universally" faster than 32-bit
Packit c4476c
# ppc-mont.pl, but improvement coefficient is not as impressive
Packit c4476c
# for longer keys...
Packit c4476c
Packit c4476c
$flavour = shift;
Packit c4476c
Packit c4476c
if ($flavour =~ /32/) {
Packit c4476c
	$SIZE_T=4;
Packit c4476c
	$RZONE=	224;
Packit c4476c
	$fname=	"bn_mul_mont_fpu64";
Packit c4476c
Packit c4476c
	$STUX=	"stwux";	# store indexed and update
Packit c4476c
	$PUSH=	"stw";
Packit c4476c
	$POP=	"lwz";
Packit c4476c
} elsif ($flavour =~ /64/) {
Packit c4476c
	$SIZE_T=8;
Packit c4476c
	$RZONE=	288;
Packit c4476c
	$fname=	"bn_mul_mont_fpu64";
Packit c4476c
Packit c4476c
	# same as above, but 64-bit mnemonics...
Packit c4476c
	$STUX=	"stdux";	# store indexed and update
Packit c4476c
	$PUSH=	"std";
Packit c4476c
	$POP=	"ld";
Packit c4476c
} else { die "nonsense $flavour"; }
Packit c4476c
Packit c4476c
$LITTLE_ENDIAN = ($flavour=~/le$/) ? 4 : 0;
Packit c4476c
Packit c4476c
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
Packit c4476c
( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
Packit c4476c
( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
Packit c4476c
die "can't locate ppc-xlate.pl";
Packit c4476c
Packit c4476c
open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
Packit c4476c
Packit c4476c
$FRAME=64;	# padded frame header
Packit c4476c
$TRANSFER=16*8;
Packit c4476c
Packit c4476c
$carry="r0";
Packit c4476c
$sp="r1";
Packit c4476c
$toc="r2";
Packit c4476c
$rp="r3";	$ovf="r3";
Packit c4476c
$ap="r4";
Packit c4476c
$bp="r5";
Packit c4476c
$np="r6";
Packit c4476c
$n0="r7";
Packit c4476c
$num="r8";
Packit c4476c
$rp="r9";	# $rp is reassigned
Packit c4476c
$tp="r10";
Packit c4476c
$j="r11";
Packit c4476c
$i="r12";
Packit c4476c
# non-volatile registers
Packit c4476c
$c1="r19";
Packit c4476c
$n1="r20";
Packit c4476c
$a1="r21";
Packit c4476c
$nap_d="r22";	# interleaved ap and np in double format
Packit c4476c
$a0="r23";	# ap[0]
Packit c4476c
$t0="r24";	# temporary registers
Packit c4476c
$t1="r25";
Packit c4476c
$t2="r26";
Packit c4476c
$t3="r27";
Packit c4476c
$t4="r28";
Packit c4476c
$t5="r29";
Packit c4476c
$t6="r30";
Packit c4476c
$t7="r31";
Packit c4476c
Packit c4476c
# PPC offers enough register bank capacity to unroll inner loops twice
Packit c4476c
#
Packit c4476c
#     ..A3A2A1A0
Packit c4476c
#           dcba
Packit c4476c
#    -----------
Packit c4476c
#            A0a
Packit c4476c
#           A0b
Packit c4476c
#          A0c
Packit c4476c
#         A0d
Packit c4476c
#          A1a
Packit c4476c
#         A1b
Packit c4476c
#        A1c
Packit c4476c
#       A1d
Packit c4476c
#        A2a
Packit c4476c
#       A2b
Packit c4476c
#      A2c
Packit c4476c
#     A2d
Packit c4476c
#      A3a
Packit c4476c
#     A3b
Packit c4476c
#    A3c
Packit c4476c
#   A3d
Packit c4476c
#    ..a
Packit c4476c
#   ..b
Packit c4476c
#
Packit c4476c
$ba="f0";	$bb="f1";	$bc="f2";	$bd="f3";
Packit c4476c
$na="f4";	$nb="f5";	$nc="f6";	$nd="f7";
Packit c4476c
$dota="f8";	$dotb="f9";
Packit c4476c
$A0="f10";	$A1="f11";	$A2="f12";	$A3="f13";
Packit c4476c
$N0="f20";	$N1="f21";	$N2="f22";	$N3="f23";
Packit c4476c
$T0a="f24";	$T0b="f25";
Packit c4476c
$T1a="f26";	$T1b="f27";
Packit c4476c
$T2a="f28";	$T2b="f29";
Packit c4476c
$T3a="f30";	$T3b="f31";
Packit c4476c

Packit c4476c
# sp----------->+-------------------------------+
Packit c4476c
#		| saved sp			|
Packit c4476c
#		+-------------------------------+
Packit c4476c
#		.				.
Packit c4476c
#   +64		+-------------------------------+
Packit c4476c
#		| 16 gpr<->fpr transfer zone	|
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#   +16*8	+-------------------------------+
Packit c4476c
#		| __int64 tmp[-1]		|
Packit c4476c
#		+-------------------------------+
Packit c4476c
#		| __int64 tmp[num]		|
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#   +(num+1)*8	+-------------------------------+
Packit c4476c
#		| padding to 64 byte boundary	|
Packit c4476c
#		.				.
Packit c4476c
#   +X		+-------------------------------+
Packit c4476c
#		| double nap_d[4*num]		|
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#		+-------------------------------+
Packit c4476c
#		.				.
Packit c4476c
#   -13*size_t	+-------------------------------+
Packit c4476c
#		| 13 saved gpr, r19-r31		|
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#   -12*8	+-------------------------------+
Packit c4476c
#		| 12 saved fpr, f20-f31		|
Packit c4476c
#		.				.
Packit c4476c
#		.				.
Packit c4476c
#		+-------------------------------+
Packit c4476c

Packit c4476c
$code=<<___;
Packit c4476c
.machine "any"
Packit c4476c
.text
Packit c4476c
Packit c4476c
.globl	.$fname
Packit c4476c
.align	5
Packit c4476c
.$fname:
Packit c4476c
	cmpwi	$num,`3*8/$SIZE_T`
Packit c4476c
	mr	$rp,r3		; $rp is reassigned
Packit c4476c
	li	r3,0		; possible "not handled" return code
Packit c4476c
	bltlr-
Packit c4476c
	andi.	r0,$num,`16/$SIZE_T-1`		; $num has to be "even"
Packit c4476c
	bnelr-
Packit c4476c
Packit c4476c
	slwi	$num,$num,`log($SIZE_T)/log(2)`	; num*=sizeof(BN_LONG)
Packit c4476c
	li	$i,-4096
Packit c4476c
	slwi	$tp,$num,2	; place for {an}p_{lh}[num], i.e. 4*num
Packit c4476c
	add	$tp,$tp,$num	; place for tp[num+1]
Packit c4476c
	addi	$tp,$tp,`$FRAME+$TRANSFER+8+64+$RZONE`
Packit c4476c
	subf	$tp,$tp,$sp	; $sp-$tp
Packit c4476c
	and	$tp,$tp,$i	; minimize TLB usage
Packit c4476c
	subf	$tp,$sp,$tp	; $tp-$sp
Packit c4476c
	mr	$i,$sp
Packit c4476c
	$STUX	$sp,$sp,$tp	; alloca
Packit c4476c
Packit c4476c
	$PUSH	r19,`-12*8-13*$SIZE_T`($i)
Packit c4476c
	$PUSH	r20,`-12*8-12*$SIZE_T`($i)
Packit c4476c
	$PUSH	r21,`-12*8-11*$SIZE_T`($i)
Packit c4476c
	$PUSH	r22,`-12*8-10*$SIZE_T`($i)
Packit c4476c
	$PUSH	r23,`-12*8-9*$SIZE_T`($i)
Packit c4476c
	$PUSH	r24,`-12*8-8*$SIZE_T`($i)
Packit c4476c
	$PUSH	r25,`-12*8-7*$SIZE_T`($i)
Packit c4476c
	$PUSH	r26,`-12*8-6*$SIZE_T`($i)
Packit c4476c
	$PUSH	r27,`-12*8-5*$SIZE_T`($i)
Packit c4476c
	$PUSH	r28,`-12*8-4*$SIZE_T`($i)
Packit c4476c
	$PUSH	r29,`-12*8-3*$SIZE_T`($i)
Packit c4476c
	$PUSH	r30,`-12*8-2*$SIZE_T`($i)
Packit c4476c
	$PUSH	r31,`-12*8-1*$SIZE_T`($i)
Packit c4476c
	stfd	f20,`-12*8`($i)
Packit c4476c
	stfd	f21,`-11*8`($i)
Packit c4476c
	stfd	f22,`-10*8`($i)
Packit c4476c
	stfd	f23,`-9*8`($i)
Packit c4476c
	stfd	f24,`-8*8`($i)
Packit c4476c
	stfd	f25,`-7*8`($i)
Packit c4476c
	stfd	f26,`-6*8`($i)
Packit c4476c
	stfd	f27,`-5*8`($i)
Packit c4476c
	stfd	f28,`-4*8`($i)
Packit c4476c
	stfd	f29,`-3*8`($i)
Packit c4476c
	stfd	f30,`-2*8`($i)
Packit c4476c
	stfd	f31,`-1*8`($i)
Packit c4476c
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER+8+64`
Packit c4476c
	li	$i,-64
Packit c4476c
	add	$nap_d,$tp,$num
Packit c4476c
	and	$nap_d,$nap_d,$i	; align to 64 bytes
Packit c4476c
	; nap_d is off by 1, because it's used with stfdu/lfdu
Packit c4476c
	addi	$nap_d,$nap_d,-8
Packit c4476c
	srwi	$j,$num,`3+1`	; counter register, num/2
Packit c4476c
	addi	$j,$j,-1
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER-8`
Packit c4476c
	li	$carry,0
Packit c4476c
	mtctr	$j
Packit c4476c
___
Packit c4476c

Packit c4476c
$code.=<<___ if ($SIZE_T==8);
Packit c4476c
	ld	$a0,0($ap)		; pull ap[0] value
Packit c4476c
	ld	$t3,0($bp)		; bp[0]
Packit c4476c
	ld	$n0,0($n0)		; pull n0[0] value
Packit c4476c
Packit c4476c
	mulld	$t7,$a0,$t3		; ap[0]*bp[0]
Packit c4476c
	; transfer bp[0] to FPU as 4x16-bit values
Packit c4476c
	extrdi	$t0,$t3,16,48
Packit c4476c
	extrdi	$t1,$t3,16,32
Packit c4476c
	extrdi	$t2,$t3,16,16
Packit c4476c
	extrdi	$t3,$t3,16,0
Packit c4476c
	std	$t0,`$FRAME+0`($sp)
Packit c4476c
	std	$t1,`$FRAME+8`($sp)
Packit c4476c
	std	$t2,`$FRAME+16`($sp)
Packit c4476c
	std	$t3,`$FRAME+24`($sp)
Packit c4476c
Packit c4476c
	mulld	$t7,$t7,$n0		; tp[0]*n0
Packit c4476c
	; transfer (ap[0]*bp[0])*n0 to FPU as 4x16-bit values
Packit c4476c
	extrdi	$t4,$t7,16,48
Packit c4476c
	extrdi	$t5,$t7,16,32
Packit c4476c
	extrdi	$t6,$t7,16,16
Packit c4476c
	extrdi	$t7,$t7,16,0
Packit c4476c
	std	$t4,`$FRAME+32`($sp)
Packit c4476c
	std	$t5,`$FRAME+40`($sp)
Packit c4476c
	std	$t6,`$FRAME+48`($sp)
Packit c4476c
	std	$t7,`$FRAME+56`($sp)
Packit c4476c
Packit c4476c
	extrdi	$t0,$a0,32,32		; lwz	$t0,4($ap)
Packit c4476c
	extrdi	$t1,$a0,32,0		; lwz	$t1,0($ap)
Packit c4476c
	lwz	$t2,`12^$LITTLE_ENDIAN`($ap)	; load a[1] as 32-bit word pair
Packit c4476c
	lwz	$t3,`8^$LITTLE_ENDIAN`($ap)
Packit c4476c
	lwz	$t4,`4^$LITTLE_ENDIAN`($np)	; load n[0] as 32-bit word pair
Packit c4476c
	lwz	$t5,`0^$LITTLE_ENDIAN`($np)
Packit c4476c
	lwz	$t6,`12^$LITTLE_ENDIAN`($np)	; load n[1] as 32-bit word pair
Packit c4476c
	lwz	$t7,`8^$LITTLE_ENDIAN`($np)
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);
Packit c4476c
	lwz	$a0,0($ap)		; pull ap[0,1] value
Packit c4476c
	mr	$n1,$n0
Packit c4476c
	lwz	$a1,4($ap)
Packit c4476c
	li	$c1,0
Packit c4476c
	lwz	$t1,0($bp)		; bp[0,1]
Packit c4476c
	lwz	$t3,4($bp)
Packit c4476c
	lwz	$n0,0($n1)		; pull n0[0,1] value
Packit c4476c
	lwz	$n1,4($n1)
Packit c4476c
Packit c4476c
	mullw	$t4,$a0,$t1		; mulld ap[0]*bp[0]
Packit c4476c
	mulhwu	$t5,$a0,$t1
Packit c4476c
	mullw	$t6,$a1,$t1
Packit c4476c
	mullw	$t7,$a0,$t3
Packit c4476c
	add	$t5,$t5,$t6
Packit c4476c
	add	$t5,$t5,$t7
Packit c4476c
	; transfer bp[0] to FPU as 4x16-bit values
Packit c4476c
	extrwi	$t0,$t1,16,16
Packit c4476c
	extrwi	$t1,$t1,16,0
Packit c4476c
	extrwi	$t2,$t3,16,16
Packit c4476c
	extrwi	$t3,$t3,16,0
Packit c4476c
	std	$t0,`$FRAME+0`($sp)	; yes, std in 32-bit build
Packit c4476c
	std	$t1,`$FRAME+8`($sp)
Packit c4476c
	std	$t2,`$FRAME+16`($sp)
Packit c4476c
	std	$t3,`$FRAME+24`($sp)
Packit c4476c
Packit c4476c
	mullw	$t0,$t4,$n0		; mulld tp[0]*n0
Packit c4476c
	mulhwu	$t1,$t4,$n0
Packit c4476c
	mullw	$t2,$t5,$n0
Packit c4476c
	mullw	$t3,$t4,$n1
Packit c4476c
	add	$t1,$t1,$t2
Packit c4476c
	add	$t1,$t1,$t3
Packit c4476c
	; transfer (ap[0]*bp[0])*n0 to FPU as 4x16-bit values
Packit c4476c
	extrwi	$t4,$t0,16,16
Packit c4476c
	extrwi	$t5,$t0,16,0
Packit c4476c
	extrwi	$t6,$t1,16,16
Packit c4476c
	extrwi	$t7,$t1,16,0
Packit c4476c
	std	$t4,`$FRAME+32`($sp)	; yes, std in 32-bit build
Packit c4476c
	std	$t5,`$FRAME+40`($sp)
Packit c4476c
	std	$t6,`$FRAME+48`($sp)
Packit c4476c
	std	$t7,`$FRAME+56`($sp)
Packit c4476c
Packit c4476c
	mr	$t0,$a0			; lwz	$t0,0($ap)
Packit c4476c
	mr	$t1,$a1			; lwz	$t1,4($ap)
Packit c4476c
	lwz	$t2,8($ap)		; load a[j..j+3] as 32-bit word pairs
Packit c4476c
	lwz	$t3,12($ap)
Packit c4476c
	lwz	$t4,0($np)		; load n[j..j+3] as 32-bit word pairs
Packit c4476c
	lwz	$t5,4($np)
Packit c4476c
	lwz	$t6,8($np)
Packit c4476c
	lwz	$t7,12($np)
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	lfd	$ba,`$FRAME+0`($sp)
Packit c4476c
	lfd	$bb,`$FRAME+8`($sp)
Packit c4476c
	lfd	$bc,`$FRAME+16`($sp)
Packit c4476c
	lfd	$bd,`$FRAME+24`($sp)
Packit c4476c
	lfd	$na,`$FRAME+32`($sp)
Packit c4476c
	lfd	$nb,`$FRAME+40`($sp)
Packit c4476c
	lfd	$nc,`$FRAME+48`($sp)
Packit c4476c
	lfd	$nd,`$FRAME+56`($sp)
Packit c4476c
	std	$t0,`$FRAME+64`($sp)	; yes, std even in 32-bit build
Packit c4476c
	std	$t1,`$FRAME+72`($sp)
Packit c4476c
	std	$t2,`$FRAME+80`($sp)
Packit c4476c
	std	$t3,`$FRAME+88`($sp)
Packit c4476c
	std	$t4,`$FRAME+96`($sp)
Packit c4476c
	std	$t5,`$FRAME+104`($sp)
Packit c4476c
	std	$t6,`$FRAME+112`($sp)
Packit c4476c
	std	$t7,`$FRAME+120`($sp)
Packit c4476c
	fcfid	$ba,$ba
Packit c4476c
	fcfid	$bb,$bb
Packit c4476c
	fcfid	$bc,$bc
Packit c4476c
	fcfid	$bd,$bd
Packit c4476c
	fcfid	$na,$na
Packit c4476c
	fcfid	$nb,$nb
Packit c4476c
	fcfid	$nc,$nc
Packit c4476c
	fcfid	$nd,$nd
Packit c4476c
Packit c4476c
	lfd	$A0,`$FRAME+64`($sp)
Packit c4476c
	lfd	$A1,`$FRAME+72`($sp)
Packit c4476c
	lfd	$A2,`$FRAME+80`($sp)
Packit c4476c
	lfd	$A3,`$FRAME+88`($sp)
Packit c4476c
	lfd	$N0,`$FRAME+96`($sp)
Packit c4476c
	lfd	$N1,`$FRAME+104`($sp)
Packit c4476c
	lfd	$N2,`$FRAME+112`($sp)
Packit c4476c
	lfd	$N3,`$FRAME+120`($sp)
Packit c4476c
	fcfid	$A0,$A0
Packit c4476c
	fcfid	$A1,$A1
Packit c4476c
	fcfid	$A2,$A2
Packit c4476c
	fcfid	$A3,$A3
Packit c4476c
	fcfid	$N0,$N0
Packit c4476c
	fcfid	$N1,$N1
Packit c4476c
	fcfid	$N2,$N2
Packit c4476c
	fcfid	$N3,$N3
Packit c4476c
	addi	$ap,$ap,16
Packit c4476c
	addi	$np,$np,16
Packit c4476c
Packit c4476c
	fmul	$T1a,$A1,$ba
Packit c4476c
	fmul	$T1b,$A1,$bb
Packit c4476c
	stfd	$A0,8($nap_d)		; save a[j] in double format
Packit c4476c
	stfd	$A1,16($nap_d)
Packit c4476c
	fmul	$T2a,$A2,$ba
Packit c4476c
	fmul	$T2b,$A2,$bb
Packit c4476c
	stfd	$A2,24($nap_d)		; save a[j+1] in double format
Packit c4476c
	stfd	$A3,32($nap_d)
Packit c4476c
	fmul	$T3a,$A3,$ba
Packit c4476c
	fmul	$T3b,$A3,$bb
Packit c4476c
	stfd	$N0,40($nap_d)		; save n[j] in double format
Packit c4476c
	stfd	$N1,48($nap_d)
Packit c4476c
	fmul	$T0a,$A0,$ba
Packit c4476c
	fmul	$T0b,$A0,$bb
Packit c4476c
	stfd	$N2,56($nap_d)		; save n[j+1] in double format
Packit c4476c
	stfdu	$N3,64($nap_d)
Packit c4476c
Packit c4476c
	fmadd	$T1a,$A0,$bc,$T1a
Packit c4476c
	fmadd	$T1b,$A0,$bd,$T1b
Packit c4476c
	fmadd	$T2a,$A1,$bc,$T2a
Packit c4476c
	fmadd	$T2b,$A1,$bd,$T2b
Packit c4476c
	fmadd	$T3a,$A2,$bc,$T3a
Packit c4476c
	fmadd	$T3b,$A2,$bd,$T3b
Packit c4476c
	fmul	$dota,$A3,$bc
Packit c4476c
	fmul	$dotb,$A3,$bd
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
Packit c4476c
	stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c

Packit c4476c
.align	5
Packit c4476c
L1st:
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==8);
Packit c4476c
	lwz	$t0,`4^$LITTLE_ENDIAN`($ap)	; load a[j] as 32-bit word pair
Packit c4476c
	lwz	$t1,`0^$LITTLE_ENDIAN`($ap)
Packit c4476c
	lwz	$t2,`12^$LITTLE_ENDIAN`($ap)	; load a[j+1] as 32-bit word pair
Packit c4476c
	lwz	$t3,`8^$LITTLE_ENDIAN`($ap)
Packit c4476c
	lwz	$t4,`4^$LITTLE_ENDIAN`($np)	; load n[j] as 32-bit word pair
Packit c4476c
	lwz	$t5,`0^$LITTLE_ENDIAN`($np)
Packit c4476c
	lwz	$t6,`12^$LITTLE_ENDIAN`($np)	; load n[j+1] as 32-bit word pair
Packit c4476c
	lwz	$t7,`8^$LITTLE_ENDIAN`($np)
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);
Packit c4476c
	lwz	$t0,0($ap)		; load a[j..j+3] as 32-bit word pairs
Packit c4476c
	lwz	$t1,4($ap)
Packit c4476c
	lwz	$t2,8($ap)
Packit c4476c
	lwz	$t3,12($ap)
Packit c4476c
	lwz	$t4,0($np)		; load n[j..j+3] as 32-bit word pairs
Packit c4476c
	lwz	$t5,4($np)
Packit c4476c
	lwz	$t6,8($np)
Packit c4476c
	lwz	$t7,12($np)
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	std	$t0,`$FRAME+64`($sp)	; yes, std even in 32-bit build
Packit c4476c
	std	$t1,`$FRAME+72`($sp)
Packit c4476c
	std	$t2,`$FRAME+80`($sp)
Packit c4476c
	std	$t3,`$FRAME+88`($sp)
Packit c4476c
	std	$t4,`$FRAME+96`($sp)
Packit c4476c
	std	$t5,`$FRAME+104`($sp)
Packit c4476c
	std	$t6,`$FRAME+112`($sp)
Packit c4476c
	std	$t7,`$FRAME+120`($sp)
Packit c4476c
___
Packit c4476c
if ($SIZE_T==8 or $flavour =~ /osx/) {
Packit c4476c
$code.=<<___;
Packit c4476c
	ld	$t0,`$FRAME+0`($sp)
Packit c4476c
	ld	$t1,`$FRAME+8`($sp)
Packit c4476c
	ld	$t2,`$FRAME+16`($sp)
Packit c4476c
	ld	$t3,`$FRAME+24`($sp)
Packit c4476c
	ld	$t4,`$FRAME+32`($sp)
Packit c4476c
	ld	$t5,`$FRAME+40`($sp)
Packit c4476c
	ld	$t6,`$FRAME+48`($sp)
Packit c4476c
	ld	$t7,`$FRAME+56`($sp)
Packit c4476c
___
Packit c4476c
} else {
Packit c4476c
$code.=<<___;
Packit c4476c
	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
Packit c4476c
___
Packit c4476c
}
Packit c4476c
$code.=<<___;
Packit c4476c
	lfd	$A0,`$FRAME+64`($sp)
Packit c4476c
	lfd	$A1,`$FRAME+72`($sp)
Packit c4476c
	lfd	$A2,`$FRAME+80`($sp)
Packit c4476c
	lfd	$A3,`$FRAME+88`($sp)
Packit c4476c
	lfd	$N0,`$FRAME+96`($sp)
Packit c4476c
	lfd	$N1,`$FRAME+104`($sp)
Packit c4476c
	lfd	$N2,`$FRAME+112`($sp)
Packit c4476c
	lfd	$N3,`$FRAME+120`($sp)
Packit c4476c
	fcfid	$A0,$A0
Packit c4476c
	fcfid	$A1,$A1
Packit c4476c
	fcfid	$A2,$A2
Packit c4476c
	fcfid	$A3,$A3
Packit c4476c
	fcfid	$N0,$N0
Packit c4476c
	fcfid	$N1,$N1
Packit c4476c
	fcfid	$N2,$N2
Packit c4476c
	fcfid	$N3,$N3
Packit c4476c
	addi	$ap,$ap,16
Packit c4476c
	addi	$np,$np,16
Packit c4476c
Packit c4476c
	fmul	$T1a,$A1,$ba
Packit c4476c
	fmul	$T1b,$A1,$bb
Packit c4476c
	fmul	$T2a,$A2,$ba
Packit c4476c
	fmul	$T2b,$A2,$bb
Packit c4476c
	stfd	$A0,8($nap_d)		; save a[j] in double format
Packit c4476c
	stfd	$A1,16($nap_d)
Packit c4476c
	fmul	$T3a,$A3,$ba
Packit c4476c
	fmul	$T3b,$A3,$bb
Packit c4476c
	fmadd	$T0a,$A0,$ba,$dota
Packit c4476c
	fmadd	$T0b,$A0,$bb,$dotb
Packit c4476c
	stfd	$A2,24($nap_d)		; save a[j+1] in double format
Packit c4476c
	stfd	$A3,32($nap_d)
Packit c4476c
___
Packit c4476c
if ($SIZE_T==8 or $flavour =~ /osx/) {
Packit c4476c
$code.=<<___;
Packit c4476c
	fmadd	$T1a,$A0,$bc,$T1a
Packit c4476c
	fmadd	$T1b,$A0,$bd,$T1b
Packit c4476c
	fmadd	$T2a,$A1,$bc,$T2a
Packit c4476c
	fmadd	$T2b,$A1,$bd,$T2b
Packit c4476c
	stfd	$N0,40($nap_d)		; save n[j] in double format
Packit c4476c
	stfd	$N1,48($nap_d)
Packit c4476c
	fmadd	$T3a,$A2,$bc,$T3a
Packit c4476c
	fmadd	$T3b,$A2,$bd,$T3b
Packit c4476c
	 add	$t0,$t0,$carry		; can not overflow
Packit c4476c
	fmul	$dota,$A3,$bc
Packit c4476c
	fmul	$dotb,$A3,$bd
Packit c4476c
	stfd	$N2,56($nap_d)		; save n[j+1] in double format
Packit c4476c
	stfdu	$N3,64($nap_d)
Packit c4476c
	 srdi	$carry,$t0,16
Packit c4476c
	 add	$t1,$t1,$carry
Packit c4476c
	 srdi	$carry,$t1,16
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	 insrdi	$t0,$t1,16,32
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	 add	$t2,$t2,$carry
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	 srdi	$carry,$t2,16
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
	 insrdi	$t0,$t2,16,16
Packit c4476c
	 add	$t3,$t3,$carry
Packit c4476c
	 srdi	$carry,$t3,16
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	 insrdi	$t0,$t3,16,0		; 0..63 bits
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	 add	$t4,$t4,$carry
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	 srdi	$carry,$t4,16
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
	 add	$t5,$t5,$carry
Packit c4476c
	 srdi	$carry,$t5,16
Packit c4476c
	 insrdi	$t4,$t5,16,32
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	 add	$t6,$t6,$carry
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	 srdi	$carry,$t6,16
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	 insrdi	$t4,$t6,16,16
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
	 add	$t7,$t7,$carry
Packit c4476c
	 insrdi	$t4,$t7,16,0		; 64..127 bits
Packit c4476c
	 srdi	$carry,$t7,16		; upper 33 bits
Packit c4476c
Packit c4476c
	stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c
	 std	$t0,8($tp)		; tp[j-1]
Packit c4476c
	 stdu	$t4,16($tp)		; tp[j]
Packit c4476c
___
Packit c4476c
} else {
Packit c4476c
$code.=<<___;
Packit c4476c
	fmadd	$T1a,$A0,$bc,$T1a
Packit c4476c
	fmadd	$T1b,$A0,$bd,$T1b
Packit c4476c
	 addc	$t0,$t0,$carry
Packit c4476c
	 adde	$t1,$t1,$c1
Packit c4476c
	 srwi	$carry,$t0,16
Packit c4476c
	fmadd	$T2a,$A1,$bc,$T2a
Packit c4476c
	fmadd	$T2b,$A1,$bd,$T2b
Packit c4476c
	stfd	$N0,40($nap_d)		; save n[j] in double format
Packit c4476c
	stfd	$N1,48($nap_d)
Packit c4476c
	 srwi	$c1,$t1,16
Packit c4476c
	 insrwi	$carry,$t1,16,0
Packit c4476c
	fmadd	$T3a,$A2,$bc,$T3a
Packit c4476c
	fmadd	$T3b,$A2,$bd,$T3b
Packit c4476c
	 addc	$t2,$t2,$carry
Packit c4476c
	 adde	$t3,$t3,$c1
Packit c4476c
	 srwi	$carry,$t2,16
Packit c4476c
	fmul	$dota,$A3,$bc
Packit c4476c
	fmul	$dotb,$A3,$bd
Packit c4476c
	stfd	$N2,56($nap_d)		; save n[j+1] in double format
Packit c4476c
	stfdu	$N3,64($nap_d)
Packit c4476c
	 insrwi	$t0,$t2,16,0		; 0..31 bits
Packit c4476c
	 srwi	$c1,$t3,16
Packit c4476c
	 insrwi	$carry,$t3,16,0
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	 lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
Packit c4476c
	 lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
Packit c4476c
	 addc	$t4,$t4,$carry
Packit c4476c
	 adde	$t5,$t5,$c1
Packit c4476c
	 srwi	$carry,$t4,16
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	 srwi	$c1,$t5,16
Packit c4476c
	 insrwi	$carry,$t5,16,0
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	 addc	$t6,$t6,$carry
Packit c4476c
	 adde	$t7,$t7,$c1
Packit c4476c
	 srwi	$carry,$t6,16
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
	 insrwi	$t4,$t6,16,0		; 32..63 bits
Packit c4476c
	 srwi	$c1,$t7,16
Packit c4476c
	 insrwi	$carry,$t7,16,0
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	 lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
Packit c4476c
	 lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
Packit c4476c
	 addc	$t2,$t2,$carry
Packit c4476c
	 adde	$t3,$t3,$c1
Packit c4476c
	 srwi	$carry,$t2,16
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	 stw	$t0,12($tp)		; tp[j-1]
Packit c4476c
	 stw	$t4,8($tp)
Packit c4476c
	 srwi	$c1,$t3,16
Packit c4476c
	 insrwi	$carry,$t3,16,0
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	 lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
Packit c4476c
	 lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
Packit c4476c
	 addc	$t6,$t6,$carry
Packit c4476c
	 adde	$t7,$t7,$c1
Packit c4476c
	 srwi	$carry,$t6,16
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
	 insrwi	$t2,$t6,16,0		; 64..95 bits
Packit c4476c
	 srwi	$c1,$t7,16
Packit c4476c
	 insrwi	$carry,$t7,16,0
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	 lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
Packit c4476c
	 lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
Packit c4476c
	 addc	$t0,$t0,$carry
Packit c4476c
	 adde	$t1,$t1,$c1
Packit c4476c
	 srwi	$carry,$t0,16
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	 srwi	$c1,$t1,16
Packit c4476c
	 insrwi	$carry,$t1,16,0
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	 addc	$t4,$t4,$carry
Packit c4476c
	 adde	$t5,$t5,$c1
Packit c4476c
	 srwi	$carry,$t4,16
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
	 insrwi	$t0,$t4,16,0		; 96..127 bits
Packit c4476c
	 srwi	$c1,$t5,16
Packit c4476c
	 insrwi	$carry,$t5,16,0
Packit c4476c
Packit c4476c
	stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c
	 stw	$t2,20($tp)		; tp[j]
Packit c4476c
	 stwu	$t0,16($tp)
Packit c4476c
___
Packit c4476c
}
Packit c4476c
$code.=<<___;
Packit c4476c
	bdnz	L1st
Packit c4476c

Packit c4476c
	fctid	$dota,$dota
Packit c4476c
	fctid	$dotb,$dotb
Packit c4476c
___
Packit c4476c
if ($SIZE_T==8 or $flavour =~ /osx/) {
Packit c4476c
$code.=<<___;
Packit c4476c
	ld	$t0,`$FRAME+0`($sp)
Packit c4476c
	ld	$t1,`$FRAME+8`($sp)
Packit c4476c
	ld	$t2,`$FRAME+16`($sp)
Packit c4476c
	ld	$t3,`$FRAME+24`($sp)
Packit c4476c
	ld	$t4,`$FRAME+32`($sp)
Packit c4476c
	ld	$t5,`$FRAME+40`($sp)
Packit c4476c
	ld	$t6,`$FRAME+48`($sp)
Packit c4476c
	ld	$t7,`$FRAME+56`($sp)
Packit c4476c
	stfd	$dota,`$FRAME+64`($sp)
Packit c4476c
	stfd	$dotb,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	add	$t0,$t0,$carry		; can not overflow
Packit c4476c
	srdi	$carry,$t0,16
Packit c4476c
	add	$t1,$t1,$carry
Packit c4476c
	srdi	$carry,$t1,16
Packit c4476c
	insrdi	$t0,$t1,16,32
Packit c4476c
	add	$t2,$t2,$carry
Packit c4476c
	srdi	$carry,$t2,16
Packit c4476c
	insrdi	$t0,$t2,16,16
Packit c4476c
	add	$t3,$t3,$carry
Packit c4476c
	srdi	$carry,$t3,16
Packit c4476c
	insrdi	$t0,$t3,16,0		; 0..63 bits
Packit c4476c
	add	$t4,$t4,$carry
Packit c4476c
	srdi	$carry,$t4,16
Packit c4476c
	add	$t5,$t5,$carry
Packit c4476c
	srdi	$carry,$t5,16
Packit c4476c
	insrdi	$t4,$t5,16,32
Packit c4476c
	add	$t6,$t6,$carry
Packit c4476c
	srdi	$carry,$t6,16
Packit c4476c
	insrdi	$t4,$t6,16,16
Packit c4476c
	add	$t7,$t7,$carry
Packit c4476c
	insrdi	$t4,$t7,16,0		; 64..127 bits
Packit c4476c
	srdi	$carry,$t7,16		; upper 33 bits
Packit c4476c
	ld	$t6,`$FRAME+64`($sp)
Packit c4476c
	ld	$t7,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	std	$t0,8($tp)		; tp[j-1]
Packit c4476c
	stdu	$t4,16($tp)		; tp[j]
Packit c4476c
Packit c4476c
	add	$t6,$t6,$carry		; can not overflow
Packit c4476c
	srdi	$carry,$t6,16
Packit c4476c
	add	$t7,$t7,$carry
Packit c4476c
	insrdi	$t6,$t7,48,0
Packit c4476c
	srdi	$ovf,$t7,48
Packit c4476c
	std	$t6,8($tp)		; tp[num-1]
Packit c4476c
___
Packit c4476c
} else {
Packit c4476c
$code.=<<___;
Packit c4476c
	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
Packit c4476c
	stfd	$dota,`$FRAME+64`($sp)
Packit c4476c
	stfd	$dotb,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	addc	$t0,$t0,$carry
Packit c4476c
	adde	$t1,$t1,$c1
Packit c4476c
	srwi	$carry,$t0,16
Packit c4476c
	insrwi	$carry,$t1,16,0
Packit c4476c
	srwi	$c1,$t1,16
Packit c4476c
	addc	$t2,$t2,$carry
Packit c4476c
	adde	$t3,$t3,$c1
Packit c4476c
	srwi	$carry,$t2,16
Packit c4476c
	 insrwi	$t0,$t2,16,0		; 0..31 bits
Packit c4476c
	insrwi	$carry,$t3,16,0
Packit c4476c
	srwi	$c1,$t3,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
	srwi	$carry,$t4,16
Packit c4476c
	insrwi	$carry,$t5,16,0
Packit c4476c
	srwi	$c1,$t5,16
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	 insrwi	$t4,$t6,16,0		; 32..63 bits
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	 stw	$t0,12($tp)		; tp[j-1]
Packit c4476c
	 stw	$t4,8($tp)
Packit c4476c
Packit c4476c
	lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
Packit c4476c
	lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
Packit c4476c
	lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
Packit c4476c
	lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
Packit c4476c
	lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
Packit c4476c
	lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
Packit c4476c
	lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
Packit c4476c
	lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
Packit c4476c
Packit c4476c
	addc	$t2,$t2,$carry
Packit c4476c
	adde	$t3,$t3,$c1
Packit c4476c
	srwi	$carry,$t2,16
Packit c4476c
	insrwi	$carry,$t3,16,0
Packit c4476c
	srwi	$c1,$t3,16
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	 insrwi	$t2,$t6,16,0		; 64..95 bits
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	addc	$t0,$t0,$carry
Packit c4476c
	adde	$t1,$t1,$c1
Packit c4476c
	srwi	$carry,$t0,16
Packit c4476c
	insrwi	$carry,$t1,16,0
Packit c4476c
	srwi	$c1,$t1,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
	srwi	$carry,$t4,16
Packit c4476c
	 insrwi	$t0,$t4,16,0		; 96..127 bits
Packit c4476c
	insrwi	$carry,$t5,16,0
Packit c4476c
	srwi	$c1,$t5,16
Packit c4476c
	 stw	$t2,20($tp)		; tp[j]
Packit c4476c
	 stwu	$t0,16($tp)
Packit c4476c
Packit c4476c
	lwz	$t7,`$FRAME+64^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t6,`$FRAME+68^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t5,`$FRAME+72^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t4,`$FRAME+76^$LITTLE_ENDIAN`($sp)
Packit c4476c
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
Packit c4476c
	insrwi	$t6,$t4,16,0
Packit c4476c
	srwi	$t4,$t4,16
Packit c4476c
	insrwi	$t4,$t5,16,0
Packit c4476c
	srwi	$ovf,$t5,16
Packit c4476c
	stw	$t6,12($tp)		; tp[num-1]
Packit c4476c
	stw	$t4,8($tp)
Packit c4476c
___
Packit c4476c
}
Packit c4476c
$code.=<<___;
Packit c4476c
	slwi	$t7,$num,2
Packit c4476c
	subf	$nap_d,$t7,$nap_d	; rewind pointer
Packit c4476c

Packit c4476c
	li	$i,8			; i=1
Packit c4476c
.align	5
Packit c4476c
Louter:
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER`
Packit c4476c
	li	$carry,0
Packit c4476c
	mtctr	$j
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==8);
Packit c4476c
	ldx	$t3,$bp,$i		; bp[i]
Packit c4476c
Packit c4476c
	ld	$t6,`$FRAME+$TRANSFER+8`($sp)	; tp[0]
Packit c4476c
	mulld	$t7,$a0,$t3		; ap[0]*bp[i]
Packit c4476c
	add	$t7,$t7,$t6		; ap[0]*bp[i]+tp[0]
Packit c4476c
	; transfer bp[i] to FPU as 4x16-bit values
Packit c4476c
	extrdi	$t0,$t3,16,48
Packit c4476c
	extrdi	$t1,$t3,16,32
Packit c4476c
	extrdi	$t2,$t3,16,16
Packit c4476c
	extrdi	$t3,$t3,16,0
Packit c4476c
	std	$t0,`$FRAME+0`($sp)
Packit c4476c
	std	$t1,`$FRAME+8`($sp)
Packit c4476c
	std	$t2,`$FRAME+16`($sp)
Packit c4476c
	std	$t3,`$FRAME+24`($sp)
Packit c4476c
Packit c4476c
	mulld	$t7,$t7,$n0		; tp[0]*n0
Packit c4476c
	; transfer (ap[0]*bp[i]+tp[0])*n0 to FPU as 4x16-bit values
Packit c4476c
	extrdi	$t4,$t7,16,48
Packit c4476c
	extrdi	$t5,$t7,16,32
Packit c4476c
	extrdi	$t6,$t7,16,16
Packit c4476c
	extrdi	$t7,$t7,16,0
Packit c4476c
	std	$t4,`$FRAME+32`($sp)
Packit c4476c
	std	$t5,`$FRAME+40`($sp)
Packit c4476c
	std	$t6,`$FRAME+48`($sp)
Packit c4476c
	std	$t7,`$FRAME+56`($sp)
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);
Packit c4476c
	add	$t0,$bp,$i
Packit c4476c
	li	$c1,0
Packit c4476c
	lwz	$t1,0($t0)		; bp[i,i+1]
Packit c4476c
	lwz	$t3,4($t0)
Packit c4476c
Packit c4476c
	mullw	$t4,$a0,$t1		; ap[0]*bp[i]
Packit c4476c
	lwz	$t0,`$FRAME+$TRANSFER+8+4`($sp)	; tp[0]
Packit c4476c
	mulhwu	$t5,$a0,$t1
Packit c4476c
	lwz	$t2,`$FRAME+$TRANSFER+8`($sp)	; tp[0]
Packit c4476c
	mullw	$t6,$a1,$t1
Packit c4476c
	mullw	$t7,$a0,$t3
Packit c4476c
	add	$t5,$t5,$t6
Packit c4476c
	add	$t5,$t5,$t7
Packit c4476c
	addc	$t4,$t4,$t0		; ap[0]*bp[i]+tp[0]
Packit c4476c
	adde	$t5,$t5,$t2
Packit c4476c
	; transfer bp[i] to FPU as 4x16-bit values
Packit c4476c
	extrwi	$t0,$t1,16,16
Packit c4476c
	extrwi	$t1,$t1,16,0
Packit c4476c
	extrwi	$t2,$t3,16,16
Packit c4476c
	extrwi	$t3,$t3,16,0
Packit c4476c
	std	$t0,`$FRAME+0`($sp)	; yes, std in 32-bit build
Packit c4476c
	std	$t1,`$FRAME+8`($sp)
Packit c4476c
	std	$t2,`$FRAME+16`($sp)
Packit c4476c
	std	$t3,`$FRAME+24`($sp)
Packit c4476c
Packit c4476c
	mullw	$t0,$t4,$n0		; mulld tp[0]*n0
Packit c4476c
	mulhwu	$t1,$t4,$n0
Packit c4476c
	mullw	$t2,$t5,$n0
Packit c4476c
	mullw	$t3,$t4,$n1
Packit c4476c
	add	$t1,$t1,$t2
Packit c4476c
	add	$t1,$t1,$t3
Packit c4476c
	; transfer (ap[0]*bp[i]+tp[0])*n0 to FPU as 4x16-bit values
Packit c4476c
	extrwi	$t4,$t0,16,16
Packit c4476c
	extrwi	$t5,$t0,16,0
Packit c4476c
	extrwi	$t6,$t1,16,16
Packit c4476c
	extrwi	$t7,$t1,16,0
Packit c4476c
	std	$t4,`$FRAME+32`($sp)	; yes, std in 32-bit build
Packit c4476c
	std	$t5,`$FRAME+40`($sp)
Packit c4476c
	std	$t6,`$FRAME+48`($sp)
Packit c4476c
	std	$t7,`$FRAME+56`($sp)
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	lfd	$A0,8($nap_d)		; load a[j] in double format
Packit c4476c
	lfd	$A1,16($nap_d)
Packit c4476c
	lfd	$A2,24($nap_d)		; load a[j+1] in double format
Packit c4476c
	lfd	$A3,32($nap_d)
Packit c4476c
	lfd	$N0,40($nap_d)		; load n[j] in double format
Packit c4476c
	lfd	$N1,48($nap_d)
Packit c4476c
	lfd	$N2,56($nap_d)		; load n[j+1] in double format
Packit c4476c
	lfdu	$N3,64($nap_d)
Packit c4476c
Packit c4476c
	lfd	$ba,`$FRAME+0`($sp)
Packit c4476c
	lfd	$bb,`$FRAME+8`($sp)
Packit c4476c
	lfd	$bc,`$FRAME+16`($sp)
Packit c4476c
	lfd	$bd,`$FRAME+24`($sp)
Packit c4476c
	lfd	$na,`$FRAME+32`($sp)
Packit c4476c
	lfd	$nb,`$FRAME+40`($sp)
Packit c4476c
	lfd	$nc,`$FRAME+48`($sp)
Packit c4476c
	lfd	$nd,`$FRAME+56`($sp)
Packit c4476c
Packit c4476c
	fcfid	$ba,$ba
Packit c4476c
	fcfid	$bb,$bb
Packit c4476c
	fcfid	$bc,$bc
Packit c4476c
	fcfid	$bd,$bd
Packit c4476c
	fcfid	$na,$na
Packit c4476c
	fcfid	$nb,$nb
Packit c4476c
	fcfid	$nc,$nc
Packit c4476c
	fcfid	$nd,$nd
Packit c4476c
Packit c4476c
	fmul	$T1a,$A1,$ba
Packit c4476c
	fmul	$T1b,$A1,$bb
Packit c4476c
	fmul	$T2a,$A2,$ba
Packit c4476c
	fmul	$T2b,$A2,$bb
Packit c4476c
	fmul	$T3a,$A3,$ba
Packit c4476c
	fmul	$T3b,$A3,$bb
Packit c4476c
	fmul	$T0a,$A0,$ba
Packit c4476c
	fmul	$T0b,$A0,$bb
Packit c4476c
Packit c4476c
	fmadd	$T1a,$A0,$bc,$T1a
Packit c4476c
	fmadd	$T1b,$A0,$bd,$T1b
Packit c4476c
	fmadd	$T2a,$A1,$bc,$T2a
Packit c4476c
	fmadd	$T2b,$A1,$bd,$T2b
Packit c4476c
	fmadd	$T3a,$A2,$bc,$T3a
Packit c4476c
	fmadd	$T3b,$A2,$bd,$T3b
Packit c4476c
	fmul	$dota,$A3,$bc
Packit c4476c
	fmul	$dotb,$A3,$bd
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	 lfd	$A0,8($nap_d)		; load a[j] in double format
Packit c4476c
	 lfd	$A1,16($nap_d)
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	 lfd	$A2,24($nap_d)		; load a[j+1] in double format
Packit c4476c
	 lfd	$A3,32($nap_d)
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
Packit c4476c
	stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c

Packit c4476c
.align	5
Packit c4476c
Linner:
Packit c4476c
	fmul	$T1a,$A1,$ba
Packit c4476c
	fmul	$T1b,$A1,$bb
Packit c4476c
	fmul	$T2a,$A2,$ba
Packit c4476c
	fmul	$T2b,$A2,$bb
Packit c4476c
	lfd	$N0,40($nap_d)		; load n[j] in double format
Packit c4476c
	lfd	$N1,48($nap_d)
Packit c4476c
	fmul	$T3a,$A3,$ba
Packit c4476c
	fmul	$T3b,$A3,$bb
Packit c4476c
	fmadd	$T0a,$A0,$ba,$dota
Packit c4476c
	fmadd	$T0b,$A0,$bb,$dotb
Packit c4476c
	lfd	$N2,56($nap_d)		; load n[j+1] in double format
Packit c4476c
	lfdu	$N3,64($nap_d)
Packit c4476c
Packit c4476c
	fmadd	$T1a,$A0,$bc,$T1a
Packit c4476c
	fmadd	$T1b,$A0,$bd,$T1b
Packit c4476c
	fmadd	$T2a,$A1,$bc,$T2a
Packit c4476c
	fmadd	$T2b,$A1,$bd,$T2b
Packit c4476c
	 lfd	$A0,8($nap_d)		; load a[j] in double format
Packit c4476c
	 lfd	$A1,16($nap_d)
Packit c4476c
	fmadd	$T3a,$A2,$bc,$T3a
Packit c4476c
	fmadd	$T3b,$A2,$bd,$T3b
Packit c4476c
	fmul	$dota,$A3,$bc
Packit c4476c
	fmul	$dotb,$A3,$bd
Packit c4476c
	 lfd	$A2,24($nap_d)		; load a[j+1] in double format
Packit c4476c
	 lfd	$A3,32($nap_d)
Packit c4476c
___
Packit c4476c
if ($SIZE_T==8 or $flavour =~ /osx/) {
Packit c4476c
$code.=<<___;
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	 ld	$t0,`$FRAME+0`($sp)
Packit c4476c
	 ld	$t1,`$FRAME+8`($sp)
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	 ld	$t2,`$FRAME+16`($sp)
Packit c4476c
	 ld	$t3,`$FRAME+24`($sp)
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	 add	$t0,$t0,$carry		; can not overflow
Packit c4476c
	 ld	$t4,`$FRAME+32`($sp)
Packit c4476c
	 ld	$t5,`$FRAME+40`($sp)
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
	 srdi	$carry,$t0,16
Packit c4476c
	 add	$t1,$t1,$carry
Packit c4476c
	 srdi	$carry,$t1,16
Packit c4476c
	 ld	$t6,`$FRAME+48`($sp)
Packit c4476c
	 ld	$t7,`$FRAME+56`($sp)
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	 insrdi	$t0,$t1,16,32
Packit c4476c
	 ld	$t1,8($tp)		; tp[j]
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	 add	$t2,$t2,$carry
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	 srdi	$carry,$t2,16
Packit c4476c
	 insrdi	$t0,$t2,16,16
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
	 add	$t3,$t3,$carry
Packit c4476c
	 ldu	$t2,16($tp)		; tp[j+1]
Packit c4476c
	 srdi	$carry,$t3,16
Packit c4476c
	 insrdi	$t0,$t3,16,0		; 0..63 bits
Packit c4476c
	 add	$t4,$t4,$carry
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	 srdi	$carry,$t4,16
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	 add	$t5,$t5,$carry
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	 srdi	$carry,$t5,16
Packit c4476c
	 insrdi	$t4,$t5,16,32
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
	 add	$t6,$t6,$carry
Packit c4476c
	 srdi	$carry,$t6,16
Packit c4476c
	 insrdi	$t4,$t6,16,16
Packit c4476c
Packit c4476c
	stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	 add	$t7,$t7,$carry
Packit c4476c
	 addc	$t3,$t0,$t1
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
Packit c4476c
	extrdi	$t0,$t0,32,0
Packit c4476c
	extrdi	$t1,$t1,32,0
Packit c4476c
	adde	$t0,$t0,$t1
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	 insrdi	$t4,$t7,16,0		; 64..127 bits
Packit c4476c
	 srdi	$carry,$t7,16		; upper 33 bits
Packit c4476c
	stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	 adde	$t5,$t4,$t2
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
Packit c4476c
	extrdi	$t4,$t4,32,0
Packit c4476c
	extrdi	$t2,$t2,32,0
Packit c4476c
	adde	$t4,$t4,$t2
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c
	 addze	$carry,$carry
Packit c4476c
	 std	$t3,-16($tp)		; tp[j-1]
Packit c4476c
	 std	$t5,-8($tp)		; tp[j]
Packit c4476c
___
Packit c4476c
} else {
Packit c4476c
$code.=<<___;
Packit c4476c
	fmadd	$T1a,$N1,$na,$T1a
Packit c4476c
	fmadd	$T1b,$N1,$nb,$T1b
Packit c4476c
	 lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
Packit c4476c
	fmadd	$T2a,$N2,$na,$T2a
Packit c4476c
	fmadd	$T2b,$N2,$nb,$T2b
Packit c4476c
	 lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
Packit c4476c
	fmadd	$T3a,$N3,$na,$T3a
Packit c4476c
	fmadd	$T3b,$N3,$nb,$T3b
Packit c4476c
	 lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 addc	$t0,$t0,$carry
Packit c4476c
	 adde	$t1,$t1,$c1
Packit c4476c
	 srwi	$carry,$t0,16
Packit c4476c
	fmadd	$T0a,$N0,$na,$T0a
Packit c4476c
	fmadd	$T0b,$N0,$nb,$T0b
Packit c4476c
	 lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 srwi	$c1,$t1,16
Packit c4476c
	 insrwi	$carry,$t1,16,0
Packit c4476c
Packit c4476c
	fmadd	$T1a,$N0,$nc,$T1a
Packit c4476c
	fmadd	$T1b,$N0,$nd,$T1b
Packit c4476c
	 addc	$t2,$t2,$carry
Packit c4476c
	 adde	$t3,$t3,$c1
Packit c4476c
	 srwi	$carry,$t2,16
Packit c4476c
	fmadd	$T2a,$N1,$nc,$T2a
Packit c4476c
	fmadd	$T2b,$N1,$nd,$T2b
Packit c4476c
	 insrwi	$t0,$t2,16,0		; 0..31 bits
Packit c4476c
	 srwi	$c1,$t3,16
Packit c4476c
	 insrwi	$carry,$t3,16,0
Packit c4476c
	fmadd	$T3a,$N2,$nc,$T3a
Packit c4476c
	fmadd	$T3b,$N2,$nd,$T3b
Packit c4476c
	 lwz	$t2,12($tp)		; tp[j]
Packit c4476c
	 lwz	$t3,8($tp)
Packit c4476c
	 addc	$t4,$t4,$carry
Packit c4476c
	 adde	$t5,$t5,$c1
Packit c4476c
	 srwi	$carry,$t4,16
Packit c4476c
	fmadd	$dota,$N3,$nc,$dota
Packit c4476c
	fmadd	$dotb,$N3,$nd,$dotb
Packit c4476c
	 srwi	$c1,$t5,16
Packit c4476c
	 insrwi	$carry,$t5,16,0
Packit c4476c
Packit c4476c
	fctid	$T0a,$T0a
Packit c4476c
	 addc	$t6,$t6,$carry
Packit c4476c
	 adde	$t7,$t7,$c1
Packit c4476c
	 srwi	$carry,$t6,16
Packit c4476c
	fctid	$T0b,$T0b
Packit c4476c
	 insrwi	$t4,$t6,16,0		; 32..63 bits
Packit c4476c
	 srwi	$c1,$t7,16
Packit c4476c
	 insrwi	$carry,$t7,16,0
Packit c4476c
	fctid	$T1a,$T1a
Packit c4476c
	 addc	$t0,$t0,$t2
Packit c4476c
	 adde	$t4,$t4,$t3
Packit c4476c
	 lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
Packit c4476c
	 lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
Packit c4476c
	fctid	$T1b,$T1b
Packit c4476c
	 addze	$carry,$carry
Packit c4476c
	 addze	$c1,$c1
Packit c4476c
	 stw	$t0,4($tp)		; tp[j-1]
Packit c4476c
	 stw	$t4,0($tp)
Packit c4476c
	fctid	$T2a,$T2a
Packit c4476c
	 addc	$t2,$t2,$carry
Packit c4476c
	 adde	$t3,$t3,$c1
Packit c4476c
	 srwi	$carry,$t2,16
Packit c4476c
	 lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
Packit c4476c
	 lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
Packit c4476c
	fctid	$T2b,$T2b
Packit c4476c
	 srwi	$c1,$t3,16
Packit c4476c
	 insrwi	$carry,$t3,16,0
Packit c4476c
	 lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
Packit c4476c
	 lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
Packit c4476c
	fctid	$T3a,$T3a
Packit c4476c
	 addc	$t6,$t6,$carry
Packit c4476c
	 adde	$t7,$t7,$c1
Packit c4476c
	 srwi	$carry,$t6,16
Packit c4476c
	 lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
Packit c4476c
	 lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
Packit c4476c
	fctid	$T3b,$T3b
Packit c4476c
Packit c4476c
	 insrwi	$t2,$t6,16,0		; 64..95 bits
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	 lwz	$t6,20($tp)
Packit c4476c
	 lwzu	$t7,16($tp)
Packit c4476c
	addc	$t0,$t0,$carry
Packit c4476c
	 stfd	$T0a,`$FRAME+0`($sp)
Packit c4476c
	adde	$t1,$t1,$c1
Packit c4476c
	srwi	$carry,$t0,16
Packit c4476c
	 stfd	$T0b,`$FRAME+8`($sp)
Packit c4476c
	insrwi	$carry,$t1,16,0
Packit c4476c
	srwi	$c1,$t1,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	 stfd	$T1a,`$FRAME+16`($sp)
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
	srwi	$carry,$t4,16
Packit c4476c
	 insrwi	$t0,$t4,16,0		; 96..127 bits
Packit c4476c
	 stfd	$T1b,`$FRAME+24`($sp)
Packit c4476c
	insrwi	$carry,$t5,16,0
Packit c4476c
	srwi	$c1,$t5,16
Packit c4476c
Packit c4476c
	addc	$t2,$t2,$t6
Packit c4476c
	 stfd	$T2a,`$FRAME+32`($sp)
Packit c4476c
	adde	$t0,$t0,$t7
Packit c4476c
	 stfd	$T2b,`$FRAME+40`($sp)
Packit c4476c
	addze	$carry,$carry
Packit c4476c
	 stfd	$T3a,`$FRAME+48`($sp)
Packit c4476c
	addze	$c1,$c1
Packit c4476c
	 stfd	$T3b,`$FRAME+56`($sp)
Packit c4476c
	 stw	$t2,-4($tp)		; tp[j]
Packit c4476c
	 stw	$t0,-8($tp)
Packit c4476c
___
Packit c4476c
}
Packit c4476c
$code.=<<___;
Packit c4476c
	bdnz	Linner
Packit c4476c

Packit c4476c
	fctid	$dota,$dota
Packit c4476c
	fctid	$dotb,$dotb
Packit c4476c
___
Packit c4476c
if ($SIZE_T==8 or $flavour =~ /osx/) {
Packit c4476c
$code.=<<___;
Packit c4476c
	ld	$t0,`$FRAME+0`($sp)
Packit c4476c
	ld	$t1,`$FRAME+8`($sp)
Packit c4476c
	ld	$t2,`$FRAME+16`($sp)
Packit c4476c
	ld	$t3,`$FRAME+24`($sp)
Packit c4476c
	ld	$t4,`$FRAME+32`($sp)
Packit c4476c
	ld	$t5,`$FRAME+40`($sp)
Packit c4476c
	ld	$t6,`$FRAME+48`($sp)
Packit c4476c
	ld	$t7,`$FRAME+56`($sp)
Packit c4476c
	stfd	$dota,`$FRAME+64`($sp)
Packit c4476c
	stfd	$dotb,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	add	$t0,$t0,$carry		; can not overflow
Packit c4476c
	srdi	$carry,$t0,16
Packit c4476c
	add	$t1,$t1,$carry
Packit c4476c
	srdi	$carry,$t1,16
Packit c4476c
	insrdi	$t0,$t1,16,32
Packit c4476c
	add	$t2,$t2,$carry
Packit c4476c
	ld	$t1,8($tp)		; tp[j]
Packit c4476c
	srdi	$carry,$t2,16
Packit c4476c
	insrdi	$t0,$t2,16,16
Packit c4476c
	add	$t3,$t3,$carry
Packit c4476c
	ldu	$t2,16($tp)		; tp[j+1]
Packit c4476c
	srdi	$carry,$t3,16
Packit c4476c
	insrdi	$t0,$t3,16,0		; 0..63 bits
Packit c4476c
	add	$t4,$t4,$carry
Packit c4476c
	srdi	$carry,$t4,16
Packit c4476c
	add	$t5,$t5,$carry
Packit c4476c
	srdi	$carry,$t5,16
Packit c4476c
	insrdi	$t4,$t5,16,32
Packit c4476c
	add	$t6,$t6,$carry
Packit c4476c
	srdi	$carry,$t6,16
Packit c4476c
	insrdi	$t4,$t6,16,16
Packit c4476c
	add	$t7,$t7,$carry
Packit c4476c
	insrdi	$t4,$t7,16,0		; 64..127 bits
Packit c4476c
	srdi	$carry,$t7,16		; upper 33 bits
Packit c4476c
	ld	$t6,`$FRAME+64`($sp)
Packit c4476c
	ld	$t7,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	addc	$t3,$t0,$t1
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
Packit c4476c
	extrdi	$t0,$t0,32,0
Packit c4476c
	extrdi	$t1,$t1,32,0
Packit c4476c
	adde	$t0,$t0,$t1
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	adde	$t5,$t4,$t2
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
Packit c4476c
	extrdi	$t4,$t4,32,0
Packit c4476c
	extrdi	$t2,$t2,32,0
Packit c4476c
	adde	$t4,$t4,$t2
Packit c4476c
___
Packit c4476c
$code.=<<___;
Packit c4476c
	addze	$carry,$carry
Packit c4476c
Packit c4476c
	std	$t3,-16($tp)		; tp[j-1]
Packit c4476c
	std	$t5,-8($tp)		; tp[j]
Packit c4476c
Packit c4476c
	add	$carry,$carry,$ovf	; consume upmost overflow
Packit c4476c
	add	$t6,$t6,$carry		; can not overflow
Packit c4476c
	srdi	$carry,$t6,16
Packit c4476c
	add	$t7,$t7,$carry
Packit c4476c
	insrdi	$t6,$t7,48,0
Packit c4476c
	srdi	$ovf,$t7,48
Packit c4476c
	std	$t6,0($tp)		; tp[num-1]
Packit c4476c
___
Packit c4476c
} else {
Packit c4476c
$code.=<<___;
Packit c4476c
	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
Packit c4476c
	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
Packit c4476c
	stfd	$dota,`$FRAME+64`($sp)
Packit c4476c
	stfd	$dotb,`$FRAME+72`($sp)
Packit c4476c
Packit c4476c
	addc	$t0,$t0,$carry
Packit c4476c
	adde	$t1,$t1,$c1
Packit c4476c
	srwi	$carry,$t0,16
Packit c4476c
	insrwi	$carry,$t1,16,0
Packit c4476c
	srwi	$c1,$t1,16
Packit c4476c
	addc	$t2,$t2,$carry
Packit c4476c
	adde	$t3,$t3,$c1
Packit c4476c
	srwi	$carry,$t2,16
Packit c4476c
	 insrwi	$t0,$t2,16,0		; 0..31 bits
Packit c4476c
	 lwz	$t2,12($tp)		; tp[j]
Packit c4476c
	insrwi	$carry,$t3,16,0
Packit c4476c
	srwi	$c1,$t3,16
Packit c4476c
	 lwz	$t3,8($tp)
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
	srwi	$carry,$t4,16
Packit c4476c
	insrwi	$carry,$t5,16,0
Packit c4476c
	srwi	$c1,$t5,16
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	 insrwi	$t4,$t6,16,0		; 32..63 bits
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
Packit c4476c
	addc	$t0,$t0,$t2
Packit c4476c
	adde	$t4,$t4,$t3
Packit c4476c
	addze	$carry,$carry
Packit c4476c
	addze	$c1,$c1
Packit c4476c
	 stw	$t0,4($tp)		; tp[j-1]
Packit c4476c
	 stw	$t4,0($tp)
Packit c4476c
Packit c4476c
	lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
Packit c4476c
	lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
Packit c4476c
	lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
Packit c4476c
	lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
Packit c4476c
	lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
Packit c4476c
	lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
Packit c4476c
	lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
Packit c4476c
	lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
Packit c4476c
Packit c4476c
	addc	$t2,$t2,$carry
Packit c4476c
	adde	$t3,$t3,$c1
Packit c4476c
	srwi	$carry,$t2,16
Packit c4476c
	insrwi	$carry,$t3,16,0
Packit c4476c
	srwi	$c1,$t3,16
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	 insrwi	$t2,$t6,16,0		; 64..95 bits
Packit c4476c
	 lwz	$t6,20($tp)
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	 lwzu	$t7,16($tp)
Packit c4476c
	addc	$t0,$t0,$carry
Packit c4476c
	adde	$t1,$t1,$c1
Packit c4476c
	srwi	$carry,$t0,16
Packit c4476c
	insrwi	$carry,$t1,16,0
Packit c4476c
	srwi	$c1,$t1,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
	srwi	$carry,$t4,16
Packit c4476c
	 insrwi	$t0,$t4,16,0		; 96..127 bits
Packit c4476c
	insrwi	$carry,$t5,16,0
Packit c4476c
	srwi	$c1,$t5,16
Packit c4476c
Packit c4476c
	addc	$t2,$t2,$t6
Packit c4476c
	adde	$t0,$t0,$t7
Packit c4476c
	 lwz	$t7,`$FRAME+64^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t6,`$FRAME+68^$LITTLE_ENDIAN`($sp)
Packit c4476c
	addze	$carry,$carry
Packit c4476c
	addze	$c1,$c1
Packit c4476c
	 lwz	$t5,`$FRAME+72^$LITTLE_ENDIAN`($sp)
Packit c4476c
	 lwz	$t4,`$FRAME+76^$LITTLE_ENDIAN`($sp)
Packit c4476c
Packit c4476c
	addc	$t6,$t6,$carry
Packit c4476c
	adde	$t7,$t7,$c1
Packit c4476c
	 stw	$t2,-4($tp)		; tp[j]
Packit c4476c
	 stw	$t0,-8($tp)
Packit c4476c
	addc	$t6,$t6,$ovf
Packit c4476c
	addze	$t7,$t7
Packit c4476c
	srwi	$carry,$t6,16
Packit c4476c
	insrwi	$carry,$t7,16,0
Packit c4476c
	srwi	$c1,$t7,16
Packit c4476c
	addc	$t4,$t4,$carry
Packit c4476c
	adde	$t5,$t5,$c1
Packit c4476c
Packit c4476c
	insrwi	$t6,$t4,16,0
Packit c4476c
	srwi	$t4,$t4,16
Packit c4476c
	insrwi	$t4,$t5,16,0
Packit c4476c
	srwi	$ovf,$t5,16
Packit c4476c
	stw	$t6,4($tp)		; tp[num-1]
Packit c4476c
	stw	$t4,0($tp)
Packit c4476c
___
Packit c4476c
}
Packit c4476c
$code.=<<___;
Packit c4476c
	slwi	$t7,$num,2
Packit c4476c
	addi	$i,$i,8
Packit c4476c
	subf	$nap_d,$t7,$nap_d	; rewind pointer
Packit c4476c
	cmpw	$i,$num
Packit c4476c
	blt-	Louter
Packit c4476c
___
Packit c4476c

Packit c4476c
$code.=<<___ if ($SIZE_T==8);
Packit c4476c
	subf	$np,$num,$np	; rewind np
Packit c4476c
	addi	$j,$j,1		; restore counter
Packit c4476c
	subfc	$i,$i,$i	; j=0 and "clear" XER[CA]
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER+8`
Packit c4476c
	addi	$t4,$sp,`$FRAME+$TRANSFER+16`
Packit c4476c
	addi	$t5,$np,8
Packit c4476c
	addi	$t6,$rp,8
Packit c4476c
	mtctr	$j
Packit c4476c
Packit c4476c
.align	4
Packit c4476c
Lsub:	ldx	$t0,$tp,$i
Packit c4476c
	ldx	$t1,$np,$i
Packit c4476c
	ldx	$t2,$t4,$i
Packit c4476c
	ldx	$t3,$t5,$i
Packit c4476c
	subfe	$t0,$t1,$t0	; tp[j]-np[j]
Packit c4476c
	subfe	$t2,$t3,$t2	; tp[j+1]-np[j+1]
Packit c4476c
	stdx	$t0,$rp,$i
Packit c4476c
	stdx	$t2,$t6,$i
Packit c4476c
	addi	$i,$i,16
Packit c4476c
	bdnz	Lsub
Packit c4476c
Packit c4476c
	li	$i,0
Packit c4476c
	subfe	$ovf,$i,$ovf	; handle upmost overflow bit
Packit c4476c
	mtctr	$j
Packit c4476c
Packit c4476c
.align	4
Packit c4476c
Lcopy:				; conditional copy
Packit c4476c
	ldx	$t0,$tp,$i
Packit c4476c
	ldx	$t1,$t4,$i
Packit c4476c
	ldx	$t2,$rp,$i
Packit c4476c
	ldx	$t3,$t6,$i
Packit c4476c
	std	$i,8($nap_d)	; zap nap_d
Packit c4476c
	std	$i,16($nap_d)
Packit c4476c
	std	$i,24($nap_d)
Packit c4476c
	std	$i,32($nap_d)
Packit c4476c
	std	$i,40($nap_d)
Packit c4476c
	std	$i,48($nap_d)
Packit c4476c
	std	$i,56($nap_d)
Packit c4476c
	stdu	$i,64($nap_d)
Packit c4476c
	and	$t0,$t0,$ovf
Packit c4476c
	and	$t1,$t1,$ovf
Packit c4476c
	andc	$t2,$t2,$ovf
Packit c4476c
	andc	$t3,$t3,$ovf
Packit c4476c
	or	$t0,$t0,$t2
Packit c4476c
	or	$t1,$t1,$t3
Packit c4476c
	stdx	$t0,$rp,$i
Packit c4476c
	stdx	$t1,$t6,$i
Packit c4476c
	stdx	$i,$tp,$i	; zap tp at once
Packit c4476c
	stdx	$i,$t4,$i
Packit c4476c
	addi	$i,$i,16
Packit c4476c
	bdnz	Lcopy
Packit c4476c
___
Packit c4476c
$code.=<<___ if ($SIZE_T==4);
Packit c4476c
	subf	$np,$num,$np	; rewind np
Packit c4476c
	addi	$j,$j,1		; restore counter
Packit c4476c
	subfc	$i,$i,$i	; j=0 and "clear" XER[CA]
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER`
Packit c4476c
	addi	$np,$np,-4
Packit c4476c
	addi	$rp,$rp,-4
Packit c4476c
	addi	$ap,$sp,`$FRAME+$TRANSFER+4`
Packit c4476c
	mtctr	$j
Packit c4476c
Packit c4476c
.align	4
Packit c4476c
Lsub:	lwz	$t0,12($tp)	; load tp[j..j+3] in 64-bit word order
Packit c4476c
	lwz	$t1,8($tp)
Packit c4476c
	lwz	$t2,20($tp)
Packit c4476c
	lwzu	$t3,16($tp)
Packit c4476c
	lwz	$t4,4($np)	; load np[j..j+3] in 32-bit word order
Packit c4476c
	lwz	$t5,8($np)
Packit c4476c
	lwz	$t6,12($np)
Packit c4476c
	lwzu	$t7,16($np)
Packit c4476c
	subfe	$t4,$t4,$t0	; tp[j]-np[j]
Packit c4476c
	 stw	$t0,4($ap)	; save tp[j..j+3] in 32-bit word order
Packit c4476c
	subfe	$t5,$t5,$t1	; tp[j+1]-np[j+1]
Packit c4476c
	 stw	$t1,8($ap)
Packit c4476c
	subfe	$t6,$t6,$t2	; tp[j+2]-np[j+2]
Packit c4476c
	 stw	$t2,12($ap)
Packit c4476c
	subfe	$t7,$t7,$t3	; tp[j+3]-np[j+3]
Packit c4476c
	 stwu	$t3,16($ap)
Packit c4476c
	stw	$t4,4($rp)
Packit c4476c
	stw	$t5,8($rp)
Packit c4476c
	stw	$t6,12($rp)
Packit c4476c
	stwu	$t7,16($rp)
Packit c4476c
	bdnz	Lsub
Packit c4476c
Packit c4476c
	li	$i,0
Packit c4476c
	subfe	$ovf,$i,$ovf	; handle upmost overflow bit
Packit c4476c
	addi	$ap,$sp,`$FRAME+$TRANSFER+4`
Packit c4476c
	subf	$rp,$num,$rp	; rewind rp
Packit c4476c
	addi	$tp,$sp,`$FRAME+$TRANSFER`
Packit c4476c
	mtctr	$j
Packit c4476c
Packit c4476c
.align	4
Packit c4476c
Lcopy:				; conditional copy
Packit c4476c
	lwz	$t0,4($ap)
Packit c4476c
	lwz	$t1,8($ap)
Packit c4476c
	lwz	$t2,12($ap)
Packit c4476c
	lwzu	$t3,16($ap)
Packit c4476c
	lwz	$t4,4($rp)
Packit c4476c
	lwz	$t5,8($rp)
Packit c4476c
	lwz	$t6,12($rp)
Packit c4476c
	lwz	$t7,16($rp)
Packit c4476c
	std	$i,8($nap_d)	; zap nap_d
Packit c4476c
	std	$i,16($nap_d)
Packit c4476c
	std	$i,24($nap_d)
Packit c4476c
	std	$i,32($nap_d)
Packit c4476c
	std	$i,40($nap_d)
Packit c4476c
	std	$i,48($nap_d)
Packit c4476c
	std	$i,56($nap_d)
Packit c4476c
	stdu	$i,64($nap_d)
Packit c4476c
	and	$t0,$t0,$ovf
Packit c4476c
	and	$t1,$t1,$ovf
Packit c4476c
	and	$t2,$t2,$ovf
Packit c4476c
	and	$t3,$t3,$ovf
Packit c4476c
	andc	$t4,$t4,$ovf
Packit c4476c
	andc	$t5,$t5,$ovf
Packit c4476c
	andc	$t6,$t6,$ovf
Packit c4476c
	andc	$t7,$t7,$ovf
Packit c4476c
	or	$t0,$t0,$t4
Packit c4476c
	or	$t1,$t1,$t5
Packit c4476c
	or	$t2,$t2,$t6
Packit c4476c
	or	$t3,$t3,$t7
Packit c4476c
	stw	$t0,4($rp)
Packit c4476c
	stw	$t1,8($rp)
Packit c4476c
	stw	$t2,12($rp)
Packit c4476c
	stwu	$t3,16($rp)
Packit c4476c
	std	$i,8($tp)	; zap tp at once
Packit c4476c
	stdu	$i,16($tp)
Packit c4476c
	bdnz	Lcopy
Packit c4476c
___
Packit c4476c

Packit c4476c
$code.=<<___;
Packit c4476c
	$POP	$i,0($sp)
Packit c4476c
	li	r3,1	; signal "handled"
Packit c4476c
	$POP	r19,`-12*8-13*$SIZE_T`($i)
Packit c4476c
	$POP	r20,`-12*8-12*$SIZE_T`($i)
Packit c4476c
	$POP	r21,`-12*8-11*$SIZE_T`($i)
Packit c4476c
	$POP	r22,`-12*8-10*$SIZE_T`($i)
Packit c4476c
	$POP	r23,`-12*8-9*$SIZE_T`($i)
Packit c4476c
	$POP	r24,`-12*8-8*$SIZE_T`($i)
Packit c4476c
	$POP	r25,`-12*8-7*$SIZE_T`($i)
Packit c4476c
	$POP	r26,`-12*8-6*$SIZE_T`($i)
Packit c4476c
	$POP	r27,`-12*8-5*$SIZE_T`($i)
Packit c4476c
	$POP	r28,`-12*8-4*$SIZE_T`($i)
Packit c4476c
	$POP	r29,`-12*8-3*$SIZE_T`($i)
Packit c4476c
	$POP	r30,`-12*8-2*$SIZE_T`($i)
Packit c4476c
	$POP	r31,`-12*8-1*$SIZE_T`($i)
Packit c4476c
	lfd	f20,`-12*8`($i)
Packit c4476c
	lfd	f21,`-11*8`($i)
Packit c4476c
	lfd	f22,`-10*8`($i)
Packit c4476c
	lfd	f23,`-9*8`($i)
Packit c4476c
	lfd	f24,`-8*8`($i)
Packit c4476c
	lfd	f25,`-7*8`($i)
Packit c4476c
	lfd	f26,`-6*8`($i)
Packit c4476c
	lfd	f27,`-5*8`($i)
Packit c4476c
	lfd	f28,`-4*8`($i)
Packit c4476c
	lfd	f29,`-3*8`($i)
Packit c4476c
	lfd	f30,`-2*8`($i)
Packit c4476c
	lfd	f31,`-1*8`($i)
Packit c4476c
	mr	$sp,$i
Packit c4476c
	blr
Packit c4476c
	.long	0
Packit c4476c
	.byte	0,12,4,0,0x8c,13,6,0
Packit c4476c
	.long	0
Packit c4476c
.size	.$fname,.-.$fname
Packit c4476c
Packit c4476c
.asciz  "Montgomery Multiplication for PPC64, CRYPTOGAMS by <appro\@openssl.org>"
Packit c4476c
___
Packit c4476c
Packit c4476c
$code =~ s/\`([^\`]*)\`/eval $1/gem;
Packit c4476c
print $code;
Packit c4476c
close STDOUT or die "error closing STDOUT: $!";