sha512-sse2.pl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. #!/usr/bin/env perl
  2. #
  3. # ====================================================================
  4. # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
  5. # project. Rights for redistribution and usage in source and binary
  6. # forms are granted according to the OpenSSL license.
  7. # ====================================================================
  8. #
  9. # SHA512_Transform_SSE2.
  10. #
  11. # As the name suggests, this is an IA-32 SSE2 implementation of
  12. # SHA512_Transform. Motivating factor for the undertaken effort was that
  13. # SHA512 was observed to *consistently* perform *significantly* poorer
  14. # than SHA256 [2x and slower is common] on 32-bit platforms. On 64-bit
  15. # platforms on the other hand SHA512 tend to outperform SHA256 [~50%
  16. # seem to be common improvement factor]. All this is perfectly natural,
  17. # as SHA512 is a 64-bit algorithm. But isn't IA-32 SSE2 essentially
  18. # a 64-bit instruction set? Is it rich enough to implement SHA512?
  19. # If answer was "no," then you wouldn't have been reading this...
  20. #
  21. # Throughput performance in MBps (larger is better):
  22. #
  23. # 2.4GHz P4 1.4GHz AMD32 1.4GHz AMD64(*)
  24. # SHA256/gcc(*) 54 43 59
  25. # SHA512/gcc 17 23 92
  26. # SHA512/sse2 61(**) 57(**)
  27. # SHA512/icc 26 28
  28. # SHA256/icc(*) 65 54
  29. #
  30. # (*) AMD64 and SHA256 numbers are presented mostly for amusement or
  31. # reference purposes.
  32. # (**) I.e. it gives ~2-3x speed-up if compared with compiler generated
  33. # code. One can argue that hand-coded *non*-SSE2 implementation
  34. # would perform better than compiler generated one as well, and
  35. # that comparison is therefore not exactly fair. Well, as SHA512
  36. # puts enormous pressure on IA-32 GP register bank, I reckon that
  37. # hand-coded version wouldn't perform significantly better than
  38. # one compiled with icc, ~20% perhaps... So that this code would
  39. # still outperform it with distinguishing marginal. But feel free
  40. # to prove me wrong:-)
  41. # <appro@fy.chalmers.se>
  42. push(@INC,"perlasm","../../perlasm");
  43. require "x86asm.pl";
  44. &asm_init($ARGV[0],"sha512-sse2.pl",$ARGV[$#ARGV] eq "386");
  45. $K512="esi"; # K512[80] table, found at the end...
  46. #$W512="esp"; # $W512 is not just W512[16]: it comprises *two* copies
  47. # of W512[16] and a copy of A-H variables...
  48. $W512_SZ=8*(16+16+8); # see above...
  49. #$Kidx="ebx"; # index in K512 table, advances from 0 to 80...
  50. $Widx="edx"; # index in W512, wraps around at 16...
  51. $data="edi"; # 16 qwords of input data...
  52. $A="mm0"; # B-D and
  53. $E="mm1"; # F-H are allocated dynamically...
  54. $Aoff=256+0; # A-H offsets relative to $W512...
  55. $Boff=256+8;
  56. $Coff=256+16;
  57. $Doff=256+24;
  58. $Eoff=256+32;
  59. $Foff=256+40;
  60. $Goff=256+48;
  61. $Hoff=256+56;
  62. sub SHA2_ROUND()
  63. { local ($kidx,$widx)=@_;
  64. # One can argue that one could reorder instructions for better
  65. # performance. Well, I tried and it doesn't seem to make any
  66. # noticeable difference. Modern out-of-order execution cores
  67. # reorder instructions to their liking in either case and they
  68. # apparently do decent job. So we can keep the code more
  69. # readable/regular/comprehensible:-)
  70. # I adhere to 64-bit %mmX registers in order to avoid/not care
  71. # about #GP exceptions on misaligned 128-bit access, most
  72. # notably in paddq with memory operand. Not to mention that
  73. # SSE2 intructions operating on %mmX can be scheduled every
  74. # cycle [and not every second one if operating on %xmmN].
  75. &movq ("mm4",&QWP($Foff,$W512)); # load f
  76. &movq ("mm5",&QWP($Goff,$W512)); # load g
  77. &movq ("mm6",&QWP($Hoff,$W512)); # load h
  78. &movq ("mm2",$E); # %mm2 is sliding right
  79. &movq ("mm3",$E); # %mm3 is sliding left
  80. &psrlq ("mm2",14);
  81. &psllq ("mm3",23);
  82. &movq ("mm7","mm2"); # %mm7 is T1
  83. &pxor ("mm7","mm3");
  84. &psrlq ("mm2",4);
  85. &psllq ("mm3",23);
  86. &pxor ("mm7","mm2");
  87. &pxor ("mm7","mm3");
  88. &psrlq ("mm2",23);
  89. &psllq ("mm3",4);
  90. &pxor ("mm7","mm2");
  91. &pxor ("mm7","mm3"); # T1=Sigma1_512(e)
  92. &movq (&QWP($Foff,$W512),$E); # f = e
  93. &movq (&QWP($Goff,$W512),"mm4"); # g = f
  94. &movq (&QWP($Hoff,$W512),"mm5"); # h = g
  95. &pxor ("mm4","mm5"); # f^=g
  96. &pand ("mm4",$E); # f&=e
  97. &pxor ("mm4","mm5"); # f^=g
  98. &paddq ("mm7","mm4"); # T1+=Ch(e,f,g)
  99. &movq ("mm2",&QWP($Boff,$W512)); # load b
  100. &movq ("mm3",&QWP($Coff,$W512)); # load c
  101. &movq ($E,&QWP($Doff,$W512)); # e = d
  102. &paddq ("mm7","mm6"); # T1+=h
  103. &paddq ("mm7",&QWP(0,$K512,$kidx,8)); # T1+=K512[i]
  104. &paddq ("mm7",&QWP(0,$W512,$widx,8)); # T1+=W512[i]
  105. &paddq ($E,"mm7"); # e += T1
  106. &movq ("mm4",$A); # %mm4 is sliding right
  107. &movq ("mm5",$A); # %mm5 is sliding left
  108. &psrlq ("mm4",28);
  109. &psllq ("mm5",25);
  110. &movq ("mm6","mm4"); # %mm6 is T2
  111. &pxor ("mm6","mm5");
  112. &psrlq ("mm4",6);
  113. &psllq ("mm5",5);
  114. &pxor ("mm6","mm4");
  115. &pxor ("mm6","mm5");
  116. &psrlq ("mm4",5);
  117. &psllq ("mm5",6);
  118. &pxor ("mm6","mm4");
  119. &pxor ("mm6","mm5"); # T2=Sigma0_512(a)
  120. &movq (&QWP($Boff,$W512),$A); # b = a
  121. &movq (&QWP($Coff,$W512),"mm2"); # c = b
  122. &movq (&QWP($Doff,$W512),"mm3"); # d = c
  123. &movq ("mm4",$A); # %mm4=a
  124. &por ($A,"mm3"); # a=a|c
  125. &pand ("mm4","mm3"); # %mm4=a&c
  126. &pand ($A,"mm2"); # a=(a|c)&b
  127. &por ("mm4",$A); # %mm4=(a&c)|((a|c)&b)
  128. &paddq ("mm6","mm4"); # T2+=Maj(a,b,c)
  129. &movq ($A,"mm7"); # a=T1
  130. &paddq ($A,"mm6"); # a+=T2
  131. }
  132. $func="sha512_block_sse2";
  133. &function_begin_B($func);
  134. if (0) {# Caller is expected to check if it's appropriate to
  135. # call this routine. Below 3 lines are retained for
  136. # debugging purposes...
  137. &picmeup("eax","OPENSSL_ia32cap");
  138. &bt (&DWP(0,"eax"),26);
  139. &jnc ("SHA512_Transform");
  140. }
  141. &push ("ebp");
  142. &mov ("ebp","esp");
  143. &push ("ebx");
  144. &push ("esi");
  145. &push ("edi");
  146. &mov ($Widx,&DWP(8,"ebp")); # A-H state, 1st arg
  147. &mov ($data,&DWP(12,"ebp")); # input data, 2nd arg
  148. &call (&label("pic_point")); # make it PIC!
  149. &set_label("pic_point");
  150. &blindpop($K512);
  151. &lea ($K512,&DWP(&label("K512")."-".&label("pic_point"),$K512));
  152. $W512 = "esp"; # start using %esp as W512
  153. &sub ($W512,$W512_SZ);
  154. &and ($W512,-16); # ensure 128-bit alignment
  155. # make private copy of A-H
  156. # v assume the worst and stick to unaligned load
  157. &movdqu ("xmm0",&QWP(0,$Widx));
  158. &movdqu ("xmm1",&QWP(16,$Widx));
  159. &movdqu ("xmm2",&QWP(32,$Widx));
  160. &movdqu ("xmm3",&QWP(48,$Widx));
  161. &align(8);
  162. &set_label("_chunk_loop");
  163. &movdqa (&QWP($Aoff,$W512),"xmm0"); # a,b
  164. &movdqa (&QWP($Coff,$W512),"xmm1"); # c,d
  165. &movdqa (&QWP($Eoff,$W512),"xmm2"); # e,f
  166. &movdqa (&QWP($Goff,$W512),"xmm3"); # g,h
  167. &xor ($Widx,$Widx);
  168. &movdq2q($A,"xmm0"); # load a
  169. &movdq2q($E,"xmm2"); # load e
  170. # Why aren't loops unrolled? It makes sense to unroll if
  171. # execution time for loop body is comparable with branch
  172. # penalties and/or if whole data-set resides in register bank.
  173. # Neither is case here... Well, it would be possible to
  174. # eliminate few store operations, but it would hardly affect
  175. # so to say stop-watch performance, as there is a lot of
  176. # available memory slots to fill. It will only relieve some
  177. # pressure off memory bus...
  178. # flip input stream byte order...
  179. &mov ("eax",&DWP(0,$data,$Widx,8));
  180. &mov ("ebx",&DWP(4,$data,$Widx,8));
  181. &bswap ("eax");
  182. &bswap ("ebx");
  183. &mov (&DWP(0,$W512,$Widx,8),"ebx"); # W512[i]
  184. &mov (&DWP(4,$W512,$Widx,8),"eax");
  185. &mov (&DWP(128+0,$W512,$Widx,8),"ebx"); # copy of W512[i]
  186. &mov (&DWP(128+4,$W512,$Widx,8),"eax");
  187. &align(8);
  188. &set_label("_1st_loop"); # 0-15
  189. # flip input stream byte order...
  190. &mov ("eax",&DWP(0+8,$data,$Widx,8));
  191. &mov ("ebx",&DWP(4+8,$data,$Widx,8));
  192. &bswap ("eax");
  193. &bswap ("ebx");
  194. &mov (&DWP(0+8,$W512,$Widx,8),"ebx"); # W512[i]
  195. &mov (&DWP(4+8,$W512,$Widx,8),"eax");
  196. &mov (&DWP(128+0+8,$W512,$Widx,8),"ebx"); # copy of W512[i]
  197. &mov (&DWP(128+4+8,$W512,$Widx,8),"eax");
  198. &set_label("_1st_looplet");
  199. &SHA2_ROUND($Widx,$Widx); &inc($Widx);
  200. &cmp ($Widx,15)
  201. &jl (&label("_1st_loop"));
  202. &je (&label("_1st_looplet")); # playing similar trick on 2nd loop
  203. # does not improve performance...
  204. $Kidx = "ebx"; # start using %ebx as Kidx
  205. &mov ($Kidx,$Widx);
  206. &align(8);
  207. &set_label("_2nd_loop"); # 16-79
  208. &and($Widx,0xf);
  209. # 128-bit fragment! I update W512[i] and W512[i+1] in
  210. # parallel:-) Note that I refer to W512[(i&0xf)+N] and not to
  211. # W512[(i+N)&0xf]! This is exactly what I maintain the second
  212. # copy of W512[16] for...
  213. &movdqu ("xmm0",&QWP(8*1,$W512,$Widx,8)); # s0=W512[i+1]
  214. &movdqa ("xmm2","xmm0"); # %xmm2 is sliding right
  215. &movdqa ("xmm3","xmm0"); # %xmm3 is sliding left
  216. &psrlq ("xmm2",1);
  217. &psllq ("xmm3",56);
  218. &movdqa ("xmm0","xmm2");
  219. &pxor ("xmm0","xmm3");
  220. &psrlq ("xmm2",6);
  221. &psllq ("xmm3",7);
  222. &pxor ("xmm0","xmm2");
  223. &pxor ("xmm0","xmm3");
  224. &psrlq ("xmm2",1);
  225. &pxor ("xmm0","xmm2"); # s0 = sigma0_512(s0);
  226. &movdqa ("xmm1",&QWP(8*14,$W512,$Widx,8)); # s1=W512[i+14]
  227. &movdqa ("xmm4","xmm1"); # %xmm4 is sliding right
  228. &movdqa ("xmm5","xmm1"); # %xmm5 is sliding left
  229. &psrlq ("xmm4",6);
  230. &psllq ("xmm5",3);
  231. &movdqa ("xmm1","xmm4");
  232. &pxor ("xmm1","xmm5");
  233. &psrlq ("xmm4",13);
  234. &psllq ("xmm5",42);
  235. &pxor ("xmm1","xmm4");
  236. &pxor ("xmm1","xmm5");
  237. &psrlq ("xmm4",42);
  238. &pxor ("xmm1","xmm4"); # s1 = sigma1_512(s1);
  239. # + have to explictly load W512[i+9] as it's not 128-bit
  240. # v aligned and paddq would throw an exception...
  241. &movdqu ("xmm6",&QWP(8*9,$W512,$Widx,8));
  242. &paddq ("xmm0","xmm1"); # s0 += s1
  243. &paddq ("xmm0","xmm6"); # s0 += W512[i+9]
  244. &paddq ("xmm0",&QWP(0,$W512,$Widx,8)); # s0 += W512[i]
  245. &movdqa (&QWP(0,$W512,$Widx,8),"xmm0"); # W512[i] = s0
  246. &movdqa (&QWP(16*8,$W512,$Widx,8),"xmm0"); # copy of W512[i]
  247. # as the above fragment was 128-bit, we "owe" 2 rounds...
  248. &SHA2_ROUND($Kidx,$Widx); &inc($Kidx); &inc($Widx);
  249. &SHA2_ROUND($Kidx,$Widx); &inc($Kidx); &inc($Widx);
  250. &cmp ($Kidx,80);
  251. &jl (&label("_2nd_loop"));
  252. # update A-H state
  253. &mov ($Widx,&DWP(8,"ebp")); # A-H state, 1st arg
  254. &movq (&QWP($Aoff,$W512),$A); # write out a
  255. &movq (&QWP($Eoff,$W512),$E); # write out e
  256. &movdqu ("xmm0",&QWP(0,$Widx));
  257. &movdqu ("xmm1",&QWP(16,$Widx));
  258. &movdqu ("xmm2",&QWP(32,$Widx));
  259. &movdqu ("xmm3",&QWP(48,$Widx));
  260. &paddq ("xmm0",&QWP($Aoff,$W512)); # 128-bit additions...
  261. &paddq ("xmm1",&QWP($Coff,$W512));
  262. &paddq ("xmm2",&QWP($Eoff,$W512));
  263. &paddq ("xmm3",&QWP($Goff,$W512));
  264. &movdqu (&QWP(0,$Widx),"xmm0");
  265. &movdqu (&QWP(16,$Widx),"xmm1");
  266. &movdqu (&QWP(32,$Widx),"xmm2");
  267. &movdqu (&QWP(48,$Widx),"xmm3");
  268. &add ($data,16*8); # advance input data pointer
  269. &dec (&DWP(16,"ebp")); # decrement 3rd arg
  270. &jnz (&label("_chunk_loop"));
  271. # epilogue
  272. &emms (); # required for at least ELF and Win32 ABIs
  273. &mov ("edi",&DWP(-12,"ebp"));
  274. &mov ("esi",&DWP(-8,"ebp"));
  275. &mov ("ebx",&DWP(-4,"ebp"));
  276. &leave ();
  277. &ret ();
  278. &align(64);
  279. &set_label("K512"); # Yes! I keep it in the code segment!
  280. &data_word(0xd728ae22,0x428a2f98); # u64
  281. &data_word(0x23ef65cd,0x71374491); # u64
  282. &data_word(0xec4d3b2f,0xb5c0fbcf); # u64
  283. &data_word(0x8189dbbc,0xe9b5dba5); # u64
  284. &data_word(0xf348b538,0x3956c25b); # u64
  285. &data_word(0xb605d019,0x59f111f1); # u64
  286. &data_word(0xaf194f9b,0x923f82a4); # u64
  287. &data_word(0xda6d8118,0xab1c5ed5); # u64
  288. &data_word(0xa3030242,0xd807aa98); # u64
  289. &data_word(0x45706fbe,0x12835b01); # u64
  290. &data_word(0x4ee4b28c,0x243185be); # u64
  291. &data_word(0xd5ffb4e2,0x550c7dc3); # u64
  292. &data_word(0xf27b896f,0x72be5d74); # u64
  293. &data_word(0x3b1696b1,0x80deb1fe); # u64
  294. &data_word(0x25c71235,0x9bdc06a7); # u64
  295. &data_word(0xcf692694,0xc19bf174); # u64
  296. &data_word(0x9ef14ad2,0xe49b69c1); # u64
  297. &data_word(0x384f25e3,0xefbe4786); # u64
  298. &data_word(0x8b8cd5b5,0x0fc19dc6); # u64
  299. &data_word(0x77ac9c65,0x240ca1cc); # u64
  300. &data_word(0x592b0275,0x2de92c6f); # u64
  301. &data_word(0x6ea6e483,0x4a7484aa); # u64
  302. &data_word(0xbd41fbd4,0x5cb0a9dc); # u64
  303. &data_word(0x831153b5,0x76f988da); # u64
  304. &data_word(0xee66dfab,0x983e5152); # u64
  305. &data_word(0x2db43210,0xa831c66d); # u64
  306. &data_word(0x98fb213f,0xb00327c8); # u64
  307. &data_word(0xbeef0ee4,0xbf597fc7); # u64
  308. &data_word(0x3da88fc2,0xc6e00bf3); # u64
  309. &data_word(0x930aa725,0xd5a79147); # u64
  310. &data_word(0xe003826f,0x06ca6351); # u64
  311. &data_word(0x0a0e6e70,0x14292967); # u64
  312. &data_word(0x46d22ffc,0x27b70a85); # u64
  313. &data_word(0x5c26c926,0x2e1b2138); # u64
  314. &data_word(0x5ac42aed,0x4d2c6dfc); # u64
  315. &data_word(0x9d95b3df,0x53380d13); # u64
  316. &data_word(0x8baf63de,0x650a7354); # u64
  317. &data_word(0x3c77b2a8,0x766a0abb); # u64
  318. &data_word(0x47edaee6,0x81c2c92e); # u64
  319. &data_word(0x1482353b,0x92722c85); # u64
  320. &data_word(0x4cf10364,0xa2bfe8a1); # u64
  321. &data_word(0xbc423001,0xa81a664b); # u64
  322. &data_word(0xd0f89791,0xc24b8b70); # u64
  323. &data_word(0x0654be30,0xc76c51a3); # u64
  324. &data_word(0xd6ef5218,0xd192e819); # u64
  325. &data_word(0x5565a910,0xd6990624); # u64
  326. &data_word(0x5771202a,0xf40e3585); # u64
  327. &data_word(0x32bbd1b8,0x106aa070); # u64
  328. &data_word(0xb8d2d0c8,0x19a4c116); # u64
  329. &data_word(0x5141ab53,0x1e376c08); # u64
  330. &data_word(0xdf8eeb99,0x2748774c); # u64
  331. &data_word(0xe19b48a8,0x34b0bcb5); # u64
  332. &data_word(0xc5c95a63,0x391c0cb3); # u64
  333. &data_word(0xe3418acb,0x4ed8aa4a); # u64
  334. &data_word(0x7763e373,0x5b9cca4f); # u64
  335. &data_word(0xd6b2b8a3,0x682e6ff3); # u64
  336. &data_word(0x5defb2fc,0x748f82ee); # u64
  337. &data_word(0x43172f60,0x78a5636f); # u64
  338. &data_word(0xa1f0ab72,0x84c87814); # u64
  339. &data_word(0x1a6439ec,0x8cc70208); # u64
  340. &data_word(0x23631e28,0x90befffa); # u64
  341. &data_word(0xde82bde9,0xa4506ceb); # u64
  342. &data_word(0xb2c67915,0xbef9a3f7); # u64
  343. &data_word(0xe372532b,0xc67178f2); # u64
  344. &data_word(0xea26619c,0xca273ece); # u64
  345. &data_word(0x21c0c207,0xd186b8c7); # u64
  346. &data_word(0xcde0eb1e,0xeada7dd6); # u64
  347. &data_word(0xee6ed178,0xf57d4f7f); # u64
  348. &data_word(0x72176fba,0x06f067aa); # u64
  349. &data_word(0xa2c898a6,0x0a637dc5); # u64
  350. &data_word(0xbef90dae,0x113f9804); # u64
  351. &data_word(0x131c471b,0x1b710b35); # u64
  352. &data_word(0x23047d84,0x28db77f5); # u64
  353. &data_word(0x40c72493,0x32caab7b); # u64
  354. &data_word(0x15c9bebc,0x3c9ebe0a); # u64
  355. &data_word(0x9c100d4c,0x431d67c4); # u64
  356. &data_word(0xcb3e42b6,0x4cc5d4be); # u64
  357. &data_word(0xfc657e2a,0x597f299c); # u64
  358. &data_word(0x3ad6faec,0x5fcb6fab); # u64
  359. &data_word(0x4a475817,0x6c44198c); # u64
  360. &function_end_B($func);
  361. &asm_finish();