Divide the offset by the stride
When the index is a compile-time constant, indexing an array costs nothing: the compiler multiplies index by element size at compile time and bakes the result into the load or store's offset field. v[4] on an s32 array is just 16(a0) — no shift, no add, no extra instruction. Here's sum_pair:
s32 sum_pair(s32 *v) {
return v[1] + v[4];
}
lw t6, 16(a0) # offset 16 / stride 4 = v[4]
lw t7, 4(a0) # offset 4 / stride 4 = v[1]
addu v0, t6, t7
jr ra
nop
The decoding move — one you'll make thousands of times — is offset ÷ element size = index. Stride 4 here because s32; a u8 array would put the index in the offset raw, a s16 array halved. Notice also that IDO loaded v[4] before v[1]: load order follows the compiler's scheduling mood, not your source order, and the addu's operands follow the loads. Don't fight it; the same C produces the same shuffle.
One more habit to build now: a lone pointer parameter with several different offsets hanging off it usually means array — but file away that a struct will look exactly the same. Telling those apart comes two chapters from now; on this page, everything is an array.
The target moves a value from one slot of a word array to another — a load and a store, each with an offset for you to decode.
Your task
Write func_803b2f5c to reproduce the target assembly.