Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

763 righe
19 KiB

  1. #! /usr/bin/env perl
  2. # Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the OpenSSL license (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. # ====================================================================
  9. # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
  10. # project. The module is, however, dual licensed under OpenSSL and
  11. # CRYPTOGAMS licenses depending on where you obtain it. For further
  12. # details see http://www.openssl.org/~appro/cryptogams/.
  13. # ====================================================================
  14. # January 2007.
  15. # Montgomery multiplication for ARMv4.
  16. #
  17. # Performance improvement naturally varies among CPU implementations
  18. # and compilers. The code was observed to provide +65-35% improvement
  19. # [depending on key length, less for longer keys] on ARM920T, and
  20. # +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
  21. # base and compiler generated code with in-lined umull and even umlal
  22. # instructions. The latter means that this code didn't really have an
  23. # "advantage" of utilizing some "secret" instruction.
  24. #
  25. # The code is interoperable with Thumb ISA and is rather compact, less
  26. # than 1/2KB. Windows CE port would be trivial, as it's exclusively
  27. # about decorations, ABI and instruction syntax are identical.
  28. # November 2013
  29. #
  30. # Add NEON code path, which handles lengths divisible by 8. RSA/DSA
  31. # performance improvement on Cortex-A8 is ~45-100% depending on key
  32. # length, more for longer keys. On Cortex-A15 the span is ~10-105%.
  33. # On Snapdragon S4 improvement was measured to vary from ~70% to
  34. # incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is
  35. # rather because original integer-only code seems to perform
  36. # suboptimally on S4. Situation on Cortex-A9 is unfortunately
  37. # different. It's being looked into, but the trouble is that
  38. # performance for vectors longer than 256 bits is actually couple
  39. # of percent worse than for integer-only code. The code is chosen
  40. # for execution on all NEON-capable processors, because gain on
  41. # others outweighs the marginal loss on Cortex-A9.
  42. # September 2015
  43. #
  44. # Align Cortex-A9 performance with November 2013 improvements, i.e.
  45. # NEON code is now ~20-105% faster than integer-only one on this
  46. # processor. But this optimization further improved performance even
  47. # on other processors: NEON code path is ~45-180% faster than original
  48. # integer-only on Cortex-A8, ~10-210% on Cortex-A15, ~70-450% on
  49. # Snapdragon S4.
  50. $flavour = shift;
  51. if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
  52. else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
  53. if ($flavour && $flavour ne "void") {
  54. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  55. ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
  56. ( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
  57. die "can't locate arm-xlate.pl";
  58. open STDOUT,"| \"$^X\" $xlate $flavour $output";
  59. } else {
  60. open STDOUT,">$output";
  61. }
  62. $num="r0"; # starts as num argument, but holds &tp[num-1]
  63. $ap="r1";
  64. $bp="r2"; $bi="r2"; $rp="r2";
  65. $np="r3";
  66. $tp="r4";
  67. $aj="r5";
  68. $nj="r6";
  69. $tj="r7";
  70. $n0="r8";
  71. ########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer
  72. $alo="r10"; # sl, gcc uses it to keep @GOT
  73. $ahi="r11"; # fp
  74. $nlo="r12"; # ip
  75. ########### # r13 is stack pointer
  76. $nhi="r14"; # lr
  77. ########### # r15 is program counter
  78. #### argument block layout relative to &tp[num-1], a.k.a. $num
  79. $_rp="$num,#12*4";
  80. # ap permanently resides in r1
  81. $_bp="$num,#13*4";
  82. # np permanently resides in r3
  83. $_n0="$num,#14*4";
  84. $_num="$num,#15*4"; $_bpend=$_num;
  85. $code=<<___;
  86. #include <openssl/arm_arch.h>
  87. @ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
  88. @ ARMv7 and ARMv8 processors and does not use ARMv8 instructions.
  89. .arch armv7-a
  90. .text
  91. #if defined(__thumb2__)
  92. .syntax unified
  93. .thumb
  94. #else
  95. .code 32
  96. #endif
  97. #if __ARM_MAX_ARCH__>=7
  98. .align 5
  99. .LOPENSSL_armcap:
  100. .word OPENSSL_armcap_P-.Lbn_mul_mont
  101. #endif
  102. .global bn_mul_mont
  103. .type bn_mul_mont,%function
  104. .align 5
  105. bn_mul_mont:
  106. .Lbn_mul_mont:
  107. ldr ip,[sp,#4] @ load num
  108. stmdb sp!,{r0,r2} @ sp points at argument block
  109. #if __ARM_MAX_ARCH__>=7
  110. tst ip,#7
  111. bne .Lialu
  112. adr r0,.Lbn_mul_mont
  113. ldr r2,.LOPENSSL_armcap
  114. ldr r0,[r0,r2]
  115. #ifdef __APPLE__
  116. ldr r0,[r0]
  117. #endif
  118. tst r0,#ARMV7_NEON @ NEON available?
  119. ldmia sp, {r0,r2}
  120. beq .Lialu
  121. add sp,sp,#8
  122. b bn_mul8x_mont_neon
  123. .align 4
  124. .Lialu:
  125. #endif
  126. cmp ip,#2
  127. mov $num,ip @ load num
  128. #ifdef __thumb2__
  129. ittt lt
  130. #endif
  131. movlt r0,#0
  132. addlt sp,sp,#2*4
  133. blt .Labrt
  134. stmdb sp!,{r4-r12,lr} @ save 10 registers
  135. mov $num,$num,lsl#2 @ rescale $num for byte count
  136. sub sp,sp,$num @ alloca(4*num)
  137. sub sp,sp,#4 @ +extra dword
  138. sub $num,$num,#4 @ "num=num-1"
  139. add $tp,$bp,$num @ &bp[num-1]
  140. add $num,sp,$num @ $num to point at &tp[num-1]
  141. ldr $n0,[$_n0] @ &n0
  142. ldr $bi,[$bp] @ bp[0]
  143. ldr $aj,[$ap],#4 @ ap[0],ap++
  144. ldr $nj,[$np],#4 @ np[0],np++
  145. ldr $n0,[$n0] @ *n0
  146. str $tp,[$_bpend] @ save &bp[num]
  147. umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0]
  148. str $n0,[$_n0] @ save n0 value
  149. mul $n0,$alo,$n0 @ "tp[0]"*n0
  150. mov $nlo,#0
  151. umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]"
  152. mov $tp,sp
  153. .L1st:
  154. ldr $aj,[$ap],#4 @ ap[j],ap++
  155. mov $alo,$ahi
  156. ldr $nj,[$np],#4 @ np[j],np++
  157. mov $ahi,#0
  158. umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0]
  159. mov $nhi,#0
  160. umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
  161. adds $nlo,$nlo,$alo
  162. str $nlo,[$tp],#4 @ tp[j-1]=,tp++
  163. adc $nlo,$nhi,#0
  164. cmp $tp,$num
  165. bne .L1st
  166. adds $nlo,$nlo,$ahi
  167. ldr $tp,[$_bp] @ restore bp
  168. mov $nhi,#0
  169. ldr $n0,[$_n0] @ restore n0
  170. adc $nhi,$nhi,#0
  171. str $nlo,[$num] @ tp[num-1]=
  172. mov $tj,sp
  173. str $nhi,[$num,#4] @ tp[num]=
  174. .Louter:
  175. sub $tj,$num,$tj @ "original" $num-1 value
  176. sub $ap,$ap,$tj @ "rewind" ap to &ap[1]
  177. ldr $bi,[$tp,#4]! @ *(++bp)
  178. sub $np,$np,$tj @ "rewind" np to &np[1]
  179. ldr $aj,[$ap,#-4] @ ap[0]
  180. ldr $alo,[sp] @ tp[0]
  181. ldr $nj,[$np,#-4] @ np[0]
  182. ldr $tj,[sp,#4] @ tp[1]
  183. mov $ahi,#0
  184. umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0]
  185. str $tp,[$_bp] @ save bp
  186. mul $n0,$alo,$n0
  187. mov $nlo,#0
  188. umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]"
  189. mov $tp,sp
  190. .Linner:
  191. ldr $aj,[$ap],#4 @ ap[j],ap++
  192. adds $alo,$ahi,$tj @ +=tp[j]
  193. ldr $nj,[$np],#4 @ np[j],np++
  194. mov $ahi,#0
  195. umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i]
  196. mov $nhi,#0
  197. umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
  198. adc $ahi,$ahi,#0
  199. ldr $tj,[$tp,#8] @ tp[j+1]
  200. adds $nlo,$nlo,$alo
  201. str $nlo,[$tp],#4 @ tp[j-1]=,tp++
  202. adc $nlo,$nhi,#0
  203. cmp $tp,$num
  204. bne .Linner
  205. adds $nlo,$nlo,$ahi
  206. mov $nhi,#0
  207. ldr $tp,[$_bp] @ restore bp
  208. adc $nhi,$nhi,#0
  209. ldr $n0,[$_n0] @ restore n0
  210. adds $nlo,$nlo,$tj
  211. ldr $tj,[$_bpend] @ restore &bp[num]
  212. adc $nhi,$nhi,#0
  213. str $nlo,[$num] @ tp[num-1]=
  214. str $nhi,[$num,#4] @ tp[num]=
  215. cmp $tp,$tj
  216. #ifdef __thumb2__
  217. itt ne
  218. #endif
  219. movne $tj,sp
  220. bne .Louter
  221. ldr $rp,[$_rp] @ pull rp
  222. mov $aj,sp
  223. add $num,$num,#4 @ $num to point at &tp[num]
  224. sub $aj,$num,$aj @ "original" num value
  225. mov $tp,sp @ "rewind" $tp
  226. mov $ap,$tp @ "borrow" $ap
  227. sub $np,$np,$aj @ "rewind" $np to &np[0]
  228. subs $tj,$tj,$tj @ "clear" carry flag
  229. .Lsub: ldr $tj,[$tp],#4
  230. ldr $nj,[$np],#4
  231. sbcs $tj,$tj,$nj @ tp[j]-np[j]
  232. str $tj,[$rp],#4 @ rp[j]=
  233. teq $tp,$num @ preserve carry
  234. bne .Lsub
  235. sbcs $nhi,$nhi,#0 @ upmost carry
  236. mov $tp,sp @ "rewind" $tp
  237. sub $rp,$rp,$aj @ "rewind" $rp
  238. .Lcopy: ldr $tj,[$tp] @ conditional copy
  239. ldr $aj,[$rp]
  240. str sp,[$tp],#4 @ zap tp
  241. #ifdef __thumb2__
  242. it cc
  243. #endif
  244. movcc $aj,$tj
  245. str $aj,[$rp],#4
  246. teq $tp,$num @ preserve carry
  247. bne .Lcopy
  248. mov sp,$num
  249. add sp,sp,#4 @ skip over tp[num+1]
  250. ldmia sp!,{r4-r12,lr} @ restore registers
  251. add sp,sp,#2*4 @ skip over {r0,r2}
  252. mov r0,#1
  253. .Labrt:
  254. #if __ARM_ARCH__>=5
  255. ret @ bx lr
  256. #else
  257. tst lr,#1
  258. moveq pc,lr @ be binary compatible with V4, yet
  259. bx lr @ interoperable with Thumb ISA:-)
  260. #endif
  261. .size bn_mul_mont,.-bn_mul_mont
  262. ___
  263. {
  264. my ($A0,$A1,$A2,$A3)=map("d$_",(0..3));
  265. my ($N0,$N1,$N2,$N3)=map("d$_",(4..7));
  266. my ($Z,$Temp)=("q4","q5");
  267. my @ACC=map("q$_",(6..13));
  268. my ($Bi,$Ni,$M0)=map("d$_",(28..31));
  269. my $zero="$Z#lo";
  270. my $temp="$Temp#lo";
  271. my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5));
  272. my ($tinptr,$toutptr,$inner,$outer,$bnptr)=map("r$_",(6..11));
  273. $code.=<<___;
  274. #if __ARM_MAX_ARCH__>=7
  275. .arch armv7-a
  276. .fpu neon
  277. .type bn_mul8x_mont_neon,%function
  278. .align 5
  279. bn_mul8x_mont_neon:
  280. mov ip,sp
  281. stmdb sp!,{r4-r11}
  282. vstmdb sp!,{d8-d15} @ ABI specification says so
  283. ldmia ip,{r4-r5} @ load rest of parameter block
  284. mov ip,sp
  285. cmp $num,#8
  286. bhi .LNEON_8n
  287. @ special case for $num==8, everything is in register bank...
  288. vld1.32 {${Bi}[0]}, [$bptr,:32]!
  289. veor $zero,$zero,$zero
  290. sub $toutptr,sp,$num,lsl#4
  291. vld1.32 {$A0-$A3}, [$aptr]! @ can't specify :32 :-(
  292. and $toutptr,$toutptr,#-64
  293. vld1.32 {${M0}[0]}, [$n0,:32]
  294. mov sp,$toutptr @ alloca
  295. vzip.16 $Bi,$zero
  296. vmull.u32 @ACC[0],$Bi,${A0}[0]
  297. vmull.u32 @ACC[1],$Bi,${A0}[1]
  298. vmull.u32 @ACC[2],$Bi,${A1}[0]
  299. vshl.i64 $Ni,@ACC[0]#hi,#16
  300. vmull.u32 @ACC[3],$Bi,${A1}[1]
  301. vadd.u64 $Ni,$Ni,@ACC[0]#lo
  302. veor $zero,$zero,$zero
  303. vmul.u32 $Ni,$Ni,$M0
  304. vmull.u32 @ACC[4],$Bi,${A2}[0]
  305. vld1.32 {$N0-$N3}, [$nptr]!
  306. vmull.u32 @ACC[5],$Bi,${A2}[1]
  307. vmull.u32 @ACC[6],$Bi,${A3}[0]
  308. vzip.16 $Ni,$zero
  309. vmull.u32 @ACC[7],$Bi,${A3}[1]
  310. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  311. sub $outer,$num,#1
  312. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  313. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  314. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  315. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  316. vmov $Temp,@ACC[0]
  317. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  318. vmov @ACC[0],@ACC[1]
  319. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  320. vmov @ACC[1],@ACC[2]
  321. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  322. vmov @ACC[2],@ACC[3]
  323. vmov @ACC[3],@ACC[4]
  324. vshr.u64 $temp,$temp,#16
  325. vmov @ACC[4],@ACC[5]
  326. vmov @ACC[5],@ACC[6]
  327. vadd.u64 $temp,$temp,$Temp#hi
  328. vmov @ACC[6],@ACC[7]
  329. veor @ACC[7],@ACC[7]
  330. vshr.u64 $temp,$temp,#16
  331. b .LNEON_outer8
  332. .align 4
  333. .LNEON_outer8:
  334. vld1.32 {${Bi}[0]}, [$bptr,:32]!
  335. veor $zero,$zero,$zero
  336. vzip.16 $Bi,$zero
  337. vadd.u64 @ACC[0]#lo,@ACC[0]#lo,$temp
  338. vmlal.u32 @ACC[0],$Bi,${A0}[0]
  339. vmlal.u32 @ACC[1],$Bi,${A0}[1]
  340. vmlal.u32 @ACC[2],$Bi,${A1}[0]
  341. vshl.i64 $Ni,@ACC[0]#hi,#16
  342. vmlal.u32 @ACC[3],$Bi,${A1}[1]
  343. vadd.u64 $Ni,$Ni,@ACC[0]#lo
  344. veor $zero,$zero,$zero
  345. subs $outer,$outer,#1
  346. vmul.u32 $Ni,$Ni,$M0
  347. vmlal.u32 @ACC[4],$Bi,${A2}[0]
  348. vmlal.u32 @ACC[5],$Bi,${A2}[1]
  349. vmlal.u32 @ACC[6],$Bi,${A3}[0]
  350. vzip.16 $Ni,$zero
  351. vmlal.u32 @ACC[7],$Bi,${A3}[1]
  352. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  353. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  354. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  355. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  356. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  357. vmov $Temp,@ACC[0]
  358. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  359. vmov @ACC[0],@ACC[1]
  360. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  361. vmov @ACC[1],@ACC[2]
  362. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  363. vmov @ACC[2],@ACC[3]
  364. vmov @ACC[3],@ACC[4]
  365. vshr.u64 $temp,$temp,#16
  366. vmov @ACC[4],@ACC[5]
  367. vmov @ACC[5],@ACC[6]
  368. vadd.u64 $temp,$temp,$Temp#hi
  369. vmov @ACC[6],@ACC[7]
  370. veor @ACC[7],@ACC[7]
  371. vshr.u64 $temp,$temp,#16
  372. bne .LNEON_outer8
  373. vadd.u64 @ACC[0]#lo,@ACC[0]#lo,$temp
  374. mov $toutptr,sp
  375. vshr.u64 $temp,@ACC[0]#lo,#16
  376. mov $inner,$num
  377. vadd.u64 @ACC[0]#hi,@ACC[0]#hi,$temp
  378. add $tinptr,sp,#96
  379. vshr.u64 $temp,@ACC[0]#hi,#16
  380. vzip.16 @ACC[0]#lo,@ACC[0]#hi
  381. b .LNEON_tail_entry
  382. .align 4
  383. .LNEON_8n:
  384. veor @ACC[0],@ACC[0],@ACC[0]
  385. sub $toutptr,sp,#128
  386. veor @ACC[1],@ACC[1],@ACC[1]
  387. sub $toutptr,$toutptr,$num,lsl#4
  388. veor @ACC[2],@ACC[2],@ACC[2]
  389. and $toutptr,$toutptr,#-64
  390. veor @ACC[3],@ACC[3],@ACC[3]
  391. mov sp,$toutptr @ alloca
  392. veor @ACC[4],@ACC[4],@ACC[4]
  393. add $toutptr,$toutptr,#256
  394. veor @ACC[5],@ACC[5],@ACC[5]
  395. sub $inner,$num,#8
  396. veor @ACC[6],@ACC[6],@ACC[6]
  397. veor @ACC[7],@ACC[7],@ACC[7]
  398. .LNEON_8n_init:
  399. vst1.64 {@ACC[0]-@ACC[1]},[$toutptr,:256]!
  400. subs $inner,$inner,#8
  401. vst1.64 {@ACC[2]-@ACC[3]},[$toutptr,:256]!
  402. vst1.64 {@ACC[4]-@ACC[5]},[$toutptr,:256]!
  403. vst1.64 {@ACC[6]-@ACC[7]},[$toutptr,:256]!
  404. bne .LNEON_8n_init
  405. add $tinptr,sp,#256
  406. vld1.32 {$A0-$A3},[$aptr]!
  407. add $bnptr,sp,#8
  408. vld1.32 {${M0}[0]},[$n0,:32]
  409. mov $outer,$num
  410. b .LNEON_8n_outer
  411. .align 4
  412. .LNEON_8n_outer:
  413. vld1.32 {${Bi}[0]},[$bptr,:32]! @ *b++
  414. veor $zero,$zero,$zero
  415. vzip.16 $Bi,$zero
  416. add $toutptr,sp,#128
  417. vld1.32 {$N0-$N3},[$nptr]!
  418. vmlal.u32 @ACC[0],$Bi,${A0}[0]
  419. vmlal.u32 @ACC[1],$Bi,${A0}[1]
  420. veor $zero,$zero,$zero
  421. vmlal.u32 @ACC[2],$Bi,${A1}[0]
  422. vshl.i64 $Ni,@ACC[0]#hi,#16
  423. vmlal.u32 @ACC[3],$Bi,${A1}[1]
  424. vadd.u64 $Ni,$Ni,@ACC[0]#lo
  425. vmlal.u32 @ACC[4],$Bi,${A2}[0]
  426. vmul.u32 $Ni,$Ni,$M0
  427. vmlal.u32 @ACC[5],$Bi,${A2}[1]
  428. vst1.32 {$Bi},[sp,:64] @ put aside smashed b[8*i+0]
  429. vmlal.u32 @ACC[6],$Bi,${A3}[0]
  430. vzip.16 $Ni,$zero
  431. vmlal.u32 @ACC[7],$Bi,${A3}[1]
  432. ___
  433. for ($i=0; $i<7;) {
  434. $code.=<<___;
  435. vld1.32 {${Bi}[0]},[$bptr,:32]! @ *b++
  436. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  437. veor $temp,$temp,$temp
  438. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  439. vzip.16 $Bi,$temp
  440. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  441. vshr.u64 @ACC[0]#lo,@ACC[0]#lo,#16
  442. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  443. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  444. vadd.u64 @ACC[0]#lo,@ACC[0]#lo,@ACC[0]#hi
  445. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  446. vshr.u64 @ACC[0]#lo,@ACC[0]#lo,#16
  447. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  448. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  449. vadd.u64 @ACC[1]#lo,@ACC[1]#lo,@ACC[0]#lo
  450. vst1.32 {$Ni},[$bnptr,:64]! @ put aside smashed m[8*i+$i]
  451. ___
  452. push(@ACC,shift(@ACC)); $i++;
  453. $code.=<<___;
  454. vmlal.u32 @ACC[0],$Bi,${A0}[0]
  455. vld1.64 {@ACC[7]},[$tinptr,:128]!
  456. vmlal.u32 @ACC[1],$Bi,${A0}[1]
  457. veor $zero,$zero,$zero
  458. vmlal.u32 @ACC[2],$Bi,${A1}[0]
  459. vshl.i64 $Ni,@ACC[0]#hi,#16
  460. vmlal.u32 @ACC[3],$Bi,${A1}[1]
  461. vadd.u64 $Ni,$Ni,@ACC[0]#lo
  462. vmlal.u32 @ACC[4],$Bi,${A2}[0]
  463. vmul.u32 $Ni,$Ni,$M0
  464. vmlal.u32 @ACC[5],$Bi,${A2}[1]
  465. vst1.32 {$Bi},[$bnptr,:64]! @ put aside smashed b[8*i+$i]
  466. vmlal.u32 @ACC[6],$Bi,${A3}[0]
  467. vzip.16 $Ni,$zero
  468. vmlal.u32 @ACC[7],$Bi,${A3}[1]
  469. ___
  470. }
  471. $code.=<<___;
  472. vld1.32 {$Bi},[sp,:64] @ pull smashed b[8*i+0]
  473. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  474. vld1.32 {$A0-$A3},[$aptr]!
  475. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  476. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  477. vshr.u64 @ACC[0]#lo,@ACC[0]#lo,#16
  478. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  479. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  480. vadd.u64 @ACC[0]#lo,@ACC[0]#lo,@ACC[0]#hi
  481. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  482. vshr.u64 @ACC[0]#lo,@ACC[0]#lo,#16
  483. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  484. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  485. vadd.u64 @ACC[1]#lo,@ACC[1]#lo,@ACC[0]#lo
  486. vst1.32 {$Ni},[$bnptr,:64] @ put aside smashed m[8*i+$i]
  487. add $bnptr,sp,#8 @ rewind
  488. ___
  489. push(@ACC,shift(@ACC));
  490. $code.=<<___;
  491. sub $inner,$num,#8
  492. b .LNEON_8n_inner
  493. .align 4
  494. .LNEON_8n_inner:
  495. subs $inner,$inner,#8
  496. vmlal.u32 @ACC[0],$Bi,${A0}[0]
  497. vld1.64 {@ACC[7]},[$tinptr,:128]
  498. vmlal.u32 @ACC[1],$Bi,${A0}[1]
  499. vld1.32 {$Ni},[$bnptr,:64]! @ pull smashed m[8*i+0]
  500. vmlal.u32 @ACC[2],$Bi,${A1}[0]
  501. vld1.32 {$N0-$N3},[$nptr]!
  502. vmlal.u32 @ACC[3],$Bi,${A1}[1]
  503. it ne
  504. addne $tinptr,$tinptr,#16 @ don't advance in last iteration
  505. vmlal.u32 @ACC[4],$Bi,${A2}[0]
  506. vmlal.u32 @ACC[5],$Bi,${A2}[1]
  507. vmlal.u32 @ACC[6],$Bi,${A3}[0]
  508. vmlal.u32 @ACC[7],$Bi,${A3}[1]
  509. ___
  510. for ($i=1; $i<8; $i++) {
  511. $code.=<<___;
  512. vld1.32 {$Bi},[$bnptr,:64]! @ pull smashed b[8*i+$i]
  513. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  514. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  515. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  516. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  517. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  518. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  519. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  520. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  521. vst1.64 {@ACC[0]},[$toutptr,:128]!
  522. ___
  523. push(@ACC,shift(@ACC));
  524. $code.=<<___;
  525. vmlal.u32 @ACC[0],$Bi,${A0}[0]
  526. vld1.64 {@ACC[7]},[$tinptr,:128]
  527. vmlal.u32 @ACC[1],$Bi,${A0}[1]
  528. vld1.32 {$Ni},[$bnptr,:64]! @ pull smashed m[8*i+$i]
  529. vmlal.u32 @ACC[2],$Bi,${A1}[0]
  530. it ne
  531. addne $tinptr,$tinptr,#16 @ don't advance in last iteration
  532. vmlal.u32 @ACC[3],$Bi,${A1}[1]
  533. vmlal.u32 @ACC[4],$Bi,${A2}[0]
  534. vmlal.u32 @ACC[5],$Bi,${A2}[1]
  535. vmlal.u32 @ACC[6],$Bi,${A3}[0]
  536. vmlal.u32 @ACC[7],$Bi,${A3}[1]
  537. ___
  538. }
  539. $code.=<<___;
  540. it eq
  541. subeq $aptr,$aptr,$num,lsl#2 @ rewind
  542. vmlal.u32 @ACC[0],$Ni,${N0}[0]
  543. vld1.32 {$Bi},[sp,:64] @ pull smashed b[8*i+0]
  544. vmlal.u32 @ACC[1],$Ni,${N0}[1]
  545. vld1.32 {$A0-$A3},[$aptr]!
  546. vmlal.u32 @ACC[2],$Ni,${N1}[0]
  547. add $bnptr,sp,#8 @ rewind
  548. vmlal.u32 @ACC[3],$Ni,${N1}[1]
  549. vmlal.u32 @ACC[4],$Ni,${N2}[0]
  550. vmlal.u32 @ACC[5],$Ni,${N2}[1]
  551. vmlal.u32 @ACC[6],$Ni,${N3}[0]
  552. vst1.64 {@ACC[0]},[$toutptr,:128]!
  553. vmlal.u32 @ACC[7],$Ni,${N3}[1]
  554. bne .LNEON_8n_inner
  555. ___
  556. push(@ACC,shift(@ACC));
  557. $code.=<<___;
  558. add $tinptr,sp,#128
  559. vst1.64 {@ACC[0]-@ACC[1]},[$toutptr,:256]!
  560. veor q2,q2,q2 @ $N0-$N1
  561. vst1.64 {@ACC[2]-@ACC[3]},[$toutptr,:256]!
  562. veor q3,q3,q3 @ $N2-$N3
  563. vst1.64 {@ACC[4]-@ACC[5]},[$toutptr,:256]!
  564. vst1.64 {@ACC[6]},[$toutptr,:128]
  565. subs $outer,$outer,#8
  566. vld1.64 {@ACC[0]-@ACC[1]},[$tinptr,:256]!
  567. vld1.64 {@ACC[2]-@ACC[3]},[$tinptr,:256]!
  568. vld1.64 {@ACC[4]-@ACC[5]},[$tinptr,:256]!
  569. vld1.64 {@ACC[6]-@ACC[7]},[$tinptr,:256]!
  570. itt ne
  571. subne $nptr,$nptr,$num,lsl#2 @ rewind
  572. bne .LNEON_8n_outer
  573. add $toutptr,sp,#128
  574. vst1.64 {q2-q3}, [sp,:256]! @ start wiping stack frame
  575. vshr.u64 $temp,@ACC[0]#lo,#16
  576. vst1.64 {q2-q3},[sp,:256]!
  577. vadd.u64 @ACC[0]#hi,@ACC[0]#hi,$temp
  578. vst1.64 {q2-q3}, [sp,:256]!
  579. vshr.u64 $temp,@ACC[0]#hi,#16
  580. vst1.64 {q2-q3}, [sp,:256]!
  581. vzip.16 @ACC[0]#lo,@ACC[0]#hi
  582. mov $inner,$num
  583. b .LNEON_tail_entry
  584. .align 4
  585. .LNEON_tail:
  586. vadd.u64 @ACC[0]#lo,@ACC[0]#lo,$temp
  587. vshr.u64 $temp,@ACC[0]#lo,#16
  588. vld1.64 {@ACC[2]-@ACC[3]}, [$tinptr, :256]!
  589. vadd.u64 @ACC[0]#hi,@ACC[0]#hi,$temp
  590. vld1.64 {@ACC[4]-@ACC[5]}, [$tinptr, :256]!
  591. vshr.u64 $temp,@ACC[0]#hi,#16
  592. vld1.64 {@ACC[6]-@ACC[7]}, [$tinptr, :256]!
  593. vzip.16 @ACC[0]#lo,@ACC[0]#hi
  594. .LNEON_tail_entry:
  595. ___
  596. for ($i=1; $i<8; $i++) {
  597. $code.=<<___;
  598. vadd.u64 @ACC[1]#lo,@ACC[1]#lo,$temp
  599. vst1.32 {@ACC[0]#lo[0]}, [$toutptr, :32]!
  600. vshr.u64 $temp,@ACC[1]#lo,#16
  601. vadd.u64 @ACC[1]#hi,@ACC[1]#hi,$temp
  602. vshr.u64 $temp,@ACC[1]#hi,#16
  603. vzip.16 @ACC[1]#lo,@ACC[1]#hi
  604. ___
  605. push(@ACC,shift(@ACC));
  606. }
  607. push(@ACC,shift(@ACC));
  608. $code.=<<___;
  609. vld1.64 {@ACC[0]-@ACC[1]}, [$tinptr, :256]!
  610. subs $inner,$inner,#8
  611. vst1.32 {@ACC[7]#lo[0]}, [$toutptr, :32]!
  612. bne .LNEON_tail
  613. vst1.32 {${temp}[0]}, [$toutptr, :32] @ top-most bit
  614. sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr
  615. subs $aptr,sp,#0 @ clear carry flag
  616. add $bptr,sp,$num,lsl#2
  617. .LNEON_sub:
  618. ldmia $aptr!, {r4-r7}
  619. ldmia $nptr!, {r8-r11}
  620. sbcs r8, r4,r8
  621. sbcs r9, r5,r9
  622. sbcs r10,r6,r10
  623. sbcs r11,r7,r11
  624. teq $aptr,$bptr @ preserves carry
  625. stmia $rptr!, {r8-r11}
  626. bne .LNEON_sub
  627. ldr r10, [$aptr] @ load top-most bit
  628. mov r11,sp
  629. veor q0,q0,q0
  630. sub r11,$bptr,r11 @ this is num*4
  631. veor q1,q1,q1
  632. mov $aptr,sp
  633. sub $rptr,$rptr,r11 @ rewind $rptr
  634. mov $nptr,$bptr @ second 3/4th of frame
  635. sbcs r10,r10,#0 @ result is carry flag
  636. .LNEON_copy_n_zap:
  637. ldmia $aptr!, {r4-r7}
  638. ldmia $rptr, {r8-r11}
  639. it cc
  640. movcc r8, r4
  641. vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
  642. itt cc
  643. movcc r9, r5
  644. movcc r10,r6
  645. vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
  646. it cc
  647. movcc r11,r7
  648. ldmia $aptr, {r4-r7}
  649. stmia $rptr!, {r8-r11}
  650. sub $aptr,$aptr,#16
  651. ldmia $rptr, {r8-r11}
  652. it cc
  653. movcc r8, r4
  654. vst1.64 {q0-q1}, [$aptr,:256]! @ wipe
  655. itt cc
  656. movcc r9, r5
  657. movcc r10,r6
  658. vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
  659. it cc
  660. movcc r11,r7
  661. teq $aptr,$bptr @ preserves carry
  662. stmia $rptr!, {r8-r11}
  663. bne .LNEON_copy_n_zap
  664. mov sp,ip
  665. vldmia sp!,{d8-d15}
  666. ldmia sp!,{r4-r11}
  667. ret @ bx lr
  668. .size bn_mul8x_mont_neon,.-bn_mul8x_mont_neon
  669. #endif
  670. ___
  671. }
  672. $code.=<<___;
  673. .asciz "Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
  674. .align 2
  675. #if __ARM_MAX_ARCH__>=7
  676. .comm OPENSSL_armcap_P,4,4
  677. .hidden OPENSSL_armcap_P
  678. #endif
  679. ___
  680. foreach (split("\n",$code)) {
  681. s/\`([^\`]*)\`/eval $1/ge;
  682. s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/ge or
  683. s/\bret\b/bx lr/g or
  684. s/\bbx\s+lr\b/.word\t0xe12fff1e/g; # make it possible to compile with -march=armv4
  685. print $_,"\n";
  686. }
  687. close STDOUT;