Skip to content

Instantly share code, notes, and snippets.

@pervognsen pervognsen/gen_mul.c

Last active Apr 18, 2020
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
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.