diff options
| author | Edmund Grimley Evans <Edmund.Grimley.Evans@gmail.com> | 2015-03-07 17:03:51 +0000 |
|---|---|---|
| committer | Edmund Grimley Evans <Edmund.Grimley.Evans@gmail.com> | 2015-03-07 17:42:08 +0000 |
| commit | d854dede033f451452ebc3e1d6b8a33a2e9724fb (patch) | |
| tree | 38bed021c244215108722e09634b3492f3223b1e /arm64-gen.c | |
| parent | ac70e6b84040dc24a065013cdf30ff44d98cc670 (diff) | |
| download | tinycc-d854dede033f451452ebc3e1d6b8a33a2e9724fb.tar.gz tinycc-d854dede033f451452ebc3e1d6b8a33a2e9724fb.tar.bz2 | |
arm64: Optimise some integer operations with a constant operand.
Diffstat (limited to 'arm64-gen.c')
| -rw-r--r-- | arm64-gen.c | 126 |
1 files changed, 124 insertions, 2 deletions
diff --git a/arm64-gen.c b/arm64-gen.c index fe1961d..fe1a634 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -1331,9 +1331,131 @@ ST_FUNC int gtst(int inv, int t) return gjmp(t); } -static void arm64_gen_opil(int op, int l) +static int arm64_iconst(uint64_t *val, SValue *sv) { - int x, a, b; + if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + return 0; + if (val) { + int t = sv->type.t & (VT_BTYPE | VT_UNSIGNED); + // It's crazy how TCC has all these alternatives for storing a value: + if (t == (VT_LLONG | VT_UNSIGNED)) + *val = sv->c.ull; + else if (t == VT_LLONG) + *val = sv->c.ll; + else if (t & VT_UNSIGNED) + *val = sv->c.ui; + else + *val = sv->c.i; + } + return 1; +} + +static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val, + uint32_t x, uint32_t a) +{ + if (op == '-' && !rev) { + val = -val; + op = '+'; + } + val = l ? val : (uint32_t)val; + + switch (op) { + + case '+': { + int s = l ? val >> 63 : val >> 31; + val = s ? -val : val; + val = l ? val : (uint32_t)val; + if (!(val & ~(uint64_t)0xfff)) + o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10); + else if (!(val & ~(uint64_t)0xfff000)) + o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10); + else { + arm64_movimm(30, val); // use x30 + o(0x0b1e0000 | l << 31 | s << 30 | x | a << 5); + } + return 1; + } + + case '-': + if (!val) + o(0x4b0003e0 | l << 31 | x | a << 16); // neg + else if (val == (l ? (uint64_t)-1 : (uint32_t)-1)) + o(0x2a2003e0 | l << 31 | x | a << 16); // mvn + else { + arm64_movimm(30, val); // use x30 + o(0x4b0003c0 | l << 31 | x | a << 16); // sub + } + return 1; + + case '^': + if (val == -1 || (val == 0xffffffff && !l)) { + o(0x2a2003e0 | l << 31 | x | a << 16); // mvn + return 1; + } + // fall through + case '&': + case '|': { + int e = arm64_encode_bimm64(l ? val : val | val << 32); + if (e < 0) + return 0; + o((op == '&' ? 0x12000000 : + op == '|' ? 0x32000000 : 0x52000000) | + l << 31 | x | a << 5 | (uint32_t)e << 10); + return 1; + } + + case TOK_SAR: + case TOK_SHL: + case TOK_SHR: { + uint32_t n = 32 << l; + val = val & (n - 1); + if (rev) + return 0; + if (!val) + assert(0); + else if (op == TOK_SHL) + o(0x53000000 | l << 31 | l << 22 | x | a << 5 | + (n - val) << 16 | (n - 1 - val) << 10); // lsl + else + o(0x13000000 | (op == TOK_SHR) << 30 | l << 31 | l << 22 | + x | a << 5 | val << 16 | (n - 1) << 10); // lsr/asr + return 1; + } + + } + return 0; +} + +static void arm64_gen_opil(int op, uint32_t l) +{ + uint32_t x, a, b; + + // Special treatment for operations with a constant operand: + { + uint64_t val; + int rev = 1; + + if (arm64_iconst(0, &vtop[0])) { + vswap(); + rev = 0; + } + if (arm64_iconst(&val, &vtop[-1])) { + gv(RC_INT); + a = intr(vtop[0].r); + --vtop; + x = get_reg(RC_INT); + ++vtop; + if (arm64_gen_opic(op, l, rev, val, intr(x), a)) { + vtop[0].r = x; + vswap(); + --vtop; + return; + } + } + if (!rev) + vswap(); + } + gv2(RC_INT, RC_INT); assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); a = intr(vtop[-1].r); |
