aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <[email protected]>2024-06-18 17:00:30 +0200
committerQuentin Carbonneaux <[email protected]>2024-06-18 17:06:56 +0200
commit6dab93b4b236a884d56c907d741148baa15dbbc5 (patch)
tree2a2da6810a4a0e15b89e2b9c6f67a52f86b35a1e
parent96f18be71d34b63ceca3e4fa5480eb9ca9afcf4e (diff)
cheaper mul by small constants on amd64
-rw-r--r--amd64/emit.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 00dd80f..bbc7def 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -360,6 +360,54 @@ Next:
goto Next;
}
+static int
+mulops(int depth, int *ops, int64_t k)
+{
+ static int tab[] = {9, 8, 5, 4, 3, 2, 1, 0};
+ int *pm, m;
+
+ while (depth && k>1) {
+ for (pm=tab; (m=*pm); pm++)
+ if (k % m == 0) {
+ *ops++ = m;
+ depth -= 1;
+ k /= m;
+ goto next;
+ }
+ return 0;
+ next:;
+ }
+ *ops = 1;
+ return k == 1;
+}
+
+static int
+emitmulk(Ref to, Ref r, int64_t k, Ins *i, Fn *fn, FILE *f)
+{
+ int ops[3], *pm, m;
+ char fmt[32];
+
+ if (k == 1 || !mulops(2, ops, k))
+ return 0;
+
+ for (pm=ops; (m=*pm) != 1; pm++) {
+ if (m == 4 || m == 2) {
+ if (!req(r, to))
+ emitf("mov%k %1, %=", i, fn, f);
+ emitf("add%k %=, %=", i, fn, f);
+ if (m == 4)
+ emitf("add%k %=, %=", i, fn, f);
+ } else {
+ sprintf(fmt, "lea%%k (%s, %%1, %d), %%=",
+ (m & 1) ? "%1" : "", m & ~1);
+ emitf(fmt, i, fn, f);
+ }
+ r = to;
+ i->arg[1] = to;
+ }
+ return 1;
+}
+
static void *negmask[4] = {
[Ks] = (uint32_t[4]){ 0x80000000 },
[Kd] = (uint64_t[2]){ 0x8000000000000000 },
@@ -407,6 +455,14 @@ emitins(Ins i, Fn *fn, FILE *f)
i.arg[0] = i.arg[1];
i.arg[1] = r;
}
+ if (KBASE(i.cls) == 0)
+ if (rtype(i.arg[0]) == RCon) {
+ con = &fn->con[i.arg[0].val];
+ val = con->bits.i;
+ if (con->type == CBits)
+ if (emitmulk(i.to, i.arg[1], val, &i, fn, f))
+ break;
+ }
if (KBASE(i.cls) == 0 /* only available for ints */
&& rtype(i.arg[0]) == RCon
&& rtype(i.arg[1]) == RTmp) {