2009-06-03 00:26:02 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2009-06-03 00:26:02 -06:00
|
|
|
#include "gg.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* attempt to generate 64-bit
|
|
|
|
* res = n
|
|
|
|
* return 1 on success, 0 if op not handled.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cgen64(Node *n, Node *res)
|
|
|
|
{
|
|
|
|
Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
|
2009-06-06 20:28:16 -06:00
|
|
|
Node lo1, lo2, hi1, hi2;
|
2009-06-03 00:26:02 -06:00
|
|
|
Prog *p1, *p2;
|
|
|
|
uint64 v;
|
|
|
|
uint32 lv, hv;
|
|
|
|
|
|
|
|
if(res->op != OINDREG && res->op != ONAME) {
|
|
|
|
dump("n", n);
|
|
|
|
dump("res", res);
|
|
|
|
fatal("cgen64 %O of %O", n->op, res->op);
|
|
|
|
}
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
fatal("cgen64 %O", n->op);
|
|
|
|
|
|
|
|
case OMINUS:
|
|
|
|
cgen(n->left, res);
|
|
|
|
split64(res, &lo1, &hi1);
|
|
|
|
gins(ANEGL, N, &lo1);
|
|
|
|
gins(AADCL, ncon(0), &hi1);
|
|
|
|
gins(ANEGL, N, &hi1);
|
|
|
|
splitclean();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case OCOM:
|
|
|
|
cgen(n->left, res);
|
|
|
|
split64(res, &lo1, &hi1);
|
|
|
|
gins(ANOTL, N, &lo1);
|
|
|
|
gins(ANOTL, N, &hi1);
|
|
|
|
splitclean();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case OADD:
|
|
|
|
case OSUB:
|
|
|
|
case OMUL:
|
2012-05-24 15:20:07 -06:00
|
|
|
case OLROT:
|
2009-06-03 00:26:02 -06:00
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
|
|
|
case OAND:
|
|
|
|
case OOR:
|
|
|
|
case OXOR:
|
|
|
|
// binary operators.
|
|
|
|
// common setup below.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = n->left;
|
|
|
|
r = n->right;
|
|
|
|
if(!l->addable) {
|
2009-12-02 19:31:29 -07:00
|
|
|
tempname(&t1, l->type);
|
2009-06-03 00:26:02 -06:00
|
|
|
cgen(l, &t1);
|
|
|
|
l = &t1;
|
|
|
|
}
|
|
|
|
if(r != N && !r->addable) {
|
2009-12-02 19:31:29 -07:00
|
|
|
tempname(&t2, r->type);
|
2009-06-03 00:26:02 -06:00
|
|
|
cgen(r, &t2);
|
|
|
|
r = &t2;
|
|
|
|
}
|
|
|
|
|
|
|
|
nodreg(&ax, types[TINT32], D_AX);
|
|
|
|
nodreg(&cx, types[TINT32], D_CX);
|
|
|
|
nodreg(&dx, types[TINT32], D_DX);
|
|
|
|
|
|
|
|
// Setup for binary operation.
|
|
|
|
split64(l, &lo1, &hi1);
|
|
|
|
if(is64(r->type))
|
|
|
|
split64(r, &lo2, &hi2);
|
|
|
|
|
|
|
|
// Do op. Leave result in DX:AX.
|
|
|
|
switch(n->op) {
|
|
|
|
case OADD:
|
|
|
|
// TODO: Constants
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
gins(AADDL, &lo2, &ax);
|
|
|
|
gins(AADCL, &hi2, &dx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OSUB:
|
|
|
|
// TODO: Constants.
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
gins(ASUBL, &lo2, &ax);
|
|
|
|
gins(ASBBL, &hi2, &dx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMUL:
|
|
|
|
// let's call the next two EX and FX.
|
|
|
|
regalloc(&ex, types[TPTR32], N);
|
|
|
|
regalloc(&fx, types[TPTR32], N);
|
|
|
|
|
|
|
|
// load args into DX:AX and EX:CX.
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
gins(AMOVL, &lo2, &cx);
|
|
|
|
gins(AMOVL, &hi2, &ex);
|
|
|
|
|
|
|
|
// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
|
|
|
|
gins(AMOVL, &dx, &fx);
|
|
|
|
gins(AORL, &ex, &fx);
|
|
|
|
p1 = gbranch(AJNE, T);
|
|
|
|
gins(AMULL, &cx, N); // implicit &ax
|
|
|
|
p2 = gbranch(AJMP, T);
|
|
|
|
patch(p1, pc);
|
|
|
|
|
|
|
|
// full 64x64 -> 64, from 32x32 -> 64.
|
|
|
|
gins(AIMULL, &cx, &dx);
|
|
|
|
gins(AMOVL, &ax, &fx);
|
|
|
|
gins(AIMULL, &ex, &fx);
|
|
|
|
gins(AADDL, &dx, &fx);
|
|
|
|
gins(AMOVL, &cx, &dx);
|
|
|
|
gins(AMULL, &dx, N); // implicit &ax
|
|
|
|
gins(AADDL, &fx, &dx);
|
|
|
|
patch(p2, pc);
|
|
|
|
|
|
|
|
regfree(&ex);
|
|
|
|
regfree(&fx);
|
|
|
|
break;
|
2012-05-24 15:20:07 -06:00
|
|
|
|
|
|
|
case OLROT:
|
|
|
|
// We only rotate by a constant c in [0,64).
|
|
|
|
// if c >= 32:
|
|
|
|
// lo, hi = hi, lo
|
|
|
|
// c -= 32
|
|
|
|
// if c == 0:
|
|
|
|
// no-op
|
|
|
|
// else:
|
|
|
|
// t = hi
|
|
|
|
// shld hi:lo, c
|
|
|
|
// shld lo:t, c
|
|
|
|
v = mpgetfix(r->val.u.xval);
|
|
|
|
if(v >= 32) {
|
|
|
|
// reverse during load to do the first 32 bits of rotate
|
|
|
|
v -= 32;
|
|
|
|
gins(AMOVL, &lo1, &dx);
|
|
|
|
gins(AMOVL, &hi1, &ax);
|
|
|
|
} else {
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
}
|
|
|
|
if(v == 0) {
|
|
|
|
// done
|
|
|
|
} else {
|
|
|
|
gins(AMOVL, &dx, &cx);
|
|
|
|
p1 = gins(ASHLL, ncon(v), &dx);
|
|
|
|
p1->from.index = D_AX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
p1 = gins(ASHLL, ncon(v), &ax);
|
|
|
|
p1->from.index = D_CX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
}
|
|
|
|
break;
|
2009-06-03 00:26:02 -06:00
|
|
|
|
|
|
|
case OLSH:
|
|
|
|
if(r->op == OLITERAL) {
|
|
|
|
v = mpgetfix(r->val.u.xval);
|
|
|
|
if(v >= 64) {
|
|
|
|
if(is64(r->type))
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
split64(res, &lo2, &hi2);
|
|
|
|
gins(AMOVL, ncon(0), &lo2);
|
|
|
|
gins(AMOVL, ncon(0), &hi2);
|
|
|
|
splitclean();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if(v >= 32) {
|
|
|
|
if(is64(r->type))
|
|
|
|
splitclean();
|
|
|
|
split64(res, &lo2, &hi2);
|
|
|
|
gmove(&lo1, &hi2);
|
|
|
|
if(v > 32) {
|
|
|
|
gins(ASHLL, ncon(v - 32), &hi2);
|
|
|
|
}
|
|
|
|
gins(AMOVL, ncon(0), &lo2);
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// general shift
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
p1 = gins(ASHLL, ncon(v), &dx);
|
|
|
|
p1->from.index = D_AX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
gins(ASHLL, ncon(v), &ax);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// load value into DX:AX.
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
|
|
|
|
// load shift value into register.
|
|
|
|
// if high bits are set, zero value.
|
|
|
|
p1 = P;
|
|
|
|
if(is64(r->type)) {
|
|
|
|
gins(ACMPL, &hi2, ncon(0));
|
|
|
|
p1 = gbranch(AJNE, T);
|
|
|
|
gins(AMOVL, &lo2, &cx);
|
2009-10-15 17:32:45 -06:00
|
|
|
} else {
|
|
|
|
cx.type = types[TUINT32];
|
|
|
|
gmove(r, &cx);
|
|
|
|
}
|
2009-06-03 00:26:02 -06:00
|
|
|
|
|
|
|
// if shift count is >=64, zero value
|
|
|
|
gins(ACMPL, &cx, ncon(64));
|
|
|
|
p2 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
if(p1 != P)
|
|
|
|
patch(p1, pc);
|
|
|
|
gins(AXORL, &dx, &dx);
|
|
|
|
gins(AXORL, &ax, &ax);
|
|
|
|
patch(p2, pc);
|
|
|
|
|
|
|
|
// if shift count is >= 32, zero low.
|
|
|
|
gins(ACMPL, &cx, ncon(32));
|
|
|
|
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
gins(AMOVL, &ax, &dx);
|
|
|
|
gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
|
|
|
|
gins(AXORL, &ax, &ax);
|
|
|
|
p2 = gbranch(AJMP, T);
|
|
|
|
patch(p1, pc);
|
|
|
|
|
|
|
|
// general shift
|
|
|
|
p1 = gins(ASHLL, &cx, &dx);
|
|
|
|
p1->from.index = D_AX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
gins(ASHLL, &cx, &ax);
|
|
|
|
patch(p2, pc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORSH:
|
|
|
|
if(r->op == OLITERAL) {
|
|
|
|
v = mpgetfix(r->val.u.xval);
|
|
|
|
if(v >= 64) {
|
|
|
|
if(is64(r->type))
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
split64(res, &lo2, &hi2);
|
|
|
|
if(hi1.type->etype == TINT32) {
|
|
|
|
gmove(&hi1, &lo2);
|
|
|
|
gins(ASARL, ncon(31), &lo2);
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
gins(ASARL, ncon(31), &hi2);
|
|
|
|
} else {
|
|
|
|
gins(AMOVL, ncon(0), &lo2);
|
|
|
|
gins(AMOVL, ncon(0), &hi2);
|
|
|
|
}
|
|
|
|
splitclean();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if(v >= 32) {
|
|
|
|
if(is64(r->type))
|
|
|
|
splitclean();
|
|
|
|
split64(res, &lo2, &hi2);
|
|
|
|
gmove(&hi1, &lo2);
|
|
|
|
if(v > 32)
|
|
|
|
gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
|
|
|
|
if(hi1.type->etype == TINT32) {
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
gins(ASARL, ncon(31), &hi2);
|
|
|
|
} else
|
|
|
|
gins(AMOVL, ncon(0), &hi2);
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// general shift
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
p1 = gins(ASHRL, ncon(v), &ax);
|
|
|
|
p1->from.index = D_DX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
gins(optoas(ORSH, hi1.type), ncon(v), &dx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// load value into DX:AX.
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
|
|
|
|
// load shift value into register.
|
|
|
|
// if high bits are set, zero value.
|
|
|
|
p1 = P;
|
|
|
|
if(is64(r->type)) {
|
|
|
|
gins(ACMPL, &hi2, ncon(0));
|
|
|
|
p1 = gbranch(AJNE, T);
|
|
|
|
gins(AMOVL, &lo2, &cx);
|
2009-10-15 17:32:45 -06:00
|
|
|
} else {
|
|
|
|
cx.type = types[TUINT32];
|
|
|
|
gmove(r, &cx);
|
|
|
|
}
|
2009-06-03 00:26:02 -06:00
|
|
|
|
|
|
|
// if shift count is >=64, zero or sign-extend value
|
|
|
|
gins(ACMPL, &cx, ncon(64));
|
|
|
|
p2 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
if(p1 != P)
|
|
|
|
patch(p1, pc);
|
|
|
|
if(hi1.type->etype == TINT32) {
|
|
|
|
gins(ASARL, ncon(31), &dx);
|
|
|
|
gins(AMOVL, &dx, &ax);
|
|
|
|
} else {
|
|
|
|
gins(AXORL, &dx, &dx);
|
|
|
|
gins(AXORL, &ax, &ax);
|
|
|
|
}
|
|
|
|
patch(p2, pc);
|
|
|
|
|
|
|
|
// if shift count is >= 32, sign-extend hi.
|
|
|
|
gins(ACMPL, &cx, ncon(32));
|
|
|
|
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
gins(AMOVL, &dx, &ax);
|
|
|
|
if(hi1.type->etype == TINT32) {
|
|
|
|
gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
|
|
|
|
gins(ASARL, ncon(31), &dx);
|
|
|
|
} else {
|
|
|
|
gins(ASHRL, &cx, &ax);
|
|
|
|
gins(AXORL, &dx, &dx);
|
|
|
|
}
|
|
|
|
p2 = gbranch(AJMP, T);
|
|
|
|
patch(p1, pc);
|
|
|
|
|
|
|
|
// general shift
|
|
|
|
p1 = gins(ASHRL, &cx, &ax);
|
|
|
|
p1->from.index = D_DX; // double-width shift
|
|
|
|
p1->from.scale = 0;
|
|
|
|
gins(optoas(ORSH, hi1.type), &cx, &dx);
|
|
|
|
patch(p2, pc);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OXOR:
|
|
|
|
case OAND:
|
|
|
|
case OOR:
|
|
|
|
// make constant the right side (it usually is anyway).
|
|
|
|
if(lo1.op == OLITERAL) {
|
|
|
|
nswap(&lo1, &lo2);
|
|
|
|
nswap(&hi1, &hi2);
|
|
|
|
}
|
|
|
|
if(lo2.op == OLITERAL) {
|
|
|
|
// special cases for constants.
|
|
|
|
lv = mpgetfix(lo2.val.u.xval);
|
|
|
|
hv = mpgetfix(hi2.val.u.xval);
|
|
|
|
splitclean(); // right side
|
|
|
|
split64(res, &lo2, &hi2);
|
|
|
|
switch(n->op) {
|
|
|
|
case OXOR:
|
|
|
|
gmove(&lo1, &lo2);
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
switch(lv) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 0xffffffffu:
|
|
|
|
gins(ANOTL, N, &lo2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gins(AXORL, ncon(lv), &lo2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(hv) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 0xffffffffu:
|
|
|
|
gins(ANOTL, N, &hi2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gins(AXORL, ncon(hv), &hi2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OAND:
|
|
|
|
switch(lv) {
|
|
|
|
case 0:
|
|
|
|
gins(AMOVL, ncon(0), &lo2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gmove(&lo1, &lo2);
|
|
|
|
if(lv != 0xffffffffu)
|
|
|
|
gins(AANDL, ncon(lv), &lo2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(hv) {
|
|
|
|
case 0:
|
|
|
|
gins(AMOVL, ncon(0), &hi2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
if(hv != 0xffffffffu)
|
|
|
|
gins(AANDL, ncon(hv), &hi2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OOR:
|
|
|
|
switch(lv) {
|
|
|
|
case 0:
|
|
|
|
gmove(&lo1, &lo2);
|
|
|
|
break;
|
|
|
|
case 0xffffffffu:
|
|
|
|
gins(AMOVL, ncon(0xffffffffu), &lo2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gmove(&lo1, &lo2);
|
|
|
|
gins(AORL, ncon(lv), &lo2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(hv) {
|
|
|
|
case 0:
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
break;
|
|
|
|
case 0xffffffffu:
|
|
|
|
gins(AMOVL, ncon(0xffffffffu), &hi2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gmove(&hi1, &hi2);
|
|
|
|
gins(AORL, ncon(hv), &hi2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
gins(AMOVL, &lo1, &ax);
|
|
|
|
gins(AMOVL, &hi1, &dx);
|
|
|
|
gins(optoas(n->op, lo1.type), &lo2, &ax);
|
|
|
|
gins(optoas(n->op, lo1.type), &hi2, &dx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(is64(r->type))
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
|
|
|
|
split64(res, &lo1, &hi1);
|
|
|
|
gins(AMOVL, &ax, &lo1);
|
|
|
|
gins(AMOVL, &dx, &hi1);
|
|
|
|
splitclean();
|
|
|
|
|
2009-12-02 19:31:29 -07:00
|
|
|
out:;
|
2009-06-03 00:26:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* generate comparison of nl, nr, both 64-bit.
|
|
|
|
* nl is memory; nr is constant or memory.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cmp64(Node *nl, Node *nr, int op, Prog *to)
|
|
|
|
{
|
|
|
|
Node lo1, hi1, lo2, hi2, rr;
|
|
|
|
Prog *br;
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
split64(nl, &lo1, &hi1);
|
|
|
|
split64(nr, &lo2, &hi2);
|
|
|
|
|
|
|
|
// compare most significant word;
|
|
|
|
// if they differ, we're done.
|
|
|
|
t = hi1.type;
|
|
|
|
if(nl->op == OLITERAL || nr->op == OLITERAL)
|
|
|
|
gins(ACMPL, &hi1, &hi2);
|
|
|
|
else {
|
|
|
|
regalloc(&rr, types[TINT32], N);
|
|
|
|
gins(AMOVL, &hi1, &rr);
|
|
|
|
gins(ACMPL, &rr, &hi2);
|
|
|
|
regfree(&rr);
|
|
|
|
}
|
|
|
|
br = P;
|
|
|
|
switch(op) {
|
|
|
|
default:
|
|
|
|
fatal("cmp64 %O %T", op, t);
|
|
|
|
case OEQ:
|
|
|
|
// cmp hi
|
|
|
|
// jne L
|
|
|
|
// cmp lo
|
|
|
|
// jeq to
|
|
|
|
// L:
|
|
|
|
br = gbranch(AJNE, T);
|
|
|
|
break;
|
|
|
|
case ONE:
|
|
|
|
// cmp hi
|
|
|
|
// jne to
|
|
|
|
// cmp lo
|
|
|
|
// jne to
|
|
|
|
patch(gbranch(AJNE, T), to);
|
|
|
|
break;
|
|
|
|
case OGE:
|
|
|
|
case OGT:
|
|
|
|
// cmp hi
|
|
|
|
// jgt to
|
|
|
|
// jlt L
|
|
|
|
// cmp lo
|
|
|
|
// jge to (or jgt to)
|
|
|
|
// L:
|
|
|
|
patch(gbranch(optoas(OGT, t), T), to);
|
|
|
|
br = gbranch(optoas(OLT, t), T);
|
|
|
|
break;
|
|
|
|
case OLE:
|
|
|
|
case OLT:
|
|
|
|
// cmp hi
|
|
|
|
// jlt to
|
|
|
|
// jgt L
|
|
|
|
// cmp lo
|
|
|
|
// jle to (or jlt to)
|
|
|
|
// L:
|
|
|
|
patch(gbranch(optoas(OLT, t), T), to);
|
|
|
|
br = gbranch(optoas(OGT, t), T);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compare least significant word
|
|
|
|
t = lo1.type;
|
|
|
|
if(nl->op == OLITERAL || nr->op == OLITERAL)
|
|
|
|
gins(ACMPL, &lo1, &lo2);
|
|
|
|
else {
|
|
|
|
regalloc(&rr, types[TINT32], N);
|
|
|
|
gins(AMOVL, &lo1, &rr);
|
|
|
|
gins(ACMPL, &rr, &lo2);
|
|
|
|
regfree(&rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// jump again
|
|
|
|
patch(gbranch(optoas(op, t), T), to);
|
|
|
|
|
|
|
|
// point first branch down here if appropriate
|
|
|
|
if(br != P)
|
|
|
|
patch(br, pc);
|
|
|
|
|
|
|
|
splitclean();
|
|
|
|
splitclean();
|
|
|
|
}
|
|
|
|
|