Skip to content

Instantly share code, notes, and snippets.

@pervognsen pervognsen/gen_mul.c

Last active Apr 18, 2020
Embed
What would you like to do?
void gen_mul(Value *dest, Value *src) {
if (isconst(dest)) {
gen_swap(dest, src); // this doesn't generate instructions and just swaps descriptors ("value renaming")
}
val_to_reg(dest); // the post-condition is that dest is allocated to a register
if (isconst(src) && isimm32(src->ival)) {
if (src->ival == 0) {
int_to_val(dest, 0);
} else if (src->ival == 1) {
// do nothing
} else if (src->ival == 2) {
add_reg_reg(dest->reg, dest->reg);
// The x64 flag state is treated like a special register which conditional values may be temporarily allocated to.
// We don't have to "spill" the flag state because if there's a currently live value associated with it,
// we can always rematerialize the flag state from that value's general-purpose register with CMP if we need it
// in a conditional context. however, tracking the set_flags means that we get rid of redundant CMPs. this is an
// area where most one-pass compilers do a bad job. the per-instruction flags affected are defined by the assembler,
// e.g. add_flags = OF | SF | ZF | AF | PF. it's safe/conservative to use flags = 0, worst case you get an extra CMP.
set_flags(dest, add_flags);
} else if (ispow2(src->ival)) {
shl_reg_imm(dest->reg, log2(src->ival));
set_flags(dest, shl_flags);
} else {
imul_reg_imm(dest->reg, src->ival); // this picks imm8 vs imm32 on its own
set_flags(dest, imul_flags);
}
// you could also add a case for strength reducing 3, 5, 9 to LEA
} else {
// the 64-bit immediate path hits this too
val_to_reg(src);
imul_reg_reg(dest->reg, src->reg);
set_flags(dest, imul_flags);
}
// we could have added cases for imul_reg_mem for FRAME_REL/RIP_REL but the backend wants to register allocate greedily
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.