aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir
diff options
context:
space:
mode:
Diffstat (limited to 'ir')
-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