> -----Original Message-----
> From: Niels Möller [mailto:[email protected]]
> Sent: terça-feira, 14 de março de 2017 17:54
> To: Gustavo Serra Scalet <[email protected]>
> Cc: [email protected]
> Subject: Re: Up to 7x faster sha256 for ppc64le: Please review
>
> I'm not familiar with ppc assembly, but some comments.
>
> Are you using some special sha instructions (e.g., vshasigmaw), or only
> general simd instructions? Are they always available, or do we need some
> compile time and/or run time check?
The machine needs to be at least a POWER8 machine. As all previous PowerPC
systems were big endian only, the endianness would be enough, but I guess a
compile time check that would be more specific is __POWER8_VECTOR__ == 1
(available on gcc >= 5 and clang >= 3.7). Should I add that with a compile-flag
like --x86-aesni ?
>
> In machine.m4, the aliases like
>
> define(<r15>, <15>)
>
> doesn't seem very helpful. If the assembly convention is that plain
> numbers are used to identify registers, we can stick to that for non-
> symbolic references, and then define more meaningful symbolic names on
> top of that.
The problem is that it's not very readable as you can't tell registers and
constants apart. E.g:
$ grep lvx -m 1 sha256-compress.s
lvx 9, 0, 3
$ objdump -d sha256-compress.o | grep lvx -m 1
50: ce 18 20 7d lvx v9,0,r3
The disassembler does differs the 3 from r3 for readability (but not the 0,
which is a constant) even if the plain assembly is not indicating that. And I
think that's a good thing.
And don't think like "lvx always has a constant as the second argument, you
just need to know it" because it's only if it's zero:
$ grep lvx sha256-compress.s | grep -m 1 1,
lvx 29, 1, 0
$ objdump -d sha256-compress.o | grep lvx | grep -m 1 r1
11b8: ce 00 a1 7f lvx v29,r1,r0
So it can be confusing... and that happens for a bunch of instructions,
therefore I'd like to leave it as it's even if the macros seem that dumb. Is
that ok?
> Also, I think it's good practice to use upper case for all
> m4 defines. E.g.,
>
> define(<STATE>, 3)
Ok, I can manage to do that.
> SAVE_NVOLATILE and RESTORE_NVOLATILE look a bit overkill for a single
> assembly function, but I guess they make sense if you plan more ppc
> assembly.
Sha512 will need different set of non-volatile registers so it'll be handy to
have that macro.
> For LOAD_H_VEC, what alignment would you need to not use load unaligned
> instructions? We could consider forcing larger alignment for struct
> sha256_ctx. Does it matter for performance?
16-bytes alignment. I didn't notice a significant change in performance but it
made the development a little bit trickier...
The current treat-any-alignment-type version is:
lvx $1, 0, state C load unaligned
addi t0, state,16
lvsr t1, 0, t0
lvx $5, 0, t0 C load unaligned
vperm $1, $5, $1, t1 C a = {a,b,c,d}
addi t0, t0, 16
lvx aux, 0, t0 C load unaligned
vperm $5, aux, $5, t1 C e = {e,f,g,h}
and if it were 16-bytes aligned, it would simply be:
lvx $1, 0, state C a = {a,b,c,d}
addi t0, state,16
lvx $5, 0, t0 C e = {e,f,g,h}
and we did it on all places (input, state and k) where vectors were being
read/written from/to memory.
> UPDATE_SHA_STATE looks surprisingly complicated. I guess it's alignment
> issues and that representation in registers is some permutation of the
> words as they appear in memory?
Mainly it's due to alignment. Also our vector implementation also spread one
element at a vector on compression algorithm:
+-------+----+----+----+----+
| | Vector Words: |
| Name | #1 | #2 | #3 | #4 |
+-------+----+----+----+----+
| Va | a | b | c | d |
+-------+----+----+----+----+
But not when memory is read/written:
+-------+----+----+----+----+
| | Vector Words: |
| Name | #1 | #2 | #3 | #4 |
+-------+----+----+----+----+
| Va | a | - | - | - |
| Vb | b | - | - | - |
| Vc | c | - | - | - |
| Vd | d | - | - | - |
+-------+----+----+----+----+
So there is some merging/unpacking happening after LOAD_H_VEC and on
UPDATE_SHA_STATE (I should probably document this. Thanks for pointing it out)
> Comments on the first uses of DEQUE are a bit confusing,
>
> C Load a-h registers from the memory pointed by state
> DEQUE(a, b, c, d)
> DEQUE(e, f, g, h)
>
> It's not any load from memory, right, but rather some permutation of the
> data?
Yes, I'll change DEQUE to UNPACK. I think it'll make more sense.
> You unroll the compression function completely, 880 instructions just
> for the expansion of the ROUND macros. Are op-codes 32 bits, so that
> this is 3.5 KB code size (+ non-ROUND instructions)?
Every ppc64le instruction used is 4-bytes long.
> This isn't terribly
> large, but unless you win significant performance from complete
> unrolling, I'd recommend unrolling only 8 or 16 rounds; that is likely
> enough to make loop overhead very small, and you use less of the
> instruction cache. (For comparison, the x86_64 versions also ends up at
> 3.5 KB, with 16 time unrolling).
I rolled from 16th to 64th round and I noticed no significant performance drop
despite having more branches and branch misses. The instruction count of this
new algorithm I verified by "objdump -d sha256-compress.o | wc -l" and it
decreased from 1161 to 477.
I have nothing against this change. I'll send it along the other changes
> And please add proper copyright headers. Are you the only author of this
> code?
My development group is involved on this task. I'll verify what to add as the
copyright holder.
Thanks for the quick reply.
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs