Steinar H. Gunderson: Decompilation patterns, part 12: __builtin_memcpy
Say you see this lovely chunk of decompiled code:
var_v1 = &sp10
var_v0 = D_80010040;
temp_s4 = var_v1;
sp110 = &sp2C
sp114 = &sp30
do {
var_v1->unk0 = (s32) var_v0->unk0;
var_v1->unk4 = (s32) var_v0[1];
var_v1->unk8 = (s32) var_v0[2];
var_v1->unkC = (s32) var_v0[3];
var_v0 += 0x10;
var_v1 += 0x10;
} while (var_v0 != &D_8001040[0x3C]);
var_v1->unk0 = (s32) var_v0->unk0;
var_v1->unk4 = (s32) var_v0[1];
var_v1->unk8 = (s32) var_v0[2];
If you ignore the fact that m2c wrote ->unk0 for [0] (it has a bit of an
annoying habit to do that), this is obviously something copying 16 bytes
at a time and then 12 more bytes at the end. But would a programmer ever do this?
Nope, this is an inlined, unrolled memcpy.
This is known in GCC as __builtin_memcpy, and it can happen either implicitly,
or by some sort of lowering from a struct or array copy (e.g., through initialization
of a stack array). Depending a bit on whether the variable is known to be aligned
or not, you'll either get just lw or some evil lwr/lwl sequence; I'm always
struggling a bit to change one to the other. In any case, what you want here is:
__builtin_memcpy(&sp10, D_80010040, 0x4C);
and then make sp10 the right type instead of a scalar, ideally so that you can
use sizeof() on it. Or, in some cases, a direct initialization:
s32 foo[] = { 1, 2, 3, ...more data from D_80010040... };