aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir/simpl.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-22 09:00:41 +0100
committerlemon <lsof@mailbox.org>2025-12-22 09:00:41 +0100
commit500b3e1904d95129b2af4ce9262e8c0265a49202 (patch)
tree05171a36a7dd2f7fb76917368958f1dcb5df85a9 /ir/simpl.c
parentc3ba1e7c9c3cd18c8b7ad176cf19891724a85693 (diff)
simpl: handle multiplication by negative po2 too
Diffstat (limited to 'ir/simpl.c')
-rw-r--r--ir/simpl.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/ir/simpl.c b/ir/simpl.c
index 8aec043..740a5a7 100644
--- a/ir/simpl.c
+++ b/ir/simpl.c
@@ -5,7 +5,9 @@ mulk(struct instr *ins, struct block *blk, int *curi)
{
vlong iv = intconval(ins->r);
enum irclass cls = ins->cls;
- assert(iv > 1 && "trivial mul not handled by irbinop() ?");
+ assert((uvlong)iv > 1 && "trivial mul not handled by irbinop() ?");
+ bool neg = iv < 0;
+ if (neg) iv = -iv;
/* This can be generalized to any sequence of shifts and
* adds/subtracts, but whether that's worth it depends on the number of them
* and the microarchitecture.. clang seems to stop after two shifts. Should
@@ -15,21 +17,23 @@ mulk(struct instr *ins, struct block *blk, int *curi)
/* x * 2^y ==> x << y */
ins->op = Oshl;
ins->r = mkref(RICON, ilog2(iv));
- return 1;
} else if (ispo2(iv-1)) {
/* x * 5 ==> (x << 2) + x */
ins->op = Oadd;
ins->r = ins->l;
ins->l = insertinstr(blk, (*curi)++, mkinstr(Oshl, cls, ins->l, mkref(RICON, ilog2(iv-1))));
- return 1;
} else if (ispo2(iv+1)) {
/* x * 7 ==> (x << 3) - x */
ins->op = Osub;
ins->r = ins->l;
ins->l = insertinstr(blk, (*curi)++, mkinstr(Oshl, cls, ins->l, mkref(RICON, ilog2(iv+1))));
- return 1;
+ } else return 0;
+ if (neg) {
+ ins->l = insertinstr(blk, (*curi)++, *ins);
+ ins->op = Oneg;
+ ins->r = NOREF;
}
- return 0;
+ return 1;
}
static int