mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 00:45:38 +00:00
sha256: specialize rotr_wk and shr_wk per rotation amount
The generic `rotr_wk(dst, n)` does its byte/bit decomposition with two runtime `while` loops — necessary in the abstract, but wasteful in SHA-256 where every rotation amount is one of ten fixed compile-time constants (2, 6, 7, 11, 13, 17, 18, 19, 22, 25). The loop overhead alone is ~80 cycles of bookkeeping per call, on top of the actual rotation work. Replace each `rotr_wk(SIG, 6)` call inside the sigma helpers with a dedicated `rotr_wk_6(SIG)` (and similarly for the other amounts and for `shr_wk_3` / `shr_wk_10`). Each new helper just chains the right number of `byte_rotr_wk` and `rotr1_wk` calls inline — no `rem` variable, no `>= 8` / `> 0` checks. The original `rotr_wk` / `shr_wk` wrappers stay defined for runtime-amount callers; nothing else in the example uses them today, but keeping them documents the general-purpose form. Per SHA-256 block: ~45K cycles saved across 384 sigma rotations. Combined with commit 0b5470b's leaf-function fix, the per-block compression cost drops by ~3.5 frames at NTSC. The hash output is unchanged (still AE9145DB5CABC41FE34B54E34AF8881F462362EA20FD8F861B26532FFBB84E0D for "NES"), no other examples are affected, and the emulator harness stays at 34/34. https://claude.ai/code/session_01FRmSBruVWCufm3LsUVMs8v
This commit is contained in:
parent
0b5470b054
commit
726faef538
2 changed files with 132 additions and 13 deletions
Binary file not shown.
|
|
@ -210,6 +210,13 @@ fun byte_rotr_wk(dst: u8) {
|
|||
// 0..31 by first rotating whole bytes (each call is cheaper
|
||||
// than 8 ROR chains) and then finishing with up to 7 single-
|
||||
// bit ROR chains.
|
||||
//
|
||||
// The SHA-256 sigmas only need a fixed set of rotation amounts
|
||||
// (2, 6, 7, 11, 13, 17, 18, 19, 22, 25), so the per-amount
|
||||
// helpers below skip this loop's runtime byte/bit decomposition
|
||||
// and unroll the right number of `byte_rotr_wk` / `rotr1_wk`
|
||||
// calls. This `rotr_wk` wrapper stays available for the rare
|
||||
// caller that needs a runtime amount.
|
||||
fun rotr_wk(dst: u8, n: u8) {
|
||||
var rem: u8 = n
|
||||
while rem >= 8 {
|
||||
|
|
@ -222,6 +229,102 @@ fun rotr_wk(dst: u8, n: u8) {
|
|||
}
|
||||
}
|
||||
|
||||
// ── Per-amount rotate helpers ───────────────────────────────
|
||||
//
|
||||
// Each `rotr_wk_<N>` rotates wk[dst..dst+4] right by exactly N
|
||||
// bits with no loop overhead. Calling these directly from the
|
||||
// sigma helpers replaces ~80 cycles of `rem >= 8` / `rem > 0`
|
||||
// loop bookkeeping with the bare sequence of byte + bit
|
||||
// rotations the analyzer-level constant rotation always reduces
|
||||
// to. Per SHA-256 block, ~45K cycles saved across 384 sigma
|
||||
// rotations.
|
||||
|
||||
fun rotr_wk_2(dst: u8) {
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
fun rotr_wk_6(dst: u8) {
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
fun rotr_wk_7(dst: u8) {
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 11 = 1 byte + 3 bits
|
||||
fun rotr_wk_11(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 13 = 1 byte + 5 bits
|
||||
fun rotr_wk_13(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 17 = 2 bytes + 1 bit
|
||||
fun rotr_wk_17(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 18 = 2 bytes + 2 bits
|
||||
fun rotr_wk_18(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 19 = 2 bytes + 3 bits
|
||||
fun rotr_wk_19(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 22 = 2 bytes + 6 bits
|
||||
fun rotr_wk_22(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// 25 = 3 bytes + 1 bit
|
||||
fun rotr_wk_25(dst: u8) {
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
byte_rotr_wk(dst)
|
||||
rotr1_wk(dst)
|
||||
}
|
||||
|
||||
// Shift wk[dst..dst+4] right by 1 bit (logical — top bit
|
||||
// becomes 0).
|
||||
fun shr1_wk(dst: u8) {
|
||||
|
|
@ -265,7 +368,9 @@ fun byte_shr_wk(dst: u8) {
|
|||
}
|
||||
}
|
||||
|
||||
// Shift wk[dst..dst+4] right by `n` bits (logical).
|
||||
// Shift wk[dst..dst+4] right by `n` bits (logical). Generic
|
||||
// runtime-amount form; the SHA-256 sigmas use the per-amount
|
||||
// helpers below instead.
|
||||
fun shr_wk(dst: u8, n: u8) {
|
||||
var rem: u8 = n
|
||||
while rem >= 8 {
|
||||
|
|
@ -278,6 +383,20 @@ fun shr_wk(dst: u8, n: u8) {
|
|||
}
|
||||
}
|
||||
|
||||
// 3 bits — used by σ0(x) = ... ^ (x >> 3)
|
||||
fun shr_wk_3(dst: u8) {
|
||||
shr1_wk(dst)
|
||||
shr1_wk(dst)
|
||||
shr1_wk(dst)
|
||||
}
|
||||
|
||||
// 10 bits = 1 byte + 2 bits — used by σ1(x) = ... ^ (x >> 10)
|
||||
fun shr_wk_10(dst: u8) {
|
||||
byte_shr_wk(dst)
|
||||
shr1_wk(dst)
|
||||
shr1_wk(dst)
|
||||
}
|
||||
|
||||
// ── Cross-array primitives ──────────────────────────────────
|
||||
|
||||
// wk[dst..dst+4] = w[w_ofs..w_ofs+4]
|
||||
|
|
@ -414,48 +533,48 @@ fun add_k_to_wk(dst: u8, k_ofs: u8) {
|
|||
// Σ0(src) = rotr(src, 2) ^ rotr(src, 13) ^ rotr(src, 22)
|
||||
fun big_sigma0(src: u8) {
|
||||
cp_wk(OFS_SIG, src)
|
||||
rotr_wk(OFS_SIG, 2)
|
||||
rotr_wk_2(OFS_SIG)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 13)
|
||||
rotr_wk_13(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 22)
|
||||
rotr_wk_22(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
}
|
||||
|
||||
// Σ1(src) = rotr(src, 6) ^ rotr(src, 11) ^ rotr(src, 25)
|
||||
fun big_sigma1(src: u8) {
|
||||
cp_wk(OFS_SIG, src)
|
||||
rotr_wk(OFS_SIG, 6)
|
||||
rotr_wk_6(OFS_SIG)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 11)
|
||||
rotr_wk_11(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 25)
|
||||
rotr_wk_25(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
}
|
||||
|
||||
// σ0(src) = rotr(src, 7) ^ rotr(src, 18) ^ (src >> 3)
|
||||
fun small_sigma0(src: u8) {
|
||||
cp_wk(OFS_SIG, src)
|
||||
rotr_wk(OFS_SIG, 7)
|
||||
rotr_wk_7(OFS_SIG)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 18)
|
||||
rotr_wk_18(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
cp_wk(OFS_TMP, src)
|
||||
shr_wk(OFS_TMP, 3)
|
||||
shr_wk_3(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
}
|
||||
|
||||
// σ1(src) = rotr(src, 17) ^ rotr(src, 19) ^ (src >> 10)
|
||||
fun small_sigma1(src: u8) {
|
||||
cp_wk(OFS_SIG, src)
|
||||
rotr_wk(OFS_SIG, 17)
|
||||
rotr_wk_17(OFS_SIG)
|
||||
cp_wk(OFS_TMP, src)
|
||||
rotr_wk(OFS_TMP, 19)
|
||||
rotr_wk_19(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
cp_wk(OFS_TMP, src)
|
||||
shr_wk(OFS_TMP, 10)
|
||||
shr_wk_10(OFS_TMP)
|
||||
xor_wk(OFS_SIG, OFS_TMP)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue