phase11: merge 59 — worker F's 0x800261C0 -> 599 bodies / 608 regions, ONE to the milestone
This commit is contained in:
+998
-1000
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user