phase11: merge 59 — worker F's 0x800261C0 -> 599 bodies / 608 regions, ONE to the milestone

This commit is contained in:
Christopher Williams
2026-09-24 11:33:44 -04:00
parent 773cb88dcf
commit efbcc2bd01
3 changed files with 1068 additions and 1000 deletions
+998 -1000
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -89,6 +89,7 @@
0x80025A2C 0x80025ADC src/func_80025A2C.c
0x80025ADC 0x80025B64 src/func_80025ADC.c
0x80026180 0x800261C0 src/func_80026180.c
0x800261C0 0x8002622C src/func_800261C0.c
0x80026258 0x80026264 src/func_80026258.c
0x80026264 0x80026274 src/func_80026264.c
0x80026274 0x800262E0 src/func_80026274.c
1 # Code-region registry: one C region per matched function.
89 0x80025A2C
90 0x80025ADC
91 0x80026180
92 0x800261C0
93 0x80026258
94 0x80026264
95 0x80026274
+69
View File
@@ -0,0 +1,69 @@
/*
* func_800261C0 — 108 bytes at 0x800261C0..0x8002622C
*
* Leaf routine that clears three flag bits of a caller-owned word and, unless
* `mode` is 4, writes back the word with bit 30 set and `mode & 3` placed in
* bits 28-29. Returns 22 for a null pointer and 0 otherwise.
*
* The observed instructions are:
* move a2,a0 x = p (parameter copy)
* bnez a2,0x800261d4 if (x == 0) {
* move a3,a1 mode copy, delay slot
* j 0x80026224 return 22; (shared `jr ra`)
* li v0,22 (delay slot)
* BODY:
* lui/ori a1,0xBFFFFFFF a0,0xEFFFFFFF v1,0xDFFFFFFF three mask constants
* lw v0,0(a2) v = *x; (ONE load)
* and v0,v0,a1 / a0 / v1 three ANDs
* li v0,4
* beq a3,v0,0x80026220 if (mode == 4) return 0;
* sw a0,0(a2) (delay slot) the masked word
* lui v1,0x4000 / or v1,a0,v1 v1 = v | 0x40000000;
* andi v0,a3,3 / sll v0,v0,0x1c \
* or v1,v1,v0 / v1 |= (mode & 3) << 28;
* sw v1,0(a2) *x = v1;
* move v0,zero / jr ra / nop return 0;
*
* THE SOURCE IS A READ-MODIFY-WRITE CHAIN, NOT A LOCAL (cookbook 81 instance).
* `*p = *p & M1; *p = *p & M2; *p = *p & M3;` compiles to ONE `lw`, three `and`s
* and ONE `sw`: cse forwards each statement's load from the previous store and
* deletes the intermediate stores, because all three statements are in the same
* basic block. Writing the same value as the single expression
* `*p & M1 & M2 & M3` FOLDS into one `and` with the combined mask (probe: f1 one
* `and`, f2 three `and`s) — so the three statements are mandatory. The chain's
* surviving store is the one that lands in the `beq` delay slot.
*
* The tail is TWO statements for the same reason: `*p | C1 | X` in one
* expression is reassociated by `fold` into `v | (C1 | X)` (17-byte residual),
* while `*p = *p | 0x40000000; *p = *p | ((mode & 3) << 28);` keeps the original
* `(v | C1) | X` order AND keeps the first store alive, because its load is
* forwarded from the store in the PREVIOUS basic block (cse's dead-store
* elimination is per block).
*
* `move a2,a0` / `move a3,a1` (cookbook 170 mechanism, constant-clobber variant):
* both parameters must be copied because the three mask constants are
* materialised into `a0` and `a1` — the parameters' own homes. Tests that
* discriminate: a local `v = *p; v = v & ...` spelling loses the delay-slot
* store (100 B / LENGTH-MISMATCH), and `volatile` keeps both stores but flips
* the entry branch to `beq` (100 B).
*
* LIMITS: name, parameter signedness, the exact bit meanings and the return
* codes are hypotheses read from the instructions; the masks are written as
* `~0x40000000` etc. because that form rounds-trips to the same bytes. Only
* the compiled bytes are evidence.
*/
int func_800261C0(int *p, int mode) {
if (p == 0) {
return 22;
}
*p = *p & ~0x40000000;
*p = *p & ~0x10000000;
*p = *p & ~0x20000000;
if (mode == 4) {
return 0;
}
*p = *p | 0x40000000;
*p = *p | ((mode & 3) << 28);
return 0;
}