Last active
February 17, 2024 22:47
-
-
Save pervognsen/77570f77d3748a854e2bb7c3f0ca3591 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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