diff options
| author | 2025-12-22 09:00:41 +0100 | |
|---|---|---|
| committer | 2025-12-22 09:00:41 +0100 | |
| commit | 500b3e1904d95129b2af4ce9262e8c0265a49202 (patch) | |
| tree | 05171a36a7dd2f7fb76917368958f1dcb5df85a9 | |
| parent | c3ba1e7c9c3cd18c8b7ad176cf19891724a85693 (diff) | |
simpl: handle multiplication by negative po2 too
| -rw-r--r-- | ir/simpl.c | 14 |
1 files changed, 9 insertions, 5 deletions
@@ -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 |