armv4-mont.pl 19 KB

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