diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2019-04-15 19:51:31 +0200 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2019-04-15 19:51:31 +0200 |
commit | 2a8584c9853f9392ef0ddcb0ed9b3d2b14b1db83 (patch) | |
tree | d6cbe3a64b01818429ba6f740c14350480ee790e | |
parent | 81da1cdebb213077a1ce2c1aaed051de0751e13c (diff) | |
download | roux-2a8584c9853f9392ef0ddcb0ed9b3d2b14b1db83.tar.gz |
handle big constants moves to slots
There is no flavor of mov which can set 8 bytes of memory to a constant not representable as an int32. The solution is simply to emit two movs of 4 bytes each.
-rw-r--r-- | amd64/emit.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/amd64/emit.c b/amd64/emit.c index ac7a1f3..1fe141f 100644 --- a/amd64/emit.c +++ b/amd64/emit.c @@ -430,33 +430,48 @@ emitins(Ins i, Fn *fn, FILE *f) } goto Table; case Ocopy: - /* make sure we don't emit useless copies, - * also, we can use a trick to load 64-bits - * registers, it's detailed in my note below - * http://c9x.me/art/notes.html?09/19/2015 */ - t0 = rtype(i.arg[0]); + /* copies are used for many things; see my note + * to understand how to load big constants: + * https://c9x.me/notes/2015-09-19.html */ + assert(rtype(i.to) != RMem); if (req(i.to, R) || req(i.arg[0], R)) break; - if (isreg(i.to) + if (req(i.to, i.arg[0])) + break; + t0 = rtype(i.arg[0]); + if (i.cls == Kl && t0 == RCon - && i.cls == Kl - && fn->con[i.arg[0].val].type == CBits - && (val = fn->con[i.arg[0].val].bits.i) >= 0 - && val <= UINT32_MAX) { - emitf("movl %W0, %W=", &i, fn, f); - } else if (isreg(i.to) + && fn->con[i.arg[0].val].type == CBits) { + val = fn->con[i.arg[0].val].bits.i; + if (isreg(i.to)) + if (val >= 0 && val <= UINT32_MAX) { + emitf("movl %W0, %W=", &i, fn, f); + break; + } + if (rtype(i.to) == RSlot) + if (val < INT32_MIN || val > INT32_MAX) { + emitf("movl %0, %=", &i, fn, f); + emitf("movl %0>>32, 4+%=", &i, fn, f); + break; + } + } + if (isreg(i.to) && t0 == RCon && fn->con[i.arg[0].val].type == CAddr) { emitf("lea%k %M0, %=", &i, fn, f); - } else if (rtype(i.to) == RSlot + break; + } + if (rtype(i.to) == RSlot && (t0 == RSlot || t0 == RMem)) { i.cls = KWIDE(i.cls) ? Kd : Ks; i.arg[1] = TMP(XMM0+15); emitf("mov%k %0, %1", &i, fn, f); emitf("mov%k %1, %=", &i, fn, f); - - } else if (!req(i.arg[0], i.to)) - emitf("mov%k %0, %=", &i, fn, f); + break; + } + /* conveniently, the assembler knows if it + * should use movabsq when reading movq */ + emitf("mov%k %0, %=", &i, fn, f); break; case Ocall: /* calls simply have a weird syntax in AT&T |