github.com/dominant-strategies/go-quai@v0.28.2/crypto/blake2b/blake2bAVX2_amd64.s (about)

     1  // Copyright 2016 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  // +build go1.7,amd64,!gccgo,!appengine
     6  
     7  #include "textflag.h"
     8  
     9  DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
    10  DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
    11  DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b
    12  DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1
    13  GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32
    14  
    15  DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1
    16  DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
    17  DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b
    18  DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179
    19  GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32
    20  
    21  DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403
    22  DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
    23  DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403
    24  DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b
    25  GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32
    26  
    27  DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302
    28  DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
    29  DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302
    30  DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a
    31  GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32
    32  
    33  DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
    34  DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
    35  GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16
    36  
    37  DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
    38  DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
    39  GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16
    40  
    41  DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1
    42  DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
    43  GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16
    44  
    45  DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
    46  DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
    47  GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16
    48  
    49  DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403
    50  DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
    51  GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16
    52  
    53  DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
    54  DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
    55  GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
    56  
    57  #define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
    58  #define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
    59  #define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
    60  #define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
    61  #define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
    62  
    63  #define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
    64  	VPADDQ  m0, Y0, Y0;   \
    65  	VPADDQ  Y1, Y0, Y0;   \
    66  	VPXOR   Y0, Y3, Y3;   \
    67  	VPSHUFD $-79, Y3, Y3; \
    68  	VPADDQ  Y3, Y2, Y2;   \
    69  	VPXOR   Y2, Y1, Y1;   \
    70  	VPSHUFB c40, Y1, Y1;  \
    71  	VPADDQ  m1, Y0, Y0;   \
    72  	VPADDQ  Y1, Y0, Y0;   \
    73  	VPXOR   Y0, Y3, Y3;   \
    74  	VPSHUFB c48, Y3, Y3;  \
    75  	VPADDQ  Y3, Y2, Y2;   \
    76  	VPXOR   Y2, Y1, Y1;   \
    77  	VPADDQ  Y1, Y1, t;    \
    78  	VPSRLQ  $63, Y1, Y1;  \
    79  	VPXOR   t, Y1, Y1;    \
    80  	VPERMQ_0x39_Y1_Y1;    \
    81  	VPERMQ_0x4E_Y2_Y2;    \
    82  	VPERMQ_0x93_Y3_Y3;    \
    83  	VPADDQ  m2, Y0, Y0;   \
    84  	VPADDQ  Y1, Y0, Y0;   \
    85  	VPXOR   Y0, Y3, Y3;   \
    86  	VPSHUFD $-79, Y3, Y3; \
    87  	VPADDQ  Y3, Y2, Y2;   \
    88  	VPXOR   Y2, Y1, Y1;   \
    89  	VPSHUFB c40, Y1, Y1;  \
    90  	VPADDQ  m3, Y0, Y0;   \
    91  	VPADDQ  Y1, Y0, Y0;   \
    92  	VPXOR   Y0, Y3, Y3;   \
    93  	VPSHUFB c48, Y3, Y3;  \
    94  	VPADDQ  Y3, Y2, Y2;   \
    95  	VPXOR   Y2, Y1, Y1;   \
    96  	VPADDQ  Y1, Y1, t;    \
    97  	VPSRLQ  $63, Y1, Y1;  \
    98  	VPXOR   t, Y1, Y1;    \
    99  	VPERMQ_0x39_Y3_Y3;    \
   100  	VPERMQ_0x4E_Y2_Y2;    \
   101  	VPERMQ_0x93_Y1_Y1
   102  
   103  #define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
   104  #define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
   105  #define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
   106  #define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
   107  #define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
   108  
   109  #define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
   110  #define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
   111  #define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
   112  #define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
   113  #define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
   114  
   115  #define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
   116  #define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
   117  #define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
   118  #define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
   119  #define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
   120  
   121  #define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
   122  #define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
   123  #define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
   124  #define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
   125  #define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
   126  
   127  #define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
   128  #define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
   129  
   130  // load msg: Y12 = (i0, i1, i2, i3)
   131  // i0, i1, i2, i3 must not be 0
   132  #define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
   133  	VMOVQ_SI_X12(i0*8);           \
   134  	VMOVQ_SI_X11(i2*8);           \
   135  	VPINSRQ_1_SI_X12(i1*8);       \
   136  	VPINSRQ_1_SI_X11(i3*8);       \
   137  	VINSERTI128 $1, X11, Y12, Y12
   138  
   139  // load msg: Y13 = (i0, i1, i2, i3)
   140  // i0, i1, i2, i3 must not be 0
   141  #define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
   142  	VMOVQ_SI_X13(i0*8);           \
   143  	VMOVQ_SI_X11(i2*8);           \
   144  	VPINSRQ_1_SI_X13(i1*8);       \
   145  	VPINSRQ_1_SI_X11(i3*8);       \
   146  	VINSERTI128 $1, X11, Y13, Y13
   147  
   148  // load msg: Y14 = (i0, i1, i2, i3)
   149  // i0, i1, i2, i3 must not be 0
   150  #define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
   151  	VMOVQ_SI_X14(i0*8);           \
   152  	VMOVQ_SI_X11(i2*8);           \
   153  	VPINSRQ_1_SI_X14(i1*8);       \
   154  	VPINSRQ_1_SI_X11(i3*8);       \
   155  	VINSERTI128 $1, X11, Y14, Y14
   156  
   157  // load msg: Y15 = (i0, i1, i2, i3)
   158  // i0, i1, i2, i3 must not be 0
   159  #define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
   160  	VMOVQ_SI_X15(i0*8);           \
   161  	VMOVQ_SI_X11(i2*8);           \
   162  	VPINSRQ_1_SI_X15(i1*8);       \
   163  	VPINSRQ_1_SI_X11(i3*8);       \
   164  	VINSERTI128 $1, X11, Y15, Y15
   165  
   166  #define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
   167  	VMOVQ_SI_X12_0;                   \
   168  	VMOVQ_SI_X11(4*8);                \
   169  	VPINSRQ_1_SI_X12(2*8);            \
   170  	VPINSRQ_1_SI_X11(6*8);            \
   171  	VINSERTI128 $1, X11, Y12, Y12;    \
   172  	LOAD_MSG_AVX2_Y13(1, 3, 5, 7);    \
   173  	LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
   174  	LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
   175  
   176  #define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
   177  	LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
   178  	LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
   179  	VMOVQ_SI_X11(11*8);              \
   180  	VPSHUFD     $0x4E, 0*8(SI), X14; \
   181  	VPINSRQ_1_SI_X11(5*8);           \
   182  	VINSERTI128 $1, X11, Y14, Y14;   \
   183  	LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
   184  
   185  #define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
   186  	VMOVQ_SI_X11(5*8);              \
   187  	VMOVDQU     11*8(SI), X12;      \
   188  	VPINSRQ_1_SI_X11(15*8);         \
   189  	VINSERTI128 $1, X11, Y12, Y12;  \
   190  	VMOVQ_SI_X13(8*8);              \
   191  	VMOVQ_SI_X11(2*8);              \
   192  	VPINSRQ_1_SI_X13_0;             \
   193  	VPINSRQ_1_SI_X11(13*8);         \
   194  	VINSERTI128 $1, X11, Y13, Y13;  \
   195  	LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
   196  	LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
   197  
   198  #define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
   199  	LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
   200  	LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
   201  	LOAD_MSG_AVX2_Y14(2, 5, 4, 15);  \
   202  	VMOVQ_SI_X15(6*8);               \
   203  	VMOVQ_SI_X11_0;                  \
   204  	VPINSRQ_1_SI_X15(10*8);          \
   205  	VPINSRQ_1_SI_X11(8*8);           \
   206  	VINSERTI128 $1, X11, Y15, Y15
   207  
   208  #define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
   209  	LOAD_MSG_AVX2_Y12(9, 5, 2, 10);  \
   210  	VMOVQ_SI_X13_0;                  \
   211  	VMOVQ_SI_X11(4*8);               \
   212  	VPINSRQ_1_SI_X13(7*8);           \
   213  	VPINSRQ_1_SI_X11(15*8);          \
   214  	VINSERTI128 $1, X11, Y13, Y13;   \
   215  	LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
   216  	LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
   217  
   218  #define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
   219  	VMOVQ_SI_X12(2*8);                \
   220  	VMOVQ_SI_X11_0;                   \
   221  	VPINSRQ_1_SI_X12(6*8);            \
   222  	VPINSRQ_1_SI_X11(8*8);            \
   223  	VINSERTI128 $1, X11, Y12, Y12;    \
   224  	LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
   225  	LOAD_MSG_AVX2_Y14(4, 7, 15, 1);   \
   226  	LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
   227  
   228  #define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
   229  	LOAD_MSG_AVX2_Y12(12, 1, 14, 4);  \
   230  	LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
   231  	VMOVQ_SI_X14_0;                   \
   232  	VPSHUFD     $0x4E, 8*8(SI), X11;  \
   233  	VPINSRQ_1_SI_X14(6*8);            \
   234  	VINSERTI128 $1, X11, Y14, Y14;    \
   235  	LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
   236  
   237  #define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
   238  	LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
   239  	LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
   240  	LOAD_MSG_AVX2_Y14(5, 15, 8, 2);  \
   241  	VMOVQ_SI_X15_0;                  \
   242  	VMOVQ_SI_X11(6*8);               \
   243  	VPINSRQ_1_SI_X15(4*8);           \
   244  	VPINSRQ_1_SI_X11(10*8);          \
   245  	VINSERTI128 $1, X11, Y15, Y15
   246  
   247  #define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
   248  	VMOVQ_SI_X12(6*8);              \
   249  	VMOVQ_SI_X11(11*8);             \
   250  	VPINSRQ_1_SI_X12(14*8);         \
   251  	VPINSRQ_1_SI_X11_0;             \
   252  	VINSERTI128 $1, X11, Y12, Y12;  \
   253  	LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
   254  	VMOVQ_SI_X11(1*8);              \
   255  	VMOVDQU     12*8(SI), X14;      \
   256  	VPINSRQ_1_SI_X11(10*8);         \
   257  	VINSERTI128 $1, X11, Y14, Y14;  \
   258  	VMOVQ_SI_X15(2*8);              \
   259  	VMOVDQU     4*8(SI), X11;       \
   260  	VPINSRQ_1_SI_X15(7*8);          \
   261  	VINSERTI128 $1, X11, Y15, Y15
   262  
   263  #define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
   264  	LOAD_MSG_AVX2_Y12(10, 8, 7, 1);  \
   265  	VMOVQ_SI_X13(2*8);               \
   266  	VPSHUFD     $0x4E, 5*8(SI), X11; \
   267  	VPINSRQ_1_SI_X13(4*8);           \
   268  	VINSERTI128 $1, X11, Y13, Y13;   \
   269  	LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
   270  	VMOVQ_SI_X15(11*8);              \
   271  	VMOVQ_SI_X11(12*8);              \
   272  	VPINSRQ_1_SI_X15(14*8);          \
   273  	VPINSRQ_1_SI_X11_0;              \
   274  	VINSERTI128 $1, X11, Y15, Y15
   275  
   276  // func fAVX2(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
   277  TEXT ·fAVX2(SB), 4, $64-48 // frame size = 32 + 32 byte alignment
   278  	MOVQ h+0(FP), AX
   279  	MOVQ m+8(FP), SI
   280  	MOVQ c0+16(FP), R8
   281  	MOVQ c1+24(FP), R9
   282  	MOVQ flag+32(FP), CX
   283  	MOVQ rounds+40(FP), BX
   284  
   285  	MOVQ SP, DX
   286  	MOVQ SP, R10
   287  	ADDQ $31, R10
   288  	ANDQ $~31, R10
   289  	MOVQ R10, SP
   290  
   291  	MOVQ CX, 16(SP)
   292  	XORQ CX, CX
   293  	MOVQ CX, 24(SP)
   294  
   295  	VMOVDQU ·AVX2_c40<>(SB), Y4
   296  	VMOVDQU ·AVX2_c48<>(SB), Y5
   297  
   298  	VMOVDQU 0(AX), Y8
   299  	VMOVDQU 32(AX), Y9
   300  	VMOVDQU ·AVX2_iv0<>(SB), Y6
   301  	VMOVDQU ·AVX2_iv1<>(SB), Y7
   302  
   303  	MOVQ R8, 0(SP)
   304  	MOVQ R9, 8(SP)
   305  	
   306  	VMOVDQA Y8, Y0
   307  	VMOVDQA Y9, Y1
   308  	VMOVDQA Y6, Y2
   309  	VPXOR   0(SP), Y7, Y3
   310  
   311  loop:
   312  	SUBQ $1, BX; JCS done
   313  	LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
   314  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   315  
   316  	SUBQ $1, BX; JCS done
   317  	LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
   318  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   319  
   320  	SUBQ $1, BX; JCS done
   321  	LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
   322  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   323  
   324  	SUBQ $1, BX; JCS done
   325  	LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
   326  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   327  
   328  	SUBQ $1, BX; JCS done
   329  	LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
   330  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   331  
   332  	SUBQ $1, BX; JCS done
   333  	LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
   334  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   335  
   336  	SUBQ $1, BX; JCS done
   337  	LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
   338  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   339  
   340  	SUBQ $1, BX; JCS done
   341  	LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
   342  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   343  
   344  	SUBQ $1, BX; JCS done
   345  	LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
   346  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   347  
   348  	SUBQ $1, BX; JCS done
   349  	LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
   350  	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
   351  
   352  	JMP loop
   353  
   354  done:
   355  	VPXOR Y0, Y8, Y8
   356  	VPXOR Y1, Y9, Y9
   357  	VPXOR Y2, Y8, Y8
   358  	VPXOR Y3, Y9, Y9
   359  
   360  	VMOVDQU Y8, 0(AX)
   361  	VMOVDQU Y9, 32(AX)
   362  	VZEROUPPER
   363  
   364  	MOVQ DX, SP
   365  	RET
   366  
   367  #define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
   368  #define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
   369  #define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
   370  #define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
   371  #define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
   372  
   373  #define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
   374  #define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
   375  #define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
   376  #define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
   377  #define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
   378  #define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
   379  #define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
   380  #define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
   381  
   382  #define SHUFFLE_AVX() \
   383  	VMOVDQA X6, X13;         \
   384  	VMOVDQA X2, X14;         \
   385  	VMOVDQA X4, X6;          \
   386  	VPUNPCKLQDQ_X13_X13_X15; \
   387  	VMOVDQA X5, X4;          \
   388  	VMOVDQA X6, X5;          \
   389  	VPUNPCKHQDQ_X15_X7_X6;   \
   390  	VPUNPCKLQDQ_X7_X7_X15;   \
   391  	VPUNPCKHQDQ_X15_X13_X7;  \
   392  	VPUNPCKLQDQ_X3_X3_X15;   \
   393  	VPUNPCKHQDQ_X15_X2_X2;   \
   394  	VPUNPCKLQDQ_X14_X14_X15; \
   395  	VPUNPCKHQDQ_X15_X3_X3;   \
   396  
   397  #define SHUFFLE_AVX_INV() \
   398  	VMOVDQA X2, X13;         \
   399  	VMOVDQA X4, X14;         \
   400  	VPUNPCKLQDQ_X2_X2_X15;   \
   401  	VMOVDQA X5, X4;          \
   402  	VPUNPCKHQDQ_X15_X3_X2;   \
   403  	VMOVDQA X14, X5;         \
   404  	VPUNPCKLQDQ_X3_X3_X15;   \
   405  	VMOVDQA X6, X14;         \
   406  	VPUNPCKHQDQ_X15_X13_X3;  \
   407  	VPUNPCKLQDQ_X7_X7_X15;   \
   408  	VPUNPCKHQDQ_X15_X6_X6;   \
   409  	VPUNPCKLQDQ_X14_X14_X15; \
   410  	VPUNPCKHQDQ_X15_X7_X7;   \
   411  
   412  #define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
   413  	VPADDQ  m0, v0, v0;   \
   414  	VPADDQ  v2, v0, v0;   \
   415  	VPADDQ  m1, v1, v1;   \
   416  	VPADDQ  v3, v1, v1;   \
   417  	VPXOR   v0, v6, v6;   \
   418  	VPXOR   v1, v7, v7;   \
   419  	VPSHUFD $-79, v6, v6; \
   420  	VPSHUFD $-79, v7, v7; \
   421  	VPADDQ  v6, v4, v4;   \
   422  	VPADDQ  v7, v5, v5;   \
   423  	VPXOR   v4, v2, v2;   \
   424  	VPXOR   v5, v3, v3;   \
   425  	VPSHUFB c40, v2, v2;  \
   426  	VPSHUFB c40, v3, v3;  \
   427  	VPADDQ  m2, v0, v0;   \
   428  	VPADDQ  v2, v0, v0;   \
   429  	VPADDQ  m3, v1, v1;   \
   430  	VPADDQ  v3, v1, v1;   \
   431  	VPXOR   v0, v6, v6;   \
   432  	VPXOR   v1, v7, v7;   \
   433  	VPSHUFB c48, v6, v6;  \
   434  	VPSHUFB c48, v7, v7;  \
   435  	VPADDQ  v6, v4, v4;   \
   436  	VPADDQ  v7, v5, v5;   \
   437  	VPXOR   v4, v2, v2;   \
   438  	VPXOR   v5, v3, v3;   \
   439  	VPADDQ  v2, v2, t0;   \
   440  	VPSRLQ  $63, v2, v2;  \
   441  	VPXOR   t0, v2, v2;   \
   442  	VPADDQ  v3, v3, t0;   \
   443  	VPSRLQ  $63, v3, v3;  \
   444  	VPXOR   t0, v3, v3
   445  
   446  // load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
   447  // i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
   448  #define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
   449  	VMOVQ_SI_X12(i0*8);     \
   450  	VMOVQ_SI_X13(i2*8);     \
   451  	VMOVQ_SI_X14(i4*8);     \
   452  	VMOVQ_SI_X15(i6*8);     \
   453  	VPINSRQ_1_SI_X12(i1*8); \
   454  	VPINSRQ_1_SI_X13(i3*8); \
   455  	VPINSRQ_1_SI_X14(i5*8); \
   456  	VPINSRQ_1_SI_X15(i7*8)
   457  
   458  // load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
   459  #define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
   460  	VMOVQ_SI_X12_0;        \
   461  	VMOVQ_SI_X13(4*8);     \
   462  	VMOVQ_SI_X14(1*8);     \
   463  	VMOVQ_SI_X15(5*8);     \
   464  	VPINSRQ_1_SI_X12(2*8); \
   465  	VPINSRQ_1_SI_X13(6*8); \
   466  	VPINSRQ_1_SI_X14(3*8); \
   467  	VPINSRQ_1_SI_X15(7*8)
   468  
   469  // load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
   470  #define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
   471  	VPSHUFD $0x4E, 0*8(SI), X12; \
   472  	VMOVQ_SI_X13(11*8);          \
   473  	VMOVQ_SI_X14(12*8);          \
   474  	VMOVQ_SI_X15(7*8);           \
   475  	VPINSRQ_1_SI_X13(5*8);       \
   476  	VPINSRQ_1_SI_X14(2*8);       \
   477  	VPINSRQ_1_SI_X15(3*8)
   478  
   479  // load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
   480  #define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
   481  	VMOVDQU 11*8(SI), X12;  \
   482  	VMOVQ_SI_X13(5*8);      \
   483  	VMOVQ_SI_X14(8*8);      \
   484  	VMOVQ_SI_X15(2*8);      \
   485  	VPINSRQ_1_SI_X13(15*8); \
   486  	VPINSRQ_1_SI_X14_0;     \
   487  	VPINSRQ_1_SI_X15(13*8)
   488  
   489  // load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
   490  #define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
   491  	VMOVQ_SI_X12(2*8);      \
   492  	VMOVQ_SI_X13(4*8);      \
   493  	VMOVQ_SI_X14(6*8);      \
   494  	VMOVQ_SI_X15_0;         \
   495  	VPINSRQ_1_SI_X12(5*8);  \
   496  	VPINSRQ_1_SI_X13(15*8); \
   497  	VPINSRQ_1_SI_X14(10*8); \
   498  	VPINSRQ_1_SI_X15(8*8)
   499  
   500  // load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
   501  #define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
   502  	VMOVQ_SI_X12(9*8);      \
   503  	VMOVQ_SI_X13(2*8);      \
   504  	VMOVQ_SI_X14_0;         \
   505  	VMOVQ_SI_X15(4*8);      \
   506  	VPINSRQ_1_SI_X12(5*8);  \
   507  	VPINSRQ_1_SI_X13(10*8); \
   508  	VPINSRQ_1_SI_X14(7*8);  \
   509  	VPINSRQ_1_SI_X15(15*8)
   510  
   511  // load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
   512  #define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
   513  	VMOVQ_SI_X12(2*8);      \
   514  	VMOVQ_SI_X13_0;         \
   515  	VMOVQ_SI_X14(12*8);     \
   516  	VMOVQ_SI_X15(11*8);     \
   517  	VPINSRQ_1_SI_X12(6*8);  \
   518  	VPINSRQ_1_SI_X13(8*8);  \
   519  	VPINSRQ_1_SI_X14(10*8); \
   520  	VPINSRQ_1_SI_X15(3*8)
   521  
   522  // load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
   523  #define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
   524  	MOVQ    0*8(SI), X12;        \
   525  	VPSHUFD $0x4E, 8*8(SI), X13; \
   526  	MOVQ    7*8(SI), X14;        \
   527  	MOVQ    2*8(SI), X15;        \
   528  	VPINSRQ_1_SI_X12(6*8);       \
   529  	VPINSRQ_1_SI_X14(3*8);       \
   530  	VPINSRQ_1_SI_X15(11*8)
   531  
   532  // load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
   533  #define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
   534  	MOVQ 6*8(SI), X12;      \
   535  	MOVQ 11*8(SI), X13;     \
   536  	MOVQ 15*8(SI), X14;     \
   537  	MOVQ 3*8(SI), X15;      \
   538  	VPINSRQ_1_SI_X12(14*8); \
   539  	VPINSRQ_1_SI_X13_0;     \
   540  	VPINSRQ_1_SI_X14(9*8);  \
   541  	VPINSRQ_1_SI_X15(8*8)
   542  
   543  // load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
   544  #define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
   545  	MOVQ 5*8(SI), X12;      \
   546  	MOVQ 8*8(SI), X13;      \
   547  	MOVQ 0*8(SI), X14;      \
   548  	MOVQ 6*8(SI), X15;      \
   549  	VPINSRQ_1_SI_X12(15*8); \
   550  	VPINSRQ_1_SI_X13(2*8);  \
   551  	VPINSRQ_1_SI_X14(4*8);  \
   552  	VPINSRQ_1_SI_X15(10*8)
   553  
   554  // load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
   555  #define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
   556  	VMOVDQU 12*8(SI), X12;  \
   557  	MOVQ    1*8(SI), X13;   \
   558  	MOVQ    2*8(SI), X14;   \
   559  	VPINSRQ_1_SI_X13(10*8); \
   560  	VPINSRQ_1_SI_X14(7*8);  \
   561  	VMOVDQU 4*8(SI), X15
   562  
   563  // load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
   564  #define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
   565  	MOVQ 15*8(SI), X12;     \
   566  	MOVQ 3*8(SI), X13;      \
   567  	MOVQ 11*8(SI), X14;     \
   568  	MOVQ 12*8(SI), X15;     \
   569  	VPINSRQ_1_SI_X12(9*8);  \
   570  	VPINSRQ_1_SI_X13(13*8); \
   571  	VPINSRQ_1_SI_X14(14*8); \
   572  	VPINSRQ_1_SI_X15_0
   573  
   574  // func fAVX(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
   575  TEXT ·fAVX(SB), 4, $24-48 // frame size = 8 + 16 byte alignment
   576  	MOVQ h+0(FP), AX
   577  	MOVQ m+8(FP), SI
   578  	MOVQ c0+16(FP), R8
   579  	MOVQ c1+24(FP), R9
   580  	MOVQ flag+32(FP), CX
   581  	MOVQ rounds+40(FP), BX
   582  
   583  	MOVQ SP, BP
   584  	MOVQ SP, R10
   585  	ADDQ $15, R10
   586  	ANDQ $~15, R10
   587  	MOVQ R10, SP
   588  
   589  	VMOVDQU ·AVX_c40<>(SB), X0
   590  	VMOVDQU ·AVX_c48<>(SB), X1
   591  	VMOVDQA X0, X8
   592  	VMOVDQA X1, X9
   593  
   594  	VMOVDQU ·AVX_iv3<>(SB), X0
   595  	VMOVDQA X0, 0(SP)
   596  	XORQ    CX, 0(SP)          // 0(SP) = ·AVX_iv3 ^ (CX || 0)
   597  
   598  	VMOVDQU 0(AX), X10
   599  	VMOVDQU 16(AX), X11
   600  	VMOVDQU 32(AX), X2
   601  	VMOVDQU 48(AX), X3
   602  
   603  	VMOVQ_R8_X15
   604  	VPINSRQ_1_R9_X15
   605  
   606  	VMOVDQA X10, X0
   607  	VMOVDQA X11, X1
   608  	VMOVDQU ·AVX_iv0<>(SB), X4
   609  	VMOVDQU ·AVX_iv1<>(SB), X5
   610  	VMOVDQU ·AVX_iv2<>(SB), X6
   611  
   612  	VPXOR   X15, X6, X6
   613  	VMOVDQA 0(SP), X7
   614  
   615  loop:
   616  	SUBQ $1, BX; JCS done
   617  	LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
   618  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   619  	SHUFFLE_AVX()
   620  	LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
   621  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   622  	SHUFFLE_AVX_INV()
   623  
   624  	SUBQ $1, BX; JCS done
   625  	LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
   626  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   627  	SHUFFLE_AVX()
   628  	LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
   629  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   630  	SHUFFLE_AVX_INV()
   631  
   632  	SUBQ $1, BX; JCS done
   633  	LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
   634  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   635  	SHUFFLE_AVX()
   636  	LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
   637  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   638  	SHUFFLE_AVX_INV()
   639  
   640  	SUBQ $1, BX; JCS done
   641  	LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
   642  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   643  	SHUFFLE_AVX()
   644  	LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
   645  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   646  	SHUFFLE_AVX_INV()
   647  
   648  	SUBQ $1, BX; JCS done
   649  	LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
   650  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   651  	SHUFFLE_AVX()
   652  	LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
   653  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   654  	SHUFFLE_AVX_INV()
   655  
   656  	SUBQ $1, BX; JCS done
   657  	LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
   658  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   659  	SHUFFLE_AVX()
   660  	LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
   661  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   662  	SHUFFLE_AVX_INV()
   663  
   664  	SUBQ $1, BX; JCS done
   665  	LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
   666  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   667  	SHUFFLE_AVX()
   668  	LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
   669  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   670  	SHUFFLE_AVX_INV()
   671  
   672  	SUBQ $1, BX; JCS done
   673  	LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
   674  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   675  	SHUFFLE_AVX()
   676  	LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
   677  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   678  	SHUFFLE_AVX_INV()
   679  
   680  	SUBQ $1, BX; JCS done
   681  	LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
   682  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   683  	SHUFFLE_AVX()
   684  	LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
   685  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   686  	SHUFFLE_AVX_INV()
   687  
   688  	SUBQ $1, BX; JCS done
   689  	LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
   690  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   691  	SHUFFLE_AVX()
   692  	LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
   693  	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
   694  	SHUFFLE_AVX_INV()
   695  
   696  	JMP loop
   697  
   698  done:
   699  	VMOVDQU 32(AX), X14
   700  	VMOVDQU 48(AX), X15
   701  	VPXOR   X0, X10, X10
   702  	VPXOR   X1, X11, X11
   703  	VPXOR   X2, X14, X14
   704  	VPXOR   X3, X15, X15
   705  	VPXOR   X4, X10, X10
   706  	VPXOR   X5, X11, X11
   707  	VPXOR   X6, X14, X2
   708  	VPXOR   X7, X15, X3
   709  	VMOVDQU X2, 32(AX)
   710  	VMOVDQU X3, 48(AX)
   711  
   712  	VMOVDQU X10, 0(AX)
   713  	VMOVDQU X11, 16(AX)
   714  	VZEROUPPER
   715  
   716  	MOVQ BP, SP
   717  	RET