# KMC/GCC decompilation patterns
(This document is publicly editable, please contribute.)
As a reference, here's the IDO version of this document: https://hackmd.io/vPmcgdaFSlq4R2mfkq4bJg
PMRet GCC tips and tricks document: https://github.com/pmret/papermario/wiki/GCC-2.8.1-Tips-and-Tricks
```c
// temp_v1 = arg5 - 1;
// temp_t1 = temp_v1 & (~temp_v1 >> 0x1F);
temp_t1 = MAX(arg5 - 1, 0);
```
* Two adjacent 16-bit loads can be coalesced into a single `lw` when being compared at the same time instead of generating two `lh` instructions. This can only happen if the two are next to each other in memory and the first one is guaranteed to be 4 byte aligned. For example,
```c
struct Test {
s16 a;
s16 b;
s32 for_alignment;
};
int foo(struct Test* t) {
if (t->a || t->b) {
bar();
}
}
```
```
foo:
addiu $sp, $sp, -0x18
sw $ra, 0x10($sp)
lw $v0, 0x0($a0) # This is the coalesced loads for `a` and `b`
beqz $v0, 1f
nop
jal bar
nop
1:
lw $ra, 0x10($sp)
addiu $sp, $sp, 0x18
jr $ra
nop
```
The compiler can make similar optimizations for combining multiple 8-bit comparisons as well. In the case that the members don't total 4-bytes, it can still coalesce the loads but will mask their combined value when doing the comparison. Non-adjacent members loads can be coalesced as well as long as they're within a 4-byte boundary, and the members between that were skipped will be masked out of the comparison via a combination of `lui`, `ori`, and `and`.
```c
struct Test {
s8 a;
s8 b;
s8 c;
s8 d;
s32 for_alignment;
};
int foo(struct Test* t) {
if (t->a || t->b || t->d) {
bar();
}
}
```
```
foo:
addiu $sp, $sp, -0x18
sw $ra, 0x10($sp)
lw $v0, 0x0($a0)
lui $v1, 0xffff
ori $v1, $v1, 0xff
and $v0, $v0, $v1
beqz $v0, 1f
nop
jal bar
nop
1:
lw $ra, 0x10($sp)
jr $ra
addiu $sp, $sp, 0x18
```
In -O0, `for(;;)` generates different code than `while(1)`.
## Signed division by 2
There are three different patterns involving a signed variable divided by 2. The variant depends from the size of the type.
```c
s32 temp_v0;
// temp_v0 = ((s32)(temp_v0 + ((u32)temp_v0 >> 0x1F)) >> 1)
temp_v0 /= 2;
```
```c
s16 temp_v0;
// temp_v0 = ((s32)(temp_v0 + (((u32)(temp_v0 << 0x10)) >> 0x1F))) >> 1
temp_v0 /= 2;
```
```c
s8 temp_v0;
// temp_v0 = ((s32)(temp_v0 + (((u32)(temp_v0 << 0x18)) >> 0x1F))) >> 1
temp_v0 /= 2;
```