...

Text file src/crypto/internal/nistec/p256_asm_ppc64le.s

Documentation: crypto/internal/nistec

     1// Copyright 2019 The Go Authors. All rights reserved.
     2// Use of this source code is governed by a BSD-style
     3// license that can be found in the LICENSE file.
     4
     5//go:build !purego
     6
     7#include "textflag.h"
     8
     9// This is a port of the s390x asm implementation.
    10// to ppc64le.
    11
    12// Some changes were needed due to differences in
    13// the Go opcodes and/or available instructions
    14// between s390x and ppc64le.
    15
    16// 1. There were operand order differences in the
    17// VSUBUQM, VSUBCUQ, and VSEL instructions.
    18
    19// 2. ppc64 does not have a multiply high and low
    20// like s390x, so those were implemented using
    21// macros to compute the equivalent values.
    22
    23// 3. The LVX, STVX instructions on ppc64 require
    24// 16 byte alignment of the data.  To avoid that
    25// requirement, data is loaded using LXVD2X and
    26// STXVD2X with VPERM to reorder bytes correctly.
    27
    28// I have identified some areas where I believe
    29// changes would be needed to make this work for big
    30// endian; however additional changes beyond what I
    31// have noted are most likely needed to make it work.
    32// - The string used with VPERM to swap the byte order
    33//   for loads and stores.
    34// - The constants that are loaded from CPOOL.
    35//
    36
    37// The following constants are defined in an order
    38// that is correct for use with LXVD2X/STXVD2X
    39// on little endian.
    40DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
    41DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
    42DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
    43DATA p256<>+0x18(SB)/8, $0xffffffffffffffff // P256
    44DATA p256<>+0x20(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
    45DATA p256<>+0x28(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
    46DATA p256<>+0x30(SB)/8, $0x0000000010111213 // SEL 0  d1 d0  0
    47DATA p256<>+0x38(SB)/8, $0x1415161700000000 // SEL 0  d1 d0  0
    48DATA p256<>+0x40(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
    49DATA p256<>+0x48(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
    50DATA p256mul<>+0x00(SB)/8, $0x00000000ffffffff // P256 original
    51DATA p256mul<>+0x08(SB)/8, $0xffffffffffffffff // P256
    52DATA p256mul<>+0x10(SB)/8, $0xffffffff00000001 // P256 original
    53DATA p256mul<>+0x18(SB)/8, $0x0000000000000000 // P256
    54DATA p256mul<>+0x20(SB)/8, $0x1c1d1e1f00000000 // SEL d0  0  0 d0
    55DATA p256mul<>+0x28(SB)/8, $0x000000001c1d1e1f // SEL d0  0  0 d0
    56DATA p256mul<>+0x30(SB)/8, $0x0001020304050607 // SEL d0  0 d1 d0
    57DATA p256mul<>+0x38(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL d0  0 d1 d0
    58DATA p256mul<>+0x40(SB)/8, $0x040506071c1d1e1f // SEL  0 d1 d0 d1
    59DATA p256mul<>+0x48(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL  0 d1 d0 d1
    60DATA p256mul<>+0x50(SB)/8, $0x0405060704050607 // SEL  0  0 d1 d0
    61DATA p256mul<>+0x58(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL  0  0 d1 d0
    62DATA p256mul<>+0x60(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
    63DATA p256mul<>+0x68(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
    64DATA p256mul<>+0x70(SB)/8, $0x141516170c0d0e0f // SEL 0  d1 d0  0
    65DATA p256mul<>+0x78(SB)/8, $0x1c1d1e1f14151617 // SEL 0  d1 d0  0
    66DATA p256mul<>+0x80(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
    67DATA p256mul<>+0x88(SB)/8, $0x0000000000000001 // (1*2^256)%P256
    68DATA p256mul<>+0x90(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
    69DATA p256mul<>+0x98(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
    70
    71// External declarations for constants
    72GLOBL p256ord<>(SB), 8, $32
    73GLOBL p256<>(SB), 8, $80
    74GLOBL p256mul<>(SB), 8, $160
    75
    76// The following macros are used to implement the ppc64le
    77// equivalent function from the corresponding s390x
    78// instruction for vector multiply high, low, and add,
    79// since there aren't exact equivalent instructions.
    80// The corresponding s390x instructions appear in the
    81// comments.
    82// Implementation for big endian would have to be
    83// investigated, I think it would be different.
    84//
    85//
    86// Vector multiply word
    87//
    88//	VMLF  x0, x1, out_low
    89//	VMLHF x0, x1, out_hi
    90#define VMULT(x1, x2, out_low, out_hi) \
    91	VMULEUW x1, x2, TMP1; \
    92	VMULOUW x1, x2, TMP2; \
    93	VMRGEW TMP1, TMP2, out_hi; \
    94	VMRGOW TMP1, TMP2, out_low
    95
    96//
    97// Vector multiply add word
    98//
    99//	VMALF  x0, x1, y, out_low
   100//	VMALHF x0, x1, y, out_hi
   101#define VMULT_ADD(x1, x2, y, one, out_low, out_hi) \
   102	VMULEUW  y, one, TMP2; \
   103	VMULOUW  y, one, TMP1; \
   104	VMULEUW  x1, x2, out_low; \
   105	VMULOUW  x1, x2, out_hi; \
   106	VADDUDM  TMP2, out_low, TMP2; \
   107	VADDUDM  TMP1, out_hi, TMP1; \
   108	VMRGOW   TMP2, TMP1, out_low; \
   109	VMRGEW   TMP2, TMP1, out_hi
   110
   111#define res_ptr R3
   112#define a_ptr R4
   113
   114#undef res_ptr
   115#undef a_ptr
   116
   117#define P1ptr   R3
   118#define CPOOL   R7
   119
   120#define Y1L   V0
   121#define Y1H   V1
   122#define T1L   V2
   123#define T1H   V3
   124
   125#define PL    V30
   126#define PH    V31
   127
   128#define CAR1  V6
   129// func p256NegCond(val *p256Point, cond int)
   130TEXT ·p256NegCond(SB), NOSPLIT, $0-16
   131	MOVD val+0(FP), P1ptr
   132	MOVD $16, R16
   133
   134	MOVD cond+8(FP), R6
   135	CMP  $0, R6
   136	BC   12, 2, LR      // just return if cond == 0
   137
   138	MOVD $p256mul<>+0x00(SB), CPOOL
   139
   140	LXVD2X (P1ptr)(R0), Y1L
   141	LXVD2X (P1ptr)(R16), Y1H
   142
   143	XXPERMDI Y1H, Y1H, $2, Y1H
   144	XXPERMDI Y1L, Y1L, $2, Y1L
   145
   146	LXVD2X (CPOOL)(R0), PL
   147	LXVD2X (CPOOL)(R16), PH
   148
   149	VSUBCUQ  PL, Y1L, CAR1      // subtract part2 giving carry
   150	VSUBUQM  PL, Y1L, T1L       // subtract part2 giving result
   151	VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2
   152
   153	XXPERMDI T1H, T1H, $2, T1H
   154	XXPERMDI T1L, T1L, $2, T1L
   155
   156	STXVD2X T1L, (R0+P1ptr)
   157	STXVD2X T1H, (R16+P1ptr)
   158	RET
   159
   160#undef P1ptr
   161#undef CPOOL
   162#undef Y1L
   163#undef Y1H
   164#undef T1L
   165#undef T1H
   166#undef PL
   167#undef PH
   168#undef CAR1
   169
   170#define P3ptr   R3
   171#define P1ptr   R4
   172#define P2ptr   R5
   173
   174#define X1L    V0
   175#define X1H    V1
   176#define Y1L    V2
   177#define Y1H    V3
   178#define Z1L    V4
   179#define Z1H    V5
   180#define X2L    V6
   181#define X2H    V7
   182#define Y2L    V8
   183#define Y2H    V9
   184#define Z2L    V10
   185#define Z2H    V11
   186#define SEL    V12
   187#define ZER    V13
   188
   189// This function uses LXVD2X and STXVD2X to avoid the
   190// data alignment requirement for LVX, STVX. Since
   191// this code is just moving bytes and not doing arithmetic,
   192// order of the bytes doesn't matter.
   193//
   194// func p256MovCond(res, a, b *p256Point, cond int)
   195TEXT ·p256MovCond(SB), NOSPLIT, $0-32
   196	MOVD res+0(FP), P3ptr
   197	MOVD a+8(FP), P1ptr
   198	MOVD b+16(FP), P2ptr
   199	MOVD $16, R16
   200	MOVD $32, R17
   201	MOVD $48, R18
   202	MOVD $56, R21
   203	MOVD $64, R19
   204	MOVD $80, R20
   205	// cond is R1 + 24 (cond offset) + 32
   206	LXVDSX (R1)(R21), SEL
   207	VSPLTISB $0, ZER
   208	// SEL controls whether to store a or b
   209	VCMPEQUD SEL, ZER, SEL
   210
   211	LXVD2X (P1ptr+R0), X1H
   212	LXVD2X (P1ptr+R16), X1L
   213	LXVD2X (P1ptr+R17), Y1H
   214	LXVD2X (P1ptr+R18), Y1L
   215	LXVD2X (P1ptr+R19), Z1H
   216	LXVD2X (P1ptr+R20), Z1L
   217
   218	LXVD2X (P2ptr+R0), X2H
   219	LXVD2X (P2ptr+R16), X2L
   220	LXVD2X (P2ptr+R17), Y2H
   221	LXVD2X (P2ptr+R18), Y2L
   222	LXVD2X (P2ptr+R19), Z2H
   223	LXVD2X (P2ptr+R20), Z2L
   224
   225	VSEL X1H, X2H, SEL, X1H
   226	VSEL X1L, X2L, SEL, X1L
   227	VSEL Y1H, Y2H, SEL, Y1H
   228	VSEL Y1L, Y2L, SEL, Y1L
   229	VSEL Z1H, Z2H, SEL, Z1H
   230	VSEL Z1L, Z2L, SEL, Z1L
   231
   232	STXVD2X X1H, (P3ptr+R0)
   233	STXVD2X X1L, (P3ptr+R16)
   234	STXVD2X Y1H, (P3ptr+R17)
   235	STXVD2X Y1L, (P3ptr+R18)
   236	STXVD2X Z1H, (P3ptr+R19)
   237	STXVD2X Z1L, (P3ptr+R20)
   238
   239	RET
   240
   241#undef P3ptr
   242#undef P1ptr
   243#undef P2ptr
   244#undef X1L
   245#undef X1H
   246#undef Y1L
   247#undef Y1H
   248#undef Z1L
   249#undef Z1H
   250#undef X2L
   251#undef X2H
   252#undef Y2L
   253#undef Y2H
   254#undef Z2L
   255#undef Z2H
   256#undef SEL
   257#undef ZER
   258
   259#define P3ptr   R3
   260#define P1ptr   R4
   261#define COUNT   R5
   262
   263#define X1L    V0
   264#define X1H    V1
   265#define Y1L    V2
   266#define Y1H    V3
   267#define Z1L    V4
   268#define Z1H    V5
   269#define X2L    V6
   270#define X2H    V7
   271#define Y2L    V8
   272#define Y2H    V9
   273#define Z2L    V10
   274#define Z2H    V11
   275
   276#define ONE   V18
   277#define IDX   V19
   278#define SEL1  V20
   279#define SEL2  V21
   280// func p256Select(point *p256Point, table *p256Table, idx int)
   281TEXT ·p256Select(SB), NOSPLIT, $0-24
   282	MOVD res+0(FP), P3ptr
   283	MOVD table+8(FP), P1ptr
   284	MOVD $16, R16
   285	MOVD $32, R17
   286	MOVD $48, R18
   287	MOVD $64, R19
   288	MOVD $80, R20
   289
   290	LXVDSX   (R1)(R18), SEL1 // VLREPG idx+32(FP), SEL1
   291	VSPLTB   $7, SEL1, IDX    // splat byte
   292	VSPLTISB $1, ONE          // VREPIB $1, ONE
   293	VSPLTISB $1, SEL2         // VREPIB $1, SEL2
   294	MOVD     $17, COUNT
   295	MOVD     COUNT, CTR       // set up ctr
   296
   297	VSPLTISB $0, X1H // VZERO  X1H
   298	VSPLTISB $0, X1L // VZERO  X1L
   299	VSPLTISB $0, Y1H // VZERO  Y1H
   300	VSPLTISB $0, Y1L // VZERO  Y1L
   301	VSPLTISB $0, Z1H // VZERO  Z1H
   302	VSPLTISB $0, Z1L // VZERO  Z1L
   303
   304loop_select:
   305
   306	// LVXD2X is used here since data alignment doesn't
   307	// matter.
   308
   309	LXVD2X (P1ptr+R0), X2H
   310	LXVD2X (P1ptr+R16), X2L
   311	LXVD2X (P1ptr+R17), Y2H
   312	LXVD2X (P1ptr+R18), Y2L
   313	LXVD2X (P1ptr+R19), Z2H
   314	LXVD2X (P1ptr+R20), Z2L
   315
   316	VCMPEQUD SEL2, IDX, SEL1 // VCEQG SEL2, IDX, SEL1 OK
   317
   318	// This will result in SEL1 being all 0s or 1s, meaning
   319	// the result is either X1L or X2L, no individual byte
   320	// selection.
   321
   322	VSEL X1L, X2L, SEL1, X1L
   323	VSEL X1H, X2H, SEL1, X1H
   324	VSEL Y1L, Y2L, SEL1, Y1L
   325	VSEL Y1H, Y2H, SEL1, Y1H
   326	VSEL Z1L, Z2L, SEL1, Z1L
   327	VSEL Z1H, Z2H, SEL1, Z1H
   328
   329	// Add 1 to all bytes in SEL2
   330	VADDUBM SEL2, ONE, SEL2    // VAB  SEL2, ONE, SEL2 OK
   331	ADD     $96, P1ptr
   332	BDNZ    loop_select
   333
   334	// STXVD2X is used here so that alignment doesn't
   335	// need to be verified. Since values were loaded
   336	// using LXVD2X this is OK.
   337	STXVD2X X1H, (P3ptr+R0)
   338	STXVD2X X1L, (P3ptr+R16)
   339	STXVD2X Y1H, (P3ptr+R17)
   340	STXVD2X Y1L, (P3ptr+R18)
   341	STXVD2X Z1H, (P3ptr+R19)
   342	STXVD2X Z1L, (P3ptr+R20)
   343	RET
   344
   345#undef P3ptr
   346#undef P1ptr
   347#undef COUNT
   348#undef X1L
   349#undef X1H
   350#undef Y1L
   351#undef Y1H
   352#undef Z1L
   353#undef Z1H
   354#undef X2L
   355#undef X2H
   356#undef Y2L
   357#undef Y2H
   358#undef Z2L
   359#undef Z2H
   360#undef ONE
   361#undef IDX
   362#undef SEL1
   363#undef SEL2
   364
   365// The following functions all reverse the byte order.
   366
   367//func p256BigToLittle(res *p256Element, in *[32]byte)
   368TEXT ·p256BigToLittle(SB), NOSPLIT, $0-16
   369	MOVD	res+0(FP), R3
   370	MOVD	in+8(FP), R4
   371	BR	p256InternalEndianSwap<>(SB)
   372
   373//func p256LittleToBig(res *[32]byte, in *p256Element)
   374TEXT ·p256LittleToBig(SB), NOSPLIT, $0-16
   375	MOVD	res+0(FP), R3
   376	MOVD	in+8(FP), R4
   377	BR	p256InternalEndianSwap<>(SB)
   378
   379//func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
   380TEXT ·p256OrdBigToLittle(SB), NOSPLIT, $0-16
   381	MOVD	res+0(FP), R3
   382	MOVD	in+8(FP), R4
   383	BR	p256InternalEndianSwap<>(SB)
   384
   385//func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
   386TEXT ·p256OrdLittleToBig(SB), NOSPLIT, $0-16
   387	MOVD	res+0(FP), R3
   388	MOVD	in+8(FP), R4
   389	BR	p256InternalEndianSwap<>(SB)
   390
   391TEXT p256InternalEndianSwap<>(SB), NOSPLIT, $0-0
   392	// Index registers needed for BR movs
   393	MOVD	$8, R9
   394	MOVD	$16, R10
   395	MOVD	$24, R14
   396
   397	MOVDBR	(R0)(R4), R5
   398	MOVDBR	(R9)(R4), R6
   399	MOVDBR	(R10)(R4), R7
   400	MOVDBR	(R14)(R4), R8
   401
   402	MOVD	R8, 0(R3)
   403	MOVD	R7, 8(R3)
   404	MOVD	R6, 16(R3)
   405	MOVD	R5, 24(R3)
   406
   407	RET
   408
   409#define P3ptr   R3
   410#define P1ptr   R4
   411#define COUNT   R5
   412
   413#define X1L    V0
   414#define X1H    V1
   415#define Y1L    V2
   416#define Y1H    V3
   417#define Z1L    V4
   418#define Z1H    V5
   419#define X2L    V6
   420#define X2H    V7
   421#define Y2L    V8
   422#define Y2H    V9
   423#define Z2L    V10
   424#define Z2H    V11
   425
   426#define ONE   V18
   427#define IDX   V19
   428#define SEL1  V20
   429#define SEL2  V21
   430
   431// func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
   432TEXT ·p256SelectAffine(SB), NOSPLIT, $0-24
   433	MOVD res+0(FP), P3ptr
   434	MOVD table+8(FP), P1ptr
   435	MOVD $16, R16
   436	MOVD $32, R17
   437	MOVD $48, R18
   438
   439	LXVDSX (R1)(R18), SEL1
   440	VSPLTB $7, SEL1, IDX    // splat byte
   441
   442	VSPLTISB $1, ONE    // Vector with byte 1s
   443	VSPLTISB $1, SEL2   // Vector with byte 1s
   444	MOVD     $64, COUNT
   445	MOVD     COUNT, CTR // loop count
   446
   447	VSPLTISB $0, X1H // VZERO  X1H
   448	VSPLTISB $0, X1L // VZERO  X1L
   449	VSPLTISB $0, Y1H // VZERO  Y1H
   450	VSPLTISB $0, Y1L // VZERO  Y1L
   451
   452loop_select:
   453	LXVD2X (P1ptr+R0), X2H
   454	LXVD2X (P1ptr+R16), X2L
   455	LXVD2X (P1ptr+R17), Y2H
   456	LXVD2X (P1ptr+R18), Y2L
   457
   458	VCMPEQUD SEL2, IDX, SEL1 // Compare against idx
   459
   460	VSEL X1L, X2L, SEL1, X1L // Select if idx matched
   461	VSEL X1H, X2H, SEL1, X1H
   462	VSEL Y1L, Y2L, SEL1, Y1L
   463	VSEL Y1H, Y2H, SEL1, Y1H
   464
   465	VADDUBM SEL2, ONE, SEL2    // Increment SEL2 bytes by 1
   466	ADD     $64, P1ptr         // Next chunk
   467	BDNZ	loop_select
   468
   469	STXVD2X X1H, (P3ptr+R0)
   470	STXVD2X X1L, (P3ptr+R16)
   471	STXVD2X Y1H, (P3ptr+R17)
   472	STXVD2X Y1L, (P3ptr+R18)
   473	RET
   474
   475#undef P3ptr
   476#undef P1ptr
   477#undef COUNT
   478#undef X1L
   479#undef X1H
   480#undef Y1L
   481#undef Y1H
   482#undef Z1L
   483#undef Z1H
   484#undef X2L
   485#undef X2H
   486#undef Y2L
   487#undef Y2H
   488#undef Z2L
   489#undef Z2H
   490#undef ONE
   491#undef IDX
   492#undef SEL1
   493#undef SEL2
   494
   495#define res_ptr R3
   496#define x_ptr   R4
   497#define CPOOL   R7
   498
   499#define T0   V0
   500#define T1   V1
   501#define T2   V2
   502#define TT0  V3
   503#define TT1  V4
   504
   505#define ZER   V6
   506#define SEL1  V7
   507#define SEL2  V8
   508#define CAR1  V9
   509#define CAR2  V10
   510#define RED1  V11
   511#define RED2  V12
   512#define PL    V13
   513#define PH    V14
   514
   515// func p256FromMont(res, in *p256Element)
   516TEXT ·p256FromMont(SB), NOSPLIT, $0-16
   517	MOVD res+0(FP), res_ptr
   518	MOVD in+8(FP), x_ptr
   519
   520	MOVD $16, R16
   521	MOVD $32, R17
   522	MOVD $48, R18
   523	MOVD $64, R19
   524	MOVD $p256<>+0x00(SB), CPOOL
   525
   526	VSPLTISB $0, T2  // VZERO T2
   527	VSPLTISB $0, ZER // VZERO ZER
   528
   529	// Constants are defined so that the LXVD2X is correct
   530	LXVD2X (CPOOL+R0), PH
   531	LXVD2X (CPOOL+R16), PL
   532
   533	// VPERM byte selections
   534	LXVD2X (CPOOL+R18), SEL2
   535	LXVD2X (CPOOL+R19), SEL1
   536
   537	LXVD2X (R16)(x_ptr), T1
   538	LXVD2X (R0)(x_ptr), T0
   539
   540	// Put in true little endian order
   541	XXPERMDI T0, T0, $2, T0
   542	XXPERMDI T1, T1, $2, T1
   543
   544	// First round
   545	VPERM   T1, T0, SEL1, RED2    // d1 d0 d1 d0
   546	VPERM   ZER, RED2, SEL2, RED1 // 0  d1 d0  0
   547	VSUBUQM RED2, RED1, RED2      // VSQ   RED1, RED2, RED2      // Guaranteed not to underflow
   548
   549	VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
   550	VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
   551
   552	VADDCUQ  T0, RED1, CAR1       // VACCQ  T0, RED1, CAR1
   553	VADDUQM  T0, RED1, T0         // VAQ    T0, RED1, T0
   554	VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
   555	VADDEUQM T1, RED2, CAR1, T1   // VACQ   T1, RED2, CAR1, T1
   556	VADDUQM  T2, CAR2, T2         // VAQ    T2, CAR2, T2
   557
   558	// Second round
   559	VPERM   T1, T0, SEL1, RED2    // d1 d0 d1 d0
   560	VPERM   ZER, RED2, SEL2, RED1 // 0  d1 d0  0
   561	VSUBUQM RED2, RED1, RED2      // VSQ   RED1, RED2, RED2      // Guaranteed not to underflow
   562
   563	VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
   564	VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
   565
   566	VADDCUQ  T0, RED1, CAR1       // VACCQ  T0, RED1, CAR1
   567	VADDUQM  T0, RED1, T0         // VAQ    T0, RED1, T0
   568	VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
   569	VADDEUQM T1, RED2, CAR1, T1   // VACQ   T1, RED2, CAR1, T1
   570	VADDUQM  T2, CAR2, T2         // VAQ    T2, CAR2, T2
   571
   572	// Third round
   573	VPERM   T1, T0, SEL1, RED2    // d1 d0 d1 d0
   574	VPERM   ZER, RED2, SEL2, RED1 // 0  d1 d0  0
   575	VSUBUQM RED2, RED1, RED2      // VSQ   RED1, RED2, RED2      // Guaranteed not to underflow
   576
   577	VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
   578	VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
   579
   580	VADDCUQ  T0, RED1, CAR1       // VACCQ  T0, RED1, CAR1
   581	VADDUQM  T0, RED1, T0         // VAQ    T0, RED1, T0
   582	VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
   583	VADDEUQM T1, RED2, CAR1, T1   // VACQ   T1, RED2, CAR1, T1
   584	VADDUQM  T2, CAR2, T2         // VAQ    T2, CAR2, T2
   585
   586	// Last round
   587	VPERM   T1, T0, SEL1, RED2    // d1 d0 d1 d0
   588	VPERM   ZER, RED2, SEL2, RED1 // 0  d1 d0  0
   589	VSUBUQM RED2, RED1, RED2      // VSQ   RED1, RED2, RED2      // Guaranteed not to underflow
   590
   591	VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
   592	VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
   593
   594	VADDCUQ  T0, RED1, CAR1       // VACCQ  T0, RED1, CAR1
   595	VADDUQM  T0, RED1, T0         // VAQ    T0, RED1, T0
   596	VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
   597	VADDEUQM T1, RED2, CAR1, T1   // VACQ   T1, RED2, CAR1, T1
   598	VADDUQM  T2, CAR2, T2         // VAQ    T2, CAR2, T2
   599
   600	// ---------------------------------------------------
   601
   602	VSUBCUQ  T0, PL, CAR1       // VSCBIQ  PL, T0, CAR1
   603	VSUBUQM  T0, PL, TT0        // VSQ     PL, T0, TT0
   604	VSUBECUQ T1, PH, CAR1, CAR2 // VSBCBIQ T1, PH, CAR1, CAR2
   605	VSUBEUQM T1, PH, CAR1, TT1  // VSBIQ   T1, PH, CAR1, TT1
   606	VSUBEUQM T2, ZER, CAR2, T2  // VSBIQ   T2, ZER, CAR2, T2
   607
   608	VSEL TT0, T0, T2, T0
   609	VSEL TT1, T1, T2, T1
   610
   611	// Reorder the bytes so STXVD2X can be used.
   612	// TT0, TT1 used for VPERM result in case
   613	// the caller expects T0, T1 to be good.
   614	XXPERMDI T0, T0, $2, TT0
   615	XXPERMDI T1, T1, $2, TT1
   616
   617	STXVD2X TT0, (R0)(res_ptr)
   618	STXVD2X TT1, (R16)(res_ptr)
   619	RET
   620
   621#undef res_ptr
   622#undef x_ptr
   623#undef CPOOL
   624#undef T0
   625#undef T1
   626#undef T2
   627#undef TT0
   628#undef TT1
   629#undef ZER
   630#undef SEL1
   631#undef SEL2
   632#undef CAR1
   633#undef CAR2
   634#undef RED1
   635#undef RED2
   636#undef PL
   637#undef PH
   638
   639// ---------------------------------------
   640// p256MulInternal
   641// V0-V3 V30,V31 - Not Modified
   642// V4-V15 V27-V29 - Volatile
   643
   644#define CPOOL   R7
   645
   646// Parameters
   647#define X0    V0 // Not modified
   648#define X1    V1 // Not modified
   649#define Y0    V2 // Not modified
   650#define Y1    V3 // Not modified
   651#define T0    V4 // Result
   652#define T1    V5 // Result
   653#define P0    V30 // Not modified
   654#define P1    V31 // Not modified
   655
   656// Temporaries: lots of reused vector regs
   657#define YDIG  V6 // Overloaded with CAR2
   658#define ADD1H V7 // Overloaded with ADD3H
   659#define ADD2H V8 // Overloaded with ADD4H
   660#define ADD3  V9 // Overloaded with SEL2,SEL5
   661#define ADD4  V10 // Overloaded with SEL3,SEL6
   662#define RED1  V11 // Overloaded with CAR2
   663#define RED2  V12
   664#define RED3  V13 // Overloaded with SEL1
   665#define T2    V14
   666// Overloaded temporaries
   667#define ADD1  V4 // Overloaded with T0
   668#define ADD2  V5 // Overloaded with T1
   669#define ADD3H V7 // Overloaded with ADD1H
   670#define ADD4H V8 // Overloaded with ADD2H
   671#define ZER   V28 // Overloaded with TMP1
   672#define CAR1  V6 // Overloaded with YDIG
   673#define CAR2  V11 // Overloaded with RED1
   674// Constant Selects
   675#define SEL1  V13 // Overloaded with RED3
   676#define SEL2  V9 // Overloaded with ADD3,SEL5
   677#define SEL3  V10 // Overloaded with ADD4,SEL6
   678#define SEL4  V6 // Overloaded with YDIG,CAR1
   679#define SEL5  V9 // Overloaded with ADD3,SEL2
   680#define SEL6  V10 // Overloaded with ADD4,SEL3
   681
   682// TMP1, TMP2 used in
   683// VMULT macros
   684#define TMP1  V13 // Overloaded with RED3
   685#define TMP2  V27
   686#define ONE   V29 // 1s splatted by word
   687
   688/* *
   689 * To follow the flow of bits, for your own sanity a stiff drink, need you shall.
   690 * Of a single round, a 'helpful' picture, here is. Meaning, column position has.
   691 * With you, SIMD be...
   692 *
   693 *                                           +--------+--------+
   694 *                                  +--------|  RED2  |  RED1  |
   695 *                                  |        +--------+--------+
   696 *                                  |       ---+--------+--------+
   697 *                                  |  +---- T2|   T1   |   T0   |--+
   698 *                                  |  |    ---+--------+--------+  |
   699 *                                  |  |                            |
   700 *                                  |  |    ======================= |
   701 *                                  |  |                            |
   702 *                                  |  |       +--------+--------+<-+
   703 *                                  |  +-------|  ADD2  |  ADD1  |--|-----+
   704 *                                  |  |       +--------+--------+  |     |
   705 *                                  |  |     +--------+--------+<---+     |
   706 *                                  |  |     | ADD2H  | ADD1H  |--+       |
   707 *                                  |  |     +--------+--------+  |       |
   708 *                                  |  |     +--------+--------+<-+       |
   709 *                                  |  |     |  ADD4  |  ADD3  |--|-+     |
   710 *                                  |  |     +--------+--------+  | |     |
   711 *                                  |  |   +--------+--------+<---+ |     |
   712 *                                  |  |   | ADD4H  | ADD3H  |------|-+   |(+vzero)
   713 *                                  |  |   +--------+--------+      | |   V
   714 *                                  |  | ------------------------   | | +--------+
   715 *                                  |  |                            | | |  RED3  |  [d0 0 0 d0]
   716 *                                  |  |                            | | +--------+
   717 *                                  |  +---->+--------+--------+    | |   |
   718 *   (T2[1w]||ADD2[4w]||ADD1[3w])   +--------|   T1   |   T0   |    | |   |
   719 *                                  |        +--------+--------+    | |   |
   720 *                                  +---->---+--------+--------+    | |   |
   721 *                                         T2|   T1   |   T0   |----+ |   |
   722 *                                        ---+--------+--------+    | |   |
   723 *                                        ---+--------+--------+<---+ |   |
   724 *                                    +--- T2|   T1   |   T0   |----------+
   725 *                                    |   ---+--------+--------+      |   |
   726 *                                    |  +--------+--------+<-------------+
   727 *                                    |  |  RED2  |  RED1  |-----+    |   | [0 d1 d0 d1] [d0 0 d1 d0]
   728 *                                    |  +--------+--------+     |    |   |
   729 *                                    |  +--------+<----------------------+
   730 *                                    |  |  RED3  |--------------+    |     [0 0 d1 d0]
   731 *                                    |  +--------+              |    |
   732 *                                    +--->+--------+--------+   |    |
   733 *                                         |   T1   |   T0   |--------+
   734 *                                         +--------+--------+   |    |
   735 *                                   --------------------------- |    |
   736 *                                                               |    |
   737 *                                       +--------+--------+<----+    |
   738 *                                       |  RED2  |  RED1  |          |
   739 *                                       +--------+--------+          |
   740 *                                      ---+--------+--------+<-------+
   741 *                                       T2|   T1   |   T0   |            (H1P-H1P-H00RRAY!)
   742 *                                      ---+--------+--------+
   743 *
   744 *                                                                *Mi obra de arte de siglo XXI @vpaprots
   745 *
   746 *
   747 * First group is special, doesn't get the two inputs:
   748 *                                             +--------+--------+<-+
   749 *                                     +-------|  ADD2  |  ADD1  |--|-----+
   750 *                                     |       +--------+--------+  |     |
   751 *                                     |     +--------+--------+<---+     |
   752 *                                     |     | ADD2H  | ADD1H  |--+       |
   753 *                                     |     +--------+--------+  |       |
   754 *                                     |     +--------+--------+<-+       |
   755 *                                     |     |  ADD4  |  ADD3  |--|-+     |
   756 *                                     |     +--------+--------+  | |     |
   757 *                                     |   +--------+--------+<---+ |     |
   758 *                                     |   | ADD4H  | ADD3H  |------|-+   |(+vzero)
   759 *                                     |   +--------+--------+      | |   V
   760 *                                     | ------------------------   | | +--------+
   761 *                                     |                            | | |  RED3  |  [d0 0 0 d0]
   762 *                                     |                            | | +--------+
   763 *                                     +---->+--------+--------+    | |   |
   764 *   (T2[1w]||ADD2[4w]||ADD1[3w])            |   T1   |   T0   |----+ |   |
   765 *                                           +--------+--------+    | |   |
   766 *                                        ---+--------+--------+<---+ |   |
   767 *                                    +--- T2|   T1   |   T0   |----------+
   768 *                                    |   ---+--------+--------+      |   |
   769 *                                    |  +--------+--------+<-------------+
   770 *                                    |  |  RED2  |  RED1  |-----+    |   | [0 d1 d0 d1] [d0 0 d1 d0]
   771 *                                    |  +--------+--------+     |    |   |
   772 *                                    |  +--------+<----------------------+
   773 *                                    |  |  RED3  |--------------+    |     [0 0 d1 d0]
   774 *                                    |  +--------+              |    |
   775 *                                    +--->+--------+--------+   |    |
   776 *                                         |   T1   |   T0   |--------+
   777 *                                         +--------+--------+   |    |
   778 *                                   --------------------------- |    |
   779 *                                                               |    |
   780 *                                       +--------+--------+<----+    |
   781 *                                       |  RED2  |  RED1  |          |
   782 *                                       +--------+--------+          |
   783 *                                      ---+--------+--------+<-------+
   784 *                                       T2|   T1   |   T0   |            (H1P-H1P-H00RRAY!)
   785 *                                      ---+--------+--------+
   786 *
   787 * Last 'group' needs to RED2||RED1 shifted less
   788 */
   789TEXT p256MulInternal<>(SB), NOSPLIT, $0-16
   790	// CPOOL loaded from caller
   791	MOVD $16, R16
   792	MOVD $32, R17
   793	MOVD $48, R18
   794	MOVD $64, R19
   795	MOVD $80, R20
   796	MOVD $96, R21
   797	MOVD $112, R22
   798
   799	// ---------------------------------------------------
   800
   801	VSPLTW $3, Y0, YDIG // VREPF Y0 is input
   802
   803	//	VMLHF X0, YDIG, ADD1H
   804	//	VMLHF X1, YDIG, ADD2H
   805	//	VMLF  X0, YDIG, ADD1
   806	//	VMLF  X1, YDIG, ADD2
   807	//
   808	VMULT(X0, YDIG, ADD1, ADD1H)
   809	VMULT(X1, YDIG, ADD2, ADD2H)
   810
   811	VSPLTISW $1, ONE
   812	VSPLTW $2, Y0, YDIG // VREPF
   813
   814	//	VMALF  X0, YDIG, ADD1H, ADD3
   815	//	VMALF  X1, YDIG, ADD2H, ADD4
   816	//	VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
   817	//	VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
   818	VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
   819	VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
   820
   821	LXVD2X   (R17)(CPOOL), SEL1
   822	VSPLTISB $0, ZER               // VZERO ZER
   823	VPERM    ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
   824
   825	VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free	// VSLDB
   826	VSLDOI $12, ZER, ADD2, T1  // ADD2 Free	// VSLDB
   827
   828	VADDCUQ  T0, ADD3, CAR1     // VACCQ
   829	VADDUQM  T0, ADD3, T0       // ADD3 Free	// VAQ
   830	VADDECUQ T1, ADD4, CAR1, T2 // VACCCQ
   831	VADDEUQM T1, ADD4, CAR1, T1 // ADD4 Free	// VACQ
   832
   833	LXVD2X  (R18)(CPOOL), SEL2
   834	LXVD2X  (R19)(CPOOL), SEL3
   835	LXVD2X  (R20)(CPOOL), SEL4
   836	VPERM   RED3, T0, SEL2, RED1 // [d0  0 d1 d0]
   837	VPERM   RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
   838	VPERM   RED3, T0, SEL4, RED3 // [ 0  0 d1 d0]
   839	VSUBUQM RED2, RED3, RED2     // Guaranteed not to underflow -->? // VSQ
   840
   841	VSLDOI $12, T1, T0, T0 // VSLDB
   842	VSLDOI $12, T2, T1, T1 // VSLDB
   843
   844	VADDCUQ  T0, ADD3H, CAR1     // VACCQ
   845	VADDUQM  T0, ADD3H, T0       // VAQ
   846	VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
   847	VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
   848
   849	// ---------------------------------------------------
   850
   851	VSPLTW $1, Y0, YDIG                // VREPF
   852
   853	//	VMALHF X0, YDIG, T0, ADD1H
   854	//	VMALHF X1, YDIG, T1, ADD2H
   855	//	VMALF  X0, YDIG, T0, ADD1  // T0 Free->ADD1
   856	//	VMALF  X1, YDIG, T1, ADD2  // T1 Free->ADD2
   857	VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
   858	VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
   859
   860	VSPLTW $0, Y0, YDIG // VREPF
   861
   862	//	VMALF  X0, YDIG, ADD1H, ADD3
   863	//	VMALF  X1, YDIG, ADD2H, ADD4
   864	//	VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free->ADD3H
   865	//	VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free->ADD4H , YDIG Free->ZER
   866	VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
   867	VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
   868
   869	VSPLTISB $0, ZER               // VZERO ZER
   870	LXVD2X   (R17)(CPOOL), SEL1
   871	VPERM    ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
   872
   873	VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free->T0		// VSLDB
   874	VSLDOI $12, T2, ADD2, T1   // ADD2 Free->T1, T2 Free	// VSLDB
   875
   876	VADDCUQ  T0, RED1, CAR1     // VACCQ
   877	VADDUQM  T0, RED1, T0       // VAQ
   878	VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
   879	VADDEUQM T1, RED2, CAR1, T1 // VACQ
   880
   881	VADDCUQ  T0, ADD3, CAR1       // VACCQ
   882	VADDUQM  T0, ADD3, T0         // VAQ
   883	VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
   884	VADDEUQM T1, ADD4, CAR1, T1   // VACQ
   885	VADDUQM  T2, CAR2, T2         // VAQ
   886
   887	LXVD2X  (R18)(CPOOL), SEL2
   888	LXVD2X  (R19)(CPOOL), SEL3
   889	LXVD2X  (R20)(CPOOL), SEL4
   890	VPERM   RED3, T0, SEL2, RED1 // [d0  0 d1 d0]
   891	VPERM   RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
   892	VPERM   RED3, T0, SEL4, RED3 // [ 0  0 d1 d0]
   893	VSUBUQM RED2, RED3, RED2     // Guaranteed not to underflow	// VSQ
   894
   895	VSLDOI $12, T1, T0, T0 // VSLDB
   896	VSLDOI $12, T2, T1, T1 // VSLDB
   897
   898	VADDCUQ  T0, ADD3H, CAR1     // VACCQ
   899	VADDUQM  T0, ADD3H, T0       // VAQ
   900	VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
   901	VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
   902
   903	// ---------------------------------------------------
   904
   905	VSPLTW $3, Y1, YDIG                // VREPF
   906
   907	//	VMALHF X0, YDIG, T0, ADD1H
   908	//	VMALHF X1, YDIG, T1, ADD2H
   909	//	VMALF  X0, YDIG, T0, ADD1
   910	//	VMALF  X1, YDIG, T1, ADD2
   911	VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
   912	VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
   913
   914	VSPLTW $2, Y1, YDIG // VREPF
   915
   916	//	VMALF  X0, YDIG, ADD1H, ADD3
   917	//	VMALF  X1, YDIG, ADD2H, ADD4
   918	//	VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
   919	//	VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
   920	VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
   921	VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
   922
   923	LXVD2X   (R17)(CPOOL), SEL1
   924	VSPLTISB $0, ZER               // VZERO ZER
   925	LXVD2X   (R17)(CPOOL), SEL1
   926	VPERM    ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
   927
   928	VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free		// VSLDB
   929	VSLDOI $12, T2, ADD2, T1   // ADD2 Free		// VSLDB
   930
   931	VADDCUQ  T0, RED1, CAR1     // VACCQ
   932	VADDUQM  T0, RED1, T0       // VAQ
   933	VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
   934	VADDEUQM T1, RED2, CAR1, T1 // VACQ
   935
   936	VADDCUQ  T0, ADD3, CAR1       // VACCQ
   937	VADDUQM  T0, ADD3, T0         // VAQ
   938	VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
   939	VADDEUQM T1, ADD4, CAR1, T1   // VACQ
   940	VADDUQM  T2, CAR2, T2         // VAQ
   941
   942	LXVD2X  (R18)(CPOOL), SEL2
   943	LXVD2X  (R19)(CPOOL), SEL3
   944	LXVD2X  (R20)(CPOOL), SEL4
   945	VPERM   RED3, T0, SEL2, RED1 // [d0  0 d1 d0]
   946	VPERM   RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
   947	VPERM   RED3, T0, SEL4, RED3 // [ 0  0 d1 d0]
   948	VSUBUQM RED2, RED3, RED2     // Guaranteed not to underflow	// VSQ
   949
   950	VSLDOI $12, T1, T0, T0 // VSLDB
   951	VSLDOI $12, T2, T1, T1 // VSLDB
   952
   953	VADDCUQ  T0, ADD3H, CAR1     // VACCQ
   954	VADDUQM  T0, ADD3H, T0       // VAQ
   955	VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
   956	VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
   957
   958	// ---------------------------------------------------
   959
   960	VSPLTW $1, Y1, YDIG                // VREPF
   961
   962	//	VMALHF X0, YDIG, T0, ADD1H
   963	//	VMALHF X1, YDIG, T1, ADD2H
   964	//	VMALF  X0, YDIG, T0, ADD1
   965	//	VMALF  X1, YDIG, T1, ADD2
   966	VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
   967	VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
   968
   969	VSPLTW $0, Y1, YDIG // VREPF
   970
   971	//	VMALF  X0, YDIG, ADD1H, ADD3
   972	//	VMALF  X1, YDIG, ADD2H, ADD4
   973	//	VMALHF X0, YDIG, ADD1H, ADD3H
   974	//	VMALHF X1, YDIG, ADD2H, ADD4H
   975	VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
   976	VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
   977
   978	VSPLTISB $0, ZER               // VZERO ZER
   979	LXVD2X   (R17)(CPOOL), SEL1
   980	VPERM    ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
   981
   982	VSLDOI $12, ADD2, ADD1, T0 // VSLDB
   983	VSLDOI $12, T2, ADD2, T1   // VSLDB
   984
   985	VADDCUQ  T0, RED1, CAR1     // VACCQ
   986	VADDUQM  T0, RED1, T0       // VAQ
   987	VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
   988	VADDEUQM T1, RED2, CAR1, T1 // VACQ
   989
   990	VADDCUQ  T0, ADD3, CAR1       // VACCQ
   991	VADDUQM  T0, ADD3, T0         // VAQ
   992	VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
   993	VADDEUQM T1, ADD4, CAR1, T1   // VACQ
   994	VADDUQM  T2, CAR2, T2         // VAQ
   995
   996	LXVD2X  (R21)(CPOOL), SEL5
   997	LXVD2X  (R22)(CPOOL), SEL6
   998	VPERM   T0, RED3, SEL5, RED2 // [d1 d0 d1 d0]
   999	VPERM   T0, RED3, SEL6, RED1 // [ 0 d1 d0  0]
  1000	VSUBUQM RED2, RED1, RED2     // Guaranteed not to underflow	// VSQ
  1001
  1002	VSLDOI $12, T1, T0, T0 // VSLDB
  1003	VSLDOI $12, T2, T1, T1 // VSLDB
  1004
  1005	VADDCUQ  T0, ADD3H, CAR1     // VACCQ
  1006	VADDUQM  T0, ADD3H, T0       // VAQ
  1007	VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
  1008	VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
  1009
  1010	VADDCUQ  T0, RED1, CAR1       // VACCQ
  1011	VADDUQM  T0, RED1, T0         // VAQ
  1012	VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ
  1013	VADDEUQM T1, RED2, CAR1, T1   // VACQ
  1014	VADDUQM  T2, CAR2, T2         // VAQ
  1015
  1016	// ---------------------------------------------------
  1017
  1018	VSPLTISB $0, RED3            // VZERO   RED3
  1019	VSUBCUQ  T0, P0, CAR1        // VSCBIQ
  1020	VSUBUQM  T0, P0, ADD1H       // VSQ
  1021	VSUBECUQ T1, P1, CAR1, CAR2  // VSBCBIQ
  1022	VSUBEUQM T1, P1, CAR1, ADD2H // VSBIQ
  1023	VSUBEUQM T2, RED3, CAR2, T2  // VSBIQ
  1024
  1025	// what output to use, ADD2H||ADD1H or T1||T0?
  1026	VSEL ADD1H, T0, T2, T0
  1027	VSEL ADD2H, T1, T2, T1
  1028	RET
  1029
  1030#undef CPOOL
  1031
  1032#undef X0
  1033#undef X1
  1034#undef Y0
  1035#undef Y1
  1036#undef T0
  1037#undef T1
  1038#undef P0
  1039#undef P1
  1040
  1041#undef SEL1
  1042#undef SEL2
  1043#undef SEL3
  1044#undef SEL4
  1045#undef SEL5
  1046#undef SEL6
  1047
  1048#undef YDIG
  1049#undef ADD1H
  1050#undef ADD2H
  1051#undef ADD3
  1052#undef ADD4
  1053#undef RED1
  1054#undef RED2
  1055#undef RED3
  1056#undef T2
  1057#undef ADD1
  1058#undef ADD2
  1059#undef ADD3H
  1060#undef ADD4H
  1061#undef ZER
  1062#undef CAR1
  1063#undef CAR2
  1064
  1065#undef TMP1
  1066#undef TMP2
  1067
  1068#define p256SubInternal(T1, T0, X1, X0, Y1, Y0) \
  1069	VSPLTISB $0, ZER            \ // VZERO
  1070	VSUBCUQ  X0, Y0, CAR1       \
  1071	VSUBUQM  X0, Y0, T0         \
  1072	VSUBECUQ X1, Y1, CAR1, SEL1 \
  1073	VSUBEUQM X1, Y1, CAR1, T1   \
  1074	VSUBUQM  ZER, SEL1, SEL1    \ // VSQ
  1075	                            \
  1076	VADDCUQ  T0, PL, CAR1       \ // VACCQ
  1077	VADDUQM  T0, PL, TT0        \ // VAQ
  1078	VADDEUQM T1, PH, CAR1, TT1  \ // VACQ
  1079	                            \
  1080	VSEL     TT0, T0, SEL1, T0  \
  1081	VSEL     TT1, T1, SEL1, T1  \
  1082
  1083#define p256AddInternal(T1, T0, X1, X0, Y1, Y0) \
  1084	VADDCUQ  X0, Y0, CAR1        \
  1085	VADDUQM  X0, Y0, T0          \
  1086	VADDECUQ X1, Y1, CAR1, T2    \ // VACCCQ
  1087	VADDEUQM X1, Y1, CAR1, T1    \
  1088	                             \
  1089	VSPLTISB $0, ZER             \
  1090	VSUBCUQ  T0, PL, CAR1        \ // VSCBIQ
  1091	VSUBUQM  T0, PL, TT0         \
  1092	VSUBECUQ T1, PH, CAR1, CAR2  \ // VSBCBIQ
  1093	VSUBEUQM T1, PH, CAR1, TT1   \ // VSBIQ
  1094	VSUBEUQM T2, ZER, CAR2, SEL1 \
  1095	                             \
  1096	VSEL     TT0, T0, SEL1, T0   \
  1097	VSEL     TT1, T1, SEL1, T1
  1098
  1099#define p256HalfInternal(T1, T0, X1, X0) \
  1100	VSPLTISB $0, ZER            \
  1101	VSUBEUQM ZER, ZER, X0, SEL1 \
  1102	                            \
  1103	VADDCUQ  X0, PL, CAR1       \
  1104	VADDUQM  X0, PL, T0         \
  1105	VADDECUQ X1, PH, CAR1, T2   \
  1106	VADDEUQM X1, PH, CAR1, T1   \
  1107	                            \
  1108	VSEL     T0, X0, SEL1, T0   \
  1109	VSEL     T1, X1, SEL1, T1   \
  1110	VSEL     T2, ZER, SEL1, T2  \
  1111	                            \
  1112	VSLDOI   $15, T2, ZER, TT1  \
  1113	VSLDOI   $15, T1, ZER, TT0  \
  1114	VSPLTISB $1, SEL1           \
  1115	VSR      T0, SEL1, T0       \ // VSRL
  1116	VSR      T1, SEL1, T1       \
  1117	VSPLTISB $7, SEL1           \ // VREPIB
  1118	VSL      TT0, SEL1, TT0     \
  1119	VSL      TT1, SEL1, TT1     \
  1120	VOR      T0, TT0, T0        \
  1121	VOR      T1, TT1, T1
  1122
  1123#define res_ptr R3
  1124#define x_ptr   R4
  1125#define y_ptr   R5
  1126#define CPOOL   R7
  1127#define TEMP    R8
  1128#define N       R9
  1129
  1130// Parameters
  1131#define X0    V0
  1132#define X1    V1
  1133#define Y0    V2
  1134#define Y1    V3
  1135#define T0    V4
  1136#define T1    V5
  1137
  1138// Constants
  1139#define P0    V30
  1140#define P1    V31
  1141// func p256MulAsm(res, in1, in2 *p256Element)
  1142TEXT ·p256Mul(SB), NOSPLIT, $0-24
  1143	MOVD res+0(FP), res_ptr
  1144	MOVD in1+8(FP), x_ptr
  1145	MOVD in2+16(FP), y_ptr
  1146	MOVD $16, R16
  1147	MOVD $32, R17
  1148
  1149	MOVD $p256mul<>+0x00(SB), CPOOL
  1150
  1151
  1152	LXVD2X (R0)(x_ptr), X0
  1153	LXVD2X (R16)(x_ptr), X1
  1154
  1155	XXPERMDI X0, X0, $2, X0
  1156	XXPERMDI X1, X1, $2, X1
  1157
  1158	LXVD2X (R0)(y_ptr), Y0
  1159	LXVD2X (R16)(y_ptr), Y1
  1160
  1161	XXPERMDI Y0, Y0, $2, Y0
  1162	XXPERMDI Y1, Y1, $2, Y1
  1163
  1164	LXVD2X (R16)(CPOOL), P1
  1165	LXVD2X (R0)(CPOOL), P0
  1166
  1167	CALL p256MulInternal<>(SB)
  1168
  1169	MOVD $p256mul<>+0x00(SB), CPOOL
  1170
  1171	XXPERMDI T0, T0, $2, T0
  1172	XXPERMDI T1, T1, $2, T1
  1173	STXVD2X T0, (R0)(res_ptr)
  1174	STXVD2X T1, (R16)(res_ptr)
  1175	RET
  1176
  1177// func p256Sqr(res, in *p256Element, n int)
  1178TEXT ·p256Sqr(SB), NOSPLIT, $0-24
  1179	MOVD res+0(FP), res_ptr
  1180	MOVD in+8(FP), x_ptr
  1181	MOVD $16, R16
  1182	MOVD $32, R17
  1183
  1184	MOVD $p256mul<>+0x00(SB), CPOOL
  1185
  1186	LXVD2X (R0)(x_ptr), X0
  1187	LXVD2X (R16)(x_ptr), X1
  1188
  1189	XXPERMDI X0, X0, $2, X0
  1190	XXPERMDI X1, X1, $2, X1
  1191
  1192sqrLoop:
  1193	// Sqr uses same value for both
  1194
  1195	VOR	X0, X0, Y0
  1196	VOR	X1, X1, Y1
  1197
  1198	LXVD2X (R16)(CPOOL), P1
  1199	LXVD2X (R0)(CPOOL), P0
  1200
  1201	CALL p256MulInternal<>(SB)
  1202
  1203	MOVD	n+16(FP), N
  1204	ADD	$-1, N
  1205	CMP	$0, N
  1206	BEQ	done
  1207	MOVD	N, n+16(FP)	// Save counter to avoid clobber
  1208	VOR	T0, T0, X0
  1209	VOR	T1, T1, X1
  1210	BR	sqrLoop
  1211
  1212done:
  1213	MOVD $p256mul<>+0x00(SB), CPOOL
  1214
  1215	XXPERMDI T0, T0, $2, T0
  1216	XXPERMDI T1, T1, $2, T1
  1217	STXVD2X T0, (R0)(res_ptr)
  1218	STXVD2X T1, (R16)(res_ptr)
  1219	RET
  1220
  1221#undef res_ptr
  1222#undef x_ptr
  1223#undef y_ptr
  1224#undef CPOOL
  1225
  1226#undef X0
  1227#undef X1
  1228#undef Y0
  1229#undef Y1
  1230#undef T0
  1231#undef T1
  1232#undef P0
  1233#undef P1
  1234
  1235#define P3ptr   R3
  1236#define P1ptr   R4
  1237#define P2ptr   R5
  1238#define CPOOL   R7
  1239
  1240// Temporaries in REGs
  1241#define Y2L    V15
  1242#define Y2H    V16
  1243#define T1L    V17
  1244#define T1H    V18
  1245#define T2L    V19
  1246#define T2H    V20
  1247#define T3L    V21
  1248#define T3H    V22
  1249#define T4L    V23
  1250#define T4H    V24
  1251
  1252// Temps for Sub and Add
  1253#define TT0  V11
  1254#define TT1  V12
  1255#define T2   V13
  1256
  1257// p256MulAsm Parameters
  1258#define X0    V0
  1259#define X1    V1
  1260#define Y0    V2
  1261#define Y1    V3
  1262#define T0    V4
  1263#define T1    V5
  1264
  1265#define PL    V30
  1266#define PH    V31
  1267
  1268// Names for zero/sel selects
  1269#define X1L    V0
  1270#define X1H    V1
  1271#define Y1L    V2 // p256MulAsmParmY
  1272#define Y1H    V3 // p256MulAsmParmY
  1273#define Z1L    V4
  1274#define Z1H    V5
  1275#define X2L    V0
  1276#define X2H    V1
  1277#define Z2L    V4
  1278#define Z2H    V5
  1279#define X3L    V17 // T1L
  1280#define X3H    V18 // T1H
  1281#define Y3L    V21 // T3L
  1282#define Y3H    V22 // T3H
  1283#define Z3L    V25
  1284#define Z3H    V26
  1285
  1286#define ZER   V6
  1287#define SEL1  V7
  1288#define CAR1  V8
  1289#define CAR2  V9
  1290/* *
  1291 * Three operand formula:
  1292 * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
  1293 * T1 = Z1²
  1294 * T2 = T1*Z1
  1295 * T1 = T1*X2
  1296 * T2 = T2*Y2
  1297 * T1 = T1-X1
  1298 * T2 = T2-Y1
  1299 * Z3 = Z1*T1
  1300 * T3 = T1²
  1301 * T4 = T3*T1
  1302 * T3 = T3*X1
  1303 * T1 = 2*T3
  1304 * X3 = T2²
  1305 * X3 = X3-T1
  1306 * X3 = X3-T4
  1307 * T3 = T3-X3
  1308 * T3 = T3*T2
  1309 * T4 = T4*Y1
  1310 * Y3 = T3-T4
  1311
  1312 * Three operand formulas, but with MulInternal X,Y used to store temps
  1313X=Z1; Y=Z1; MUL;T-   // T1 = Z1²      T1
  1314X=T ; Y-  ; MUL;T2=T // T2 = T1*Z1    T1   T2
  1315X-  ; Y=X2; MUL;T1=T // T1 = T1*X2    T1   T2
  1316X=T2; Y=Y2; MUL;T-   // T2 = T2*Y2    T1   T2
  1317SUB(T2<T-Y1)         // T2 = T2-Y1    T1   T2
  1318SUB(Y<T1-X1)         // T1 = T1-X1    T1   T2
  1319X=Z1; Y- ;  MUL;Z3:=T// Z3 = Z1*T1         T2
  1320X=Y;  Y- ;  MUL;X=T  // T3 = T1*T1         T2
  1321X- ;  Y- ;  MUL;T4=T // T4 = T3*T1         T2        T4
  1322X- ;  Y=X1; MUL;T3=T // T3 = T3*X1         T2   T3   T4
  1323ADD(T1<T+T)          // T1 = T3+T3    T1   T2   T3   T4
  1324X=T2; Y=T2; MUL;T-   // X3 = T2*T2    T1   T2   T3   T4
  1325SUB(T<T-T1)          // X3 = X3-T1    T1   T2   T3   T4
  1326SUB(T<T-T4) X3:=T    // X3 = X3-T4         T2   T3   T4
  1327SUB(X<T3-T)          // T3 = T3-X3         T2   T3   T4
  1328X- ;  Y- ;  MUL;T3=T // T3 = T3*T2         T2   T3   T4
  1329X=T4; Y=Y1; MUL;T-   // T4 = T4*Y1              T3   T4
  1330SUB(T<T3-T) Y3:=T    // Y3 = T3-T4              T3   T4
  1331
  1332	*/
  1333//
  1334// V27 is clobbered by p256MulInternal so must be
  1335// saved in a temp.
  1336//
  1337// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
  1338TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $16-48
  1339	MOVD res+0(FP), P3ptr
  1340	MOVD in1+8(FP), P1ptr
  1341	MOVD in2+16(FP), P2ptr
  1342
  1343	MOVD $p256mul<>+0x00(SB), CPOOL
  1344
  1345	MOVD $16, R16
  1346	MOVD $32, R17
  1347	MOVD $48, R18
  1348	MOVD $64, R19
  1349	MOVD $80, R20
  1350	MOVD $96, R21
  1351	MOVD $112, R22
  1352	MOVD $128, R23
  1353	MOVD $144, R24
  1354	MOVD $160, R25
  1355	MOVD $104, R26 // offset of sign+24(FP)
  1356
  1357	LXVD2X (R16)(CPOOL), PH
  1358	LXVD2X (R0)(CPOOL), PL
  1359
  1360	LXVD2X (R17)(P2ptr), Y2L
  1361	LXVD2X (R18)(P2ptr), Y2H
  1362	XXPERMDI Y2H, Y2H, $2, Y2H
  1363	XXPERMDI Y2L, Y2L, $2, Y2L
  1364
  1365	// Equivalent of VLREPG sign+24(FP), SEL1
  1366	LXVDSX   (R1)(R26), SEL1
  1367	VSPLTISB $0, ZER
  1368	VCMPEQUD SEL1, ZER, SEL1
  1369
  1370	VSUBCUQ  PL, Y2L, CAR1
  1371	VSUBUQM  PL, Y2L, T1L
  1372	VSUBEUQM PH, Y2H, CAR1, T1H
  1373
  1374	VSEL T1L, Y2L, SEL1, Y2L
  1375	VSEL T1H, Y2H, SEL1, Y2H
  1376
  1377/* *
  1378 * Three operand formula:
  1379 * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
  1380 */
  1381	// X=Z1; Y=Z1; MUL; T-   // T1 = Z1²      T1
  1382	LXVD2X (R19)(P1ptr), X0     // Z1H
  1383	LXVD2X (R20)(P1ptr), X1     // Z1L
  1384	XXPERMDI X0, X0, $2, X0
  1385	XXPERMDI X1, X1, $2, X1
  1386	VOR    X0, X0, Y0
  1387	VOR    X1, X1, Y1
  1388	CALL   p256MulInternal<>(SB)
  1389
  1390	// X=T ; Y-  ; MUL; T2=T // T2 = T1*Z1    T1   T2
  1391	VOR  T0, T0, X0
  1392	VOR  T1, T1, X1
  1393	CALL p256MulInternal<>(SB)
  1394	VOR  T0, T0, T2L
  1395	VOR  T1, T1, T2H
  1396
  1397	// X-  ; Y=X2; MUL; T1=T // T1 = T1*X2    T1   T2
  1398	MOVD   in2+16(FP), P2ptr
  1399	LXVD2X (R0)(P2ptr), Y0      // X2H
  1400	LXVD2X (R16)(P2ptr), Y1     // X2L
  1401	XXPERMDI Y0, Y0, $2, Y0
  1402	XXPERMDI Y1, Y1, $2, Y1
  1403	CALL   p256MulInternal<>(SB)
  1404	VOR    T0, T0, T1L
  1405	VOR    T1, T1, T1H
  1406
  1407	// X=T2; Y=Y2; MUL; T-   // T2 = T2*Y2    T1   T2
  1408	VOR  T2L, T2L, X0
  1409	VOR  T2H, T2H, X1
  1410	VOR  Y2L, Y2L, Y0
  1411	VOR  Y2H, Y2H, Y1
  1412	CALL p256MulInternal<>(SB)
  1413
  1414	// SUB(T2<T-Y1)          // T2 = T2-Y1    T1   T2
  1415	MOVD   in1+8(FP), P1ptr
  1416	LXVD2X (R17)(P1ptr), Y1L
  1417	LXVD2X (R18)(P1ptr), Y1H
  1418	XXPERMDI Y1H, Y1H, $2, Y1H
  1419	XXPERMDI Y1L, Y1L, $2, Y1L
  1420	p256SubInternal(T2H,T2L,T1,T0,Y1H,Y1L)
  1421
  1422	// SUB(Y<T1-X1)          // T1 = T1-X1    T1   T2
  1423	LXVD2X (R0)(P1ptr), X1L
  1424	LXVD2X (R16)(P1ptr), X1H
  1425	XXPERMDI X1H, X1H, $2, X1H
  1426	XXPERMDI X1L, X1L, $2, X1L
  1427	p256SubInternal(Y1,Y0,T1H,T1L,X1H,X1L)
  1428
  1429	// X=Z1; Y- ;  MUL; Z3:=T// Z3 = Z1*T1         T2
  1430	LXVD2X (R19)(P1ptr), X0     // Z1H
  1431	LXVD2X (R20)(P1ptr), X1     // Z1L
  1432	XXPERMDI X0, X0, $2, X0
  1433	XXPERMDI X1, X1, $2, X1
  1434	CALL   p256MulInternal<>(SB)
  1435
  1436	VOR T0, T0, Z3L
  1437	VOR T1, T1, Z3H
  1438
  1439	// X=Y;  Y- ;  MUL; X=T  // T3 = T1*T1         T2
  1440	VOR  Y0, Y0, X0
  1441	VOR  Y1, Y1, X1
  1442	CALL p256MulInternal<>(SB)
  1443	VOR  T0, T0, X0
  1444	VOR  T1, T1, X1
  1445
  1446	// X- ;  Y- ;  MUL; T4=T // T4 = T3*T1         T2        T4
  1447	CALL p256MulInternal<>(SB)
  1448	VOR  T0, T0, T4L
  1449	VOR  T1, T1, T4H
  1450
  1451	// X- ;  Y=X1; MUL; T3=T // T3 = T3*X1         T2   T3   T4
  1452	MOVD   in1+8(FP), P1ptr
  1453	LXVD2X (R0)(P1ptr), Y0      // X1H
  1454	LXVD2X (R16)(P1ptr), Y1     // X1L
  1455	XXPERMDI Y1, Y1, $2, Y1
  1456	XXPERMDI Y0, Y0, $2, Y0
  1457	CALL   p256MulInternal<>(SB)
  1458	VOR    T0, T0, T3L
  1459	VOR    T1, T1, T3H
  1460
  1461	// ADD(T1<T+T)           // T1 = T3+T3    T1   T2   T3   T4
  1462	p256AddInternal(T1H,T1L, T1,T0,T1,T0)
  1463
  1464	// X=T2; Y=T2; MUL; T-   // X3 = T2*T2    T1   T2   T3   T4
  1465	VOR  T2L, T2L, X0
  1466	VOR  T2H, T2H, X1
  1467	VOR  T2L, T2L, Y0
  1468	VOR  T2H, T2H, Y1
  1469	CALL p256MulInternal<>(SB)
  1470
  1471	// SUB(T<T-T1)           // X3 = X3-T1    T1   T2   T3   T4  (T1 = X3)
  1472	p256SubInternal(T1,T0,T1,T0,T1H,T1L)
  1473
  1474	// SUB(T<T-T4) X3:=T     // X3 = X3-T4         T2   T3   T4
  1475	p256SubInternal(T1,T0,T1,T0,T4H,T4L)
  1476	VOR T0, T0, X3L
  1477	VOR T1, T1, X3H
  1478
  1479	// SUB(X<T3-T)           // T3 = T3-X3         T2   T3   T4
  1480	p256SubInternal(X1,X0,T3H,T3L,T1,T0)
  1481
  1482	// X- ;  Y- ;  MUL; T3=T // T3 = T3*T2         T2   T3   T4
  1483	CALL p256MulInternal<>(SB)
  1484	VOR  T0, T0, T3L
  1485	VOR  T1, T1, T3H
  1486
  1487	// X=T4; Y=Y1; MUL; T-   // T4 = T4*Y1              T3   T4
  1488	VOR    T4L, T4L, X0
  1489	VOR    T4H, T4H, X1
  1490	MOVD   in1+8(FP), P1ptr
  1491	LXVD2X (R17)(P1ptr), Y0     // Y1H
  1492	LXVD2X (R18)(P1ptr), Y1     // Y1L
  1493	XXPERMDI Y0, Y0, $2, Y0
  1494	XXPERMDI Y1, Y1, $2, Y1
  1495	CALL   p256MulInternal<>(SB)
  1496
  1497	// SUB(T<T3-T) Y3:=T     // Y3 = T3-T4              T3   T4  (T3 = Y3)
  1498	p256SubInternal(Y3H,Y3L,T3H,T3L,T1,T0)
  1499
  1500	//	if (sel == 0) {
  1501	//		copy(P3.x[:], X1)
  1502	//		copy(P3.y[:], Y1)
  1503	//		copy(P3.z[:], Z1)
  1504	//	}
  1505
  1506	LXVD2X (R0)(P1ptr), X1L
  1507	LXVD2X (R16)(P1ptr), X1H
  1508	XXPERMDI X1H, X1H, $2, X1H
  1509	XXPERMDI X1L, X1L, $2, X1L
  1510
  1511	// Y1 already loaded, left over from addition
  1512	LXVD2X (R19)(P1ptr), Z1L
  1513	LXVD2X (R20)(P1ptr), Z1H
  1514	XXPERMDI Z1H, Z1H, $2, Z1H
  1515	XXPERMDI Z1L, Z1L, $2, Z1L
  1516
  1517	MOVD     $112, R26        // Get offset to sel+32
  1518	LXVDSX   (R1)(R26), SEL1
  1519	VSPLTISB $0, ZER
  1520	VCMPEQUD SEL1, ZER, SEL1
  1521
  1522	VSEL X3L, X1L, SEL1, X3L
  1523	VSEL X3H, X1H, SEL1, X3H
  1524	VSEL Y3L, Y1L, SEL1, Y3L
  1525	VSEL Y3H, Y1H, SEL1, Y3H
  1526	VSEL Z3L, Z1L, SEL1, Z3L
  1527	VSEL Z3H, Z1H, SEL1, Z3H
  1528
  1529	MOVD   in2+16(FP), P2ptr
  1530	LXVD2X (R0)(P2ptr), X2L
  1531	LXVD2X (R16)(P2ptr), X2H
  1532	XXPERMDI X2H, X2H, $2, X2H
  1533	XXPERMDI X2L, X2L, $2, X2L
  1534
  1535	// Y2 already loaded
  1536	LXVD2X (R23)(CPOOL), Z2L
  1537	LXVD2X (R24)(CPOOL), Z2H
  1538
  1539	MOVD     $120, R26        // Get the value from zero+40(FP)
  1540	LXVDSX   (R1)(R26), SEL1
  1541	VSPLTISB $0, ZER
  1542	VCMPEQUD SEL1, ZER, SEL1
  1543
  1544	VSEL X3L, X2L, SEL1, X3L
  1545	VSEL X3H, X2H, SEL1, X3H
  1546	VSEL Y3L, Y2L, SEL1, Y3L
  1547	VSEL Y3H, Y2H, SEL1, Y3H
  1548	VSEL Z3L, Z2L, SEL1, Z3L
  1549	VSEL Z3H, Z2H, SEL1, Z3H
  1550
  1551	// Reorder the bytes so they can be stored using STXVD2X.
  1552	MOVD    res+0(FP), P3ptr
  1553	XXPERMDI X3H, X3H, $2, X3H
  1554	XXPERMDI X3L, X3L, $2, X3L
  1555	XXPERMDI Y3H, Y3H, $2, Y3H
  1556	XXPERMDI Y3L, Y3L, $2, Y3L
  1557	XXPERMDI Z3H, Z3H, $2, Z3H
  1558	XXPERMDI Z3L, Z3L, $2, Z3L
  1559	STXVD2X X3L, (R0)(P3ptr)
  1560	STXVD2X X3H, (R16)(P3ptr)
  1561	STXVD2X Y3L, (R17)(P3ptr)
  1562	STXVD2X Y3H, (R18)(P3ptr)
  1563	STXVD2X Z3L, (R19)(P3ptr)
  1564	STXVD2X Z3H, (R20)(P3ptr)
  1565
  1566	RET
  1567
  1568#undef P3ptr
  1569#undef P1ptr
  1570#undef P2ptr
  1571#undef CPOOL
  1572
  1573#undef Y2L
  1574#undef Y2H
  1575#undef T1L
  1576#undef T1H
  1577#undef T2L
  1578#undef T2H
  1579#undef T3L
  1580#undef T3H
  1581#undef T4L
  1582#undef T4H
  1583
  1584#undef TT0
  1585#undef TT1
  1586#undef T2
  1587
  1588#undef X0
  1589#undef X1
  1590#undef Y0
  1591#undef Y1
  1592#undef T0
  1593#undef T1
  1594
  1595#undef PL
  1596#undef PH
  1597
  1598#undef X1L
  1599#undef X1H
  1600#undef Y1L
  1601#undef Y1H
  1602#undef Z1L
  1603#undef Z1H
  1604#undef X2L
  1605#undef X2H
  1606#undef Z2L
  1607#undef Z2H
  1608#undef X3L
  1609#undef X3H
  1610#undef Y3L
  1611#undef Y3H
  1612#undef Z3L
  1613#undef Z3H
  1614
  1615#undef ZER
  1616#undef SEL1
  1617#undef CAR1
  1618#undef CAR2
  1619
  1620// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
  1621// http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
  1622// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
  1623#define P3ptr   R3
  1624#define P1ptr   R4
  1625#define CPOOL   R7
  1626
  1627// Temporaries in REGs
  1628#define X3L    V15
  1629#define X3H    V16
  1630#define Y3L    V17
  1631#define Y3H    V18
  1632#define T1L    V19
  1633#define T1H    V20
  1634#define T2L    V21
  1635#define T2H    V22
  1636#define T3L    V23
  1637#define T3H    V24
  1638
  1639#define X1L    V6
  1640#define X1H    V7
  1641#define Y1L    V8
  1642#define Y1H    V9
  1643#define Z1L    V10
  1644#define Z1H    V11
  1645
  1646// Temps for Sub and Add
  1647#define TT0  V11
  1648#define TT1  V12
  1649#define T2   V13
  1650
  1651// p256MulAsm Parameters
  1652#define X0    V0
  1653#define X1    V1
  1654#define Y0    V2
  1655#define Y1    V3
  1656#define T0    V4
  1657#define T1    V5
  1658
  1659#define PL    V30
  1660#define PH    V31
  1661
  1662#define Z3L    V23
  1663#define Z3H    V24
  1664
  1665#define ZER   V26
  1666#define SEL1  V27
  1667#define CAR1  V28
  1668#define CAR2  V29
  1669/*
  1670 * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv
  1671 * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3.
  1672 * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
  1673 * 	A  = 3(X₁-Z₁²)×(X₁+Z₁²)
  1674 * 	B  = 2Y₁
  1675 * 	Z₃ = B×Z₁
  1676 * 	C  = B²
  1677 * 	D  = C×X₁
  1678 * 	X₃ = A²-2D
  1679 * 	Y₃ = (D-X₃)×A-C²/2
  1680 *
  1681 * Three-operand formula:
  1682 *       T1 = Z1²
  1683 *       T2 = X1-T1
  1684 *       T1 = X1+T1
  1685 *       T2 = T2*T1
  1686 *       T2 = 3*T2
  1687 *       Y3 = 2*Y1
  1688 *       Z3 = Y3*Z1
  1689 *       Y3 = Y3²
  1690 *       T3 = Y3*X1
  1691 *       Y3 = Y3²
  1692 *       Y3 = half*Y3
  1693 *       X3 = T2²
  1694 *       T1 = 2*T3
  1695 *       X3 = X3-T1
  1696 *       T1 = T3-X3
  1697 *       T1 = T1*T2
  1698 *       Y3 = T1-Y3
  1699 */
  1700// p256PointDoubleAsm(res, in1 *p256Point)
  1701TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0-16
  1702	MOVD res+0(FP), P3ptr
  1703	MOVD in+8(FP), P1ptr
  1704
  1705	MOVD $p256mul<>+0x00(SB), CPOOL
  1706
  1707	MOVD $16, R16
  1708	MOVD $32, R17
  1709	MOVD $48, R18
  1710	MOVD $64, R19
  1711	MOVD $80, R20
  1712
  1713	LXVD2X (R16)(CPOOL), PH
  1714	LXVD2X (R0)(CPOOL), PL
  1715
  1716	// X=Z1; Y=Z1; MUL; T-    // T1 = Z1²
  1717	LXVD2X (R19)(P1ptr), X0 // Z1H
  1718	LXVD2X (R20)(P1ptr), X1 // Z1L
  1719
  1720	XXPERMDI X0, X0, $2, X0
  1721	XXPERMDI X1, X1, $2, X1
  1722
  1723	VOR  X0, X0, Y0
  1724	VOR  X1, X1, Y1
  1725	CALL p256MulInternal<>(SB)
  1726
  1727	// SUB(X<X1-T)            // T2 = X1-T1
  1728	LXVD2X (R0)(P1ptr), X1L
  1729	LXVD2X (R16)(P1ptr), X1H
  1730	XXPERMDI X1L, X1L, $2, X1L
  1731	XXPERMDI X1H, X1H, $2, X1H
  1732
  1733	p256SubInternal(X1,X0,X1H,X1L,T1,T0)
  1734
  1735	// ADD(Y<X1+T)            // T1 = X1+T1
  1736	p256AddInternal(Y1,Y0,X1H,X1L,T1,T0)
  1737
  1738	// X-  ; Y-  ; MUL; T-    // T2 = T2*T1
  1739	CALL p256MulInternal<>(SB)
  1740
  1741	// ADD(T2<T+T); ADD(T2<T2+T)  // T2 = 3*T2
  1742	p256AddInternal(T2H,T2L,T1,T0,T1,T0)
  1743	p256AddInternal(T2H,T2L,T2H,T2L,T1,T0)
  1744
  1745	// ADD(X<Y1+Y1)           // Y3 = 2*Y1
  1746	LXVD2X (R17)(P1ptr), Y1L
  1747	LXVD2X (R18)(P1ptr), Y1H
  1748	XXPERMDI Y1L, Y1L, $2, Y1L
  1749	XXPERMDI Y1H, Y1H, $2, Y1H
  1750
  1751	p256AddInternal(X1,X0,Y1H,Y1L,Y1H,Y1L)
  1752
  1753	// X-  ; Y=Z1; MUL; Z3:=T // Z3 = Y3*Z1
  1754	LXVD2X (R19)(P1ptr), Y0
  1755	LXVD2X (R20)(P1ptr), Y1
  1756	XXPERMDI Y0, Y0, $2, Y0
  1757	XXPERMDI Y1, Y1, $2, Y1
  1758
  1759	CALL p256MulInternal<>(SB)
  1760
  1761	// Leave T0, T1 as is.
  1762	XXPERMDI T0, T0, $2, TT0
  1763	XXPERMDI T1, T1, $2, TT1
  1764	STXVD2X TT0, (R19)(P3ptr)
  1765	STXVD2X TT1, (R20)(P3ptr)
  1766
  1767	// X-  ; Y=X ; MUL; T-    // Y3 = Y3²
  1768	VOR  X0, X0, Y0
  1769	VOR  X1, X1, Y1
  1770	CALL p256MulInternal<>(SB)
  1771
  1772	// X=T ; Y=X1; MUL; T3=T  // T3 = Y3*X1
  1773	VOR    T0, T0, X0
  1774	VOR    T1, T1, X1
  1775	LXVD2X (R0)(P1ptr), Y0
  1776	LXVD2X (R16)(P1ptr), Y1
  1777	XXPERMDI Y0, Y0, $2, Y0
  1778	XXPERMDI Y1, Y1, $2, Y1
  1779	CALL   p256MulInternal<>(SB)
  1780	VOR    T0, T0, T3L
  1781	VOR    T1, T1, T3H
  1782
  1783	// X-  ; Y=X ; MUL; T-    // Y3 = Y3²
  1784	VOR  X0, X0, Y0
  1785	VOR  X1, X1, Y1
  1786	CALL p256MulInternal<>(SB)
  1787
  1788	// HAL(Y3<T)              // Y3 = half*Y3
  1789	p256HalfInternal(Y3H,Y3L, T1,T0)
  1790
  1791	// X=T2; Y=T2; MUL; T-    // X3 = T2²
  1792	VOR  T2L, T2L, X0
  1793	VOR  T2H, T2H, X1
  1794	VOR  T2L, T2L, Y0
  1795	VOR  T2H, T2H, Y1
  1796	CALL p256MulInternal<>(SB)
  1797
  1798	// ADD(T1<T3+T3)          // T1 = 2*T3
  1799	p256AddInternal(T1H,T1L,T3H,T3L,T3H,T3L)
  1800
  1801	// SUB(X3<T-T1) X3:=X3    // X3 = X3-T1
  1802	p256SubInternal(X3H,X3L,T1,T0,T1H,T1L)
  1803
  1804	XXPERMDI X3L, X3L, $2, TT0
  1805	XXPERMDI X3H, X3H, $2, TT1
  1806	STXVD2X TT0, (R0)(P3ptr)
  1807	STXVD2X TT1, (R16)(P3ptr)
  1808
  1809	// SUB(X<T3-X3)           // T1 = T3-X3
  1810	p256SubInternal(X1,X0,T3H,T3L,X3H,X3L)
  1811
  1812	// X-  ; Y-  ; MUL; T-    // T1 = T1*T2
  1813	CALL p256MulInternal<>(SB)
  1814
  1815	// SUB(Y3<T-Y3)           // Y3 = T1-Y3
  1816	p256SubInternal(Y3H,Y3L,T1,T0,Y3H,Y3L)
  1817
  1818	XXPERMDI Y3L, Y3L, $2, Y3L
  1819	XXPERMDI Y3H, Y3H, $2, Y3H
  1820	STXVD2X Y3L, (R17)(P3ptr)
  1821	STXVD2X Y3H, (R18)(P3ptr)
  1822	RET
  1823
  1824#undef P3ptr
  1825#undef P1ptr
  1826#undef CPOOL
  1827#undef X3L
  1828#undef X3H
  1829#undef Y3L
  1830#undef Y3H
  1831#undef T1L
  1832#undef T1H
  1833#undef T2L
  1834#undef T2H
  1835#undef T3L
  1836#undef T3H
  1837#undef X1L
  1838#undef X1H
  1839#undef Y1L
  1840#undef Y1H
  1841#undef Z1L
  1842#undef Z1H
  1843#undef TT0
  1844#undef TT1
  1845#undef T2
  1846#undef X0
  1847#undef X1
  1848#undef Y0
  1849#undef Y1
  1850#undef T0
  1851#undef T1
  1852#undef PL
  1853#undef PH
  1854#undef Z3L
  1855#undef Z3H
  1856#undef ZER
  1857#undef SEL1
  1858#undef CAR1
  1859#undef CAR2
  1860
  1861#define P3ptr  R3
  1862#define P1ptr  R4
  1863#define P2ptr  R5
  1864#define CPOOL  R7
  1865#define TRUE   R14
  1866#define RES1   R9
  1867#define RES2   R10
  1868
  1869// Temporaries in REGs
  1870#define T1L   V16
  1871#define T1H   V17
  1872#define T2L   V18
  1873#define T2H   V19
  1874#define U1L   V20
  1875#define U1H   V21
  1876#define S1L   V22
  1877#define S1H   V23
  1878#define HL    V24
  1879#define HH    V25
  1880#define RL    V26
  1881#define RH    V27
  1882
  1883// Temps for Sub and Add
  1884#define ZER   V6
  1885#define SEL1  V7
  1886#define CAR1  V8
  1887#define CAR2  V9
  1888#define TT0  V11
  1889#define TT1  V12
  1890#define T2   V13
  1891
  1892// p256MulAsm Parameters
  1893#define X0    V0
  1894#define X1    V1
  1895#define Y0    V2
  1896#define Y1    V3
  1897#define T0    V4
  1898#define T1    V5
  1899
  1900#define PL    V30
  1901#define PH    V31
  1902/*
  1903 * https://choucroutage.com/Papers/SideChannelAttacks/ctrsa-2011-brown.pdf "Software Implementation of the NIST Elliptic Curves Over Prime Fields"
  1904 *
  1905 * A = X₁×Z₂²
  1906 * B = Y₁×Z₂³
  1907 * C = X₂×Z₁²-A
  1908 * D = Y₂×Z₁³-B
  1909 * X₃ = D² - 2A×C² - C³
  1910 * Y₃ = D×(A×C² - X₃) - B×C³
  1911 * Z₃ = Z₁×Z₂×C
  1912 *
  1913 * Three-operand formula (adopted): http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
  1914 * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R
  1915 *
  1916 * T1 = Z1*Z1
  1917 * T2 = Z2*Z2
  1918 * U1 = X1*T2
  1919 * H  = X2*T1
  1920 * H  = H-U1
  1921 * Z3 = Z1*Z2
  1922 * Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
  1923 *
  1924 * S1 = Z2*T2
  1925 * S1 = Y1*S1
  1926 * R  = Z1*T1
  1927 * R  = Y2*R
  1928 * R  = R-S1
  1929 *
  1930 * T1 = H*H
  1931 * T2 = H*T1
  1932 * U1 = U1*T1
  1933 *
  1934 * X3 = R*R
  1935 * X3 = X3-T2
  1936 * T1 = 2*U1
  1937 * X3 = X3-T1 << store-out X3 result reg
  1938 *
  1939 * T2 = S1*T2
  1940 * Y3 = U1-X3
  1941 * Y3 = R*Y3
  1942 * Y3 = Y3-T2 << store-out Y3 result reg
  1943
  1944	// X=Z1; Y=Z1; MUL; T-   // T1 = Z1*Z1
  1945	// X-  ; Y=T ; MUL; R=T  // R  = Z1*T1
  1946	// X=X2; Y-  ; MUL; H=T  // H  = X2*T1
  1947	// X=Z2; Y=Z2; MUL; T-   // T2 = Z2*Z2
  1948	// X-  ; Y=T ; MUL; S1=T // S1 = Z2*T2
  1949	// X=X1; Y-  ; MUL; U1=T // U1 = X1*T2
  1950	// SUB(H<H-T)            // H  = H-U1
  1951	// X=Z1; Y=Z2; MUL; T-   // Z3 = Z1*Z2
  1952	// X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
  1953	// X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
  1954	// X=Y2; Y=R ; MUL; T-   // R  = Y2*R
  1955	// SUB(R<T-S1)           // R  = R-S1
  1956	// X=H ; Y=H ; MUL; T-   // T1 = H*H
  1957	// X-  ; Y=T ; MUL; T2=T // T2 = H*T1
  1958	// X=U1; Y-  ; MUL; U1=T // U1 = U1*T1
  1959	// X=R ; Y=R ; MUL; T-   // X3 = R*R
  1960	// SUB(T<T-T2)           // X3 = X3-T2
  1961	// ADD(X<U1+U1)          // T1 = 2*U1
  1962	// SUB(T<T-X) X3:=T      // X3 = X3-T1 << store-out X3 result reg
  1963	// SUB(Y<U1-T)           // Y3 = U1-X3
  1964	// X=R ; Y-  ; MUL; U1=T // Y3 = R*Y3
  1965	// X=S1; Y=T2; MUL; T-   // T2 = S1*T2
  1966	// SUB(T<U1-T); Y3:=T    // Y3 = Y3-T2 << store-out Y3 result reg
  1967	*/
  1968// p256PointAddAsm(res, in1, in2 *p256Point)
  1969TEXT ·p256PointAddAsm(SB), NOSPLIT, $16-32
  1970	MOVD res+0(FP), P3ptr
  1971	MOVD in1+8(FP), P1ptr
  1972	MOVD $p256mul<>+0x00(SB), CPOOL
  1973	MOVD $16, R16
  1974	MOVD $32, R17
  1975	MOVD $48, R18
  1976	MOVD $64, R19
  1977	MOVD $80, R20
  1978
  1979	LXVD2X (R16)(CPOOL), PH
  1980	LXVD2X (R0)(CPOOL), PL
  1981
  1982	// X=Z1; Y=Z1; MUL; T-   // T1 = Z1*Z1
  1983	LXVD2X (R19)(P1ptr), X0     // Z1L
  1984	LXVD2X (R20)(P1ptr), X1     // Z1H
  1985	XXPERMDI X0, X0, $2, X0
  1986	XXPERMDI X1, X1, $2, X1
  1987	VOR    X0, X0, Y0
  1988	VOR    X1, X1, Y1
  1989	CALL   p256MulInternal<>(SB)
  1990
  1991	// X-  ; Y=T ; MUL; R=T  // R  = Z1*T1
  1992	VOR  T0, T0, Y0
  1993	VOR  T1, T1, Y1
  1994	CALL p256MulInternal<>(SB)
  1995	VOR  T0, T0, RL            // SAVE: RL
  1996	VOR  T1, T1, RH            // SAVE: RH
  1997
  1998	STXVD2X RH, (R1)(R17) // V27 has to be saved
  1999
  2000	// X=X2; Y-  ; MUL; H=T  // H  = X2*T1
  2001	MOVD   in2+16(FP), P2ptr
  2002	LXVD2X (R0)(P2ptr), X0      // X2L
  2003	LXVD2X (R16)(P2ptr), X1     // X2H
  2004	XXPERMDI X0, X0, $2, X0
  2005	XXPERMDI X1, X1, $2, X1
  2006	CALL   p256MulInternal<>(SB)
  2007	VOR    T0, T0, HL            // SAVE: HL
  2008	VOR    T1, T1, HH            // SAVE: HH
  2009
  2010	// X=Z2; Y=Z2; MUL; T-   // T2 = Z2*Z2
  2011	MOVD   in2+16(FP), P2ptr
  2012	LXVD2X (R19)(P2ptr), X0     // Z2L
  2013	LXVD2X (R20)(P2ptr), X1     // Z2H
  2014	XXPERMDI X0, X0, $2, X0
  2015	XXPERMDI X1, X1, $2, X1
  2016	VOR    X0, X0, Y0
  2017	VOR    X1, X1, Y1
  2018	CALL   p256MulInternal<>(SB)
  2019
  2020	// X-  ; Y=T ; MUL; S1=T // S1 = Z2*T2
  2021	VOR  T0, T0, Y0
  2022	VOR  T1, T1, Y1
  2023	CALL p256MulInternal<>(SB)
  2024	VOR  T0, T0, S1L           // SAVE: S1L
  2025	VOR  T1, T1, S1H           // SAVE: S1H
  2026
  2027	// X=X1; Y-  ; MUL; U1=T // U1 = X1*T2
  2028	MOVD   in1+8(FP), P1ptr
  2029	LXVD2X (R0)(P1ptr), X0      // X1L
  2030	LXVD2X (R16)(P1ptr), X1     // X1H
  2031	XXPERMDI X0, X0, $2, X0
  2032	XXPERMDI X1, X1, $2, X1
  2033	CALL   p256MulInternal<>(SB)
  2034	VOR    T0, T0, U1L           // SAVE: U1L
  2035	VOR    T1, T1, U1H           // SAVE: U1H
  2036
  2037	// SUB(H<H-T)            // H  = H-U1
  2038	p256SubInternal(HH,HL,HH,HL,T1,T0)
  2039
  2040	// if H == 0 or H^P == 0 then ret=1 else ret=0
  2041	// clobbers T1H and T1L
  2042	MOVD       $1, TRUE
  2043	VSPLTISB   $0, ZER
  2044	VOR        HL, HH, T1H
  2045	VCMPEQUDCC ZER, T1H, T1H
  2046
  2047	// 26 = CR6 NE
  2048	ISEL       $26, R0, TRUE, RES1
  2049	VXOR       HL, PL, T1L         // SAVE: T1L
  2050	VXOR       HH, PH, T1H         // SAVE: T1H
  2051	VOR        T1L, T1H, T1H
  2052	VCMPEQUDCC ZER, T1H, T1H
  2053
  2054	// 26 = CR6 NE
  2055	ISEL $26, R0, TRUE, RES2
  2056	OR   RES2, RES1, RES1
  2057	MOVD RES1, ret+24(FP)
  2058
  2059	// X=Z1; Y=Z2; MUL; T-   // Z3 = Z1*Z2
  2060	MOVD   in1+8(FP), P1ptr
  2061	MOVD   in2+16(FP), P2ptr
  2062	LXVD2X (R19)(P1ptr), X0        // Z1L
  2063	LXVD2X (R20)(P1ptr), X1        // Z1H
  2064	XXPERMDI X0, X0, $2, X0
  2065	XXPERMDI X1, X1, $2, X1
  2066	LXVD2X (R19)(P2ptr), Y0        // Z2L
  2067	LXVD2X (R20)(P2ptr), Y1        // Z2H
  2068	XXPERMDI Y0, Y0, $2, Y0
  2069	XXPERMDI Y1, Y1, $2, Y1
  2070	CALL   p256MulInternal<>(SB)
  2071
  2072	// X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H
  2073	VOR     T0, T0, X0
  2074	VOR     T1, T1, X1
  2075	VOR     HL, HL, Y0
  2076	VOR     HH, HH, Y1
  2077	CALL    p256MulInternal<>(SB)
  2078	MOVD    res+0(FP), P3ptr
  2079	XXPERMDI T1, T1, $2, TT1
  2080	XXPERMDI T0, T0, $2, TT0
  2081	STXVD2X TT0, (R19)(P3ptr)
  2082	STXVD2X TT1, (R20)(P3ptr)
  2083
  2084	// X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
  2085	MOVD   in1+8(FP), P1ptr
  2086	LXVD2X (R17)(P1ptr), X0
  2087	LXVD2X (R18)(P1ptr), X1
  2088	XXPERMDI X0, X0, $2, X0
  2089	XXPERMDI X1, X1, $2, X1
  2090	VOR    S1L, S1L, Y0
  2091	VOR    S1H, S1H, Y1
  2092	CALL   p256MulInternal<>(SB)
  2093	VOR    T0, T0, S1L
  2094	VOR    T1, T1, S1H
  2095
  2096	// X=Y2; Y=R ; MUL; T-   // R  = Y2*R
  2097	MOVD   in2+16(FP), P2ptr
  2098	LXVD2X (R17)(P2ptr), X0
  2099	LXVD2X (R18)(P2ptr), X1
  2100	XXPERMDI X0, X0, $2, X0
  2101	XXPERMDI X1, X1, $2, X1
  2102	VOR    RL, RL, Y0
  2103
  2104	// VOR RH, RH, Y1   RH was saved above in D2X format
  2105	LXVD2X (R1)(R17), Y1
  2106	CALL   p256MulInternal<>(SB)
  2107
  2108	// SUB(R<T-S1)           // R  = T-S1
  2109	p256SubInternal(RH,RL,T1,T0,S1H,S1L)
  2110
  2111	STXVD2X RH, (R1)(R17) // Save RH
  2112
  2113	// if R == 0 or R^P == 0 then ret=ret else ret=0
  2114	// clobbers T1H and T1L
  2115	// Redo this using ISEL??
  2116	MOVD       $1, TRUE
  2117	VSPLTISB   $0, ZER
  2118	VOR        RL, RH, T1H
  2119	VCMPEQUDCC ZER, T1H, T1H
  2120
  2121	// 24 = CR6 NE
  2122	ISEL       $26, R0, TRUE, RES1
  2123	VXOR       RL, PL, T1L
  2124	VXOR       RH, PH, T1H         // SAVE: T1L
  2125	VOR        T1L, T1H, T1H
  2126	VCMPEQUDCC ZER, T1H, T1H
  2127
  2128	// 26 = CR6 NE
  2129	ISEL $26, R0, TRUE, RES2
  2130	OR   RES2, RES1, RES1
  2131	MOVD ret+24(FP), RES2
  2132	AND  RES2, RES1, RES1
  2133	MOVD RES1, ret+24(FP)
  2134
  2135	// X=H ; Y=H ; MUL; T-   // T1 = H*H
  2136	VOR  HL, HL, X0
  2137	VOR  HH, HH, X1
  2138	VOR  HL, HL, Y0
  2139	VOR  HH, HH, Y1
  2140	CALL p256MulInternal<>(SB)
  2141
  2142	// X-  ; Y=T ; MUL; T2=T // T2 = H*T1
  2143	VOR  T0, T0, Y0
  2144	VOR  T1, T1, Y1
  2145	CALL p256MulInternal<>(SB)
  2146	VOR  T0, T0, T2L
  2147	VOR  T1, T1, T2H
  2148
  2149	// X=U1; Y-  ; MUL; U1=T // U1 = U1*T1
  2150	VOR  U1L, U1L, X0
  2151	VOR  U1H, U1H, X1
  2152	CALL p256MulInternal<>(SB)
  2153	VOR  T0, T0, U1L
  2154	VOR  T1, T1, U1H
  2155
  2156	// X=R ; Y=R ; MUL; T-   // X3 = R*R
  2157	VOR RL, RL, X0
  2158
  2159	// VOR  RH, RH, X1
  2160	VOR RL, RL, Y0
  2161
  2162	// RH was saved above using STXVD2X
  2163	LXVD2X (R1)(R17), X1
  2164	VOR    X1, X1, Y1
  2165
  2166	// VOR  RH, RH, Y1
  2167	CALL p256MulInternal<>(SB)
  2168
  2169	// SUB(T<T-T2)           // X3 = X3-T2
  2170	p256SubInternal(T1,T0,T1,T0,T2H,T2L)
  2171
  2172	// ADD(X<U1+U1)          // T1 = 2*U1
  2173	p256AddInternal(X1,X0,U1H,U1L,U1H,U1L)
  2174
  2175	// SUB(T<T-X) X3:=T      // X3 = X3-T1 << store-out X3 result reg
  2176	p256SubInternal(T1,T0,T1,T0,X1,X0)
  2177	MOVD    res+0(FP), P3ptr
  2178	XXPERMDI T1, T1, $2, TT1
  2179	XXPERMDI T0, T0, $2, TT0
  2180	STXVD2X TT0, (R0)(P3ptr)
  2181	STXVD2X TT1, (R16)(P3ptr)
  2182
  2183	// SUB(Y<U1-T)           // Y3 = U1-X3
  2184	p256SubInternal(Y1,Y0,U1H,U1L,T1,T0)
  2185
  2186	// X=R ; Y-  ; MUL; U1=T // Y3 = R*Y3
  2187	VOR RL, RL, X0
  2188
  2189	// VOR  RH, RH, X1
  2190	LXVD2X (R1)(R17), X1
  2191	CALL   p256MulInternal<>(SB)
  2192	VOR    T0, T0, U1L
  2193	VOR    T1, T1, U1H
  2194
  2195	// X=S1; Y=T2; MUL; T-   // T2 = S1*T2
  2196	VOR  S1L, S1L, X0
  2197	VOR  S1H, S1H, X1
  2198	VOR  T2L, T2L, Y0
  2199	VOR  T2H, T2H, Y1
  2200	CALL p256MulInternal<>(SB)
  2201
  2202	// SUB(T<U1-T); Y3:=T    // Y3 = Y3-T2 << store-out Y3 result reg
  2203	p256SubInternal(T1,T0,U1H,U1L,T1,T0)
  2204	MOVD    res+0(FP), P3ptr
  2205	XXPERMDI T1, T1, $2, TT1
  2206	XXPERMDI T0, T0, $2, TT0
  2207	STXVD2X TT0, (R17)(P3ptr)
  2208	STXVD2X TT1, (R18)(P3ptr)
  2209
  2210	RET

View as plain text