2008-06-04 15:37:38 -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.
|
|
|
|
|
|
|
|
#include "gg.h"
|
|
|
|
|
|
|
|
void
|
|
|
|
cgen(Node *n, Node *res)
|
|
|
|
{
|
|
|
|
Node *nl, *nr, *r;
|
2008-06-07 16:21:02 -06:00
|
|
|
Node n1, n2;
|
2008-06-04 15:37:38 -06:00
|
|
|
int a;
|
|
|
|
Prog *p1, *p2, *p3;
|
|
|
|
|
|
|
|
if(debug['g']) {
|
2008-06-08 17:11:14 -06:00
|
|
|
dump("\ncgen-res", res);
|
2008-06-04 15:37:38 -06:00
|
|
|
dump("cgen-r", n);
|
|
|
|
}
|
|
|
|
if(n == N || n->type == T)
|
|
|
|
return;
|
2008-06-24 11:30:33 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(res == N || res->type == T)
|
|
|
|
fatal("cgen: res nil");
|
|
|
|
|
2008-06-06 17:49:35 -06:00
|
|
|
if(n->ullman >= UINF) {
|
|
|
|
if(n->op == OINDREG)
|
|
|
|
fatal("cgen: this is going to misscompile");
|
2008-06-24 11:30:33 -06:00
|
|
|
if(res->ullman >= UINF) {
|
2008-06-27 18:53:23 -06:00
|
|
|
tempname(&n1, n->type);
|
|
|
|
cgen(n, &n1);
|
|
|
|
cgen(&n1, res);
|
|
|
|
goto ret;
|
2008-06-24 11:30:33 -06:00
|
|
|
}
|
2008-06-06 17:49:35 -06:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(isfat(n->type)) {
|
|
|
|
sgen(n, res, n->type->width);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!res->addable) {
|
2008-06-06 17:49:35 -06:00
|
|
|
if(n->ullman > res->ullman) {
|
2008-06-06 18:01:33 -06:00
|
|
|
regalloc(&n1, n->type, res);
|
2008-06-06 17:49:35 -06:00
|
|
|
cgen(n, &n1);
|
|
|
|
cgen(&n1, res);
|
|
|
|
regfree(&n1);
|
2008-06-27 18:53:23 -06:00
|
|
|
goto ret;
|
2008-06-06 17:49:35 -06:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
igen(res, &n1, N);
|
|
|
|
cgen(n, &n1);
|
|
|
|
regfree(&n1);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->addable) {
|
|
|
|
gmove(n, res);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
nl = n->left;
|
|
|
|
nr = n->right;
|
|
|
|
if(nl != N && nl->ullman >= UINF)
|
|
|
|
if(nr != N && nr->ullman >= UINF) {
|
2008-06-27 17:59:14 -06:00
|
|
|
tempname(&n1, nr->type);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
n2 = *n;
|
|
|
|
n2.right = &n1;
|
|
|
|
cgen(&n2, res);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
dump("cgen", n);
|
|
|
|
fatal("cgen: unknown op %N", n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// these call bgen to get a bool value
|
|
|
|
case OOROR:
|
|
|
|
case OANDAND:
|
|
|
|
case OEQ:
|
|
|
|
case ONE:
|
|
|
|
case OLT:
|
|
|
|
case OLE:
|
|
|
|
case OGE:
|
|
|
|
case OGT:
|
|
|
|
case ONOT:
|
|
|
|
p1 = gbranch(AJMP, T);
|
|
|
|
p2 = pc;
|
|
|
|
gmove(booltrue, res);
|
|
|
|
p3 = gbranch(AJMP, T);
|
|
|
|
patch(p1, pc);
|
|
|
|
bgen(n, 1, p2);
|
|
|
|
gmove(boolfalse, res);
|
|
|
|
patch(p3, pc);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OPLUS:
|
|
|
|
cgen(nl, res);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
// unary
|
|
|
|
case OCOM:
|
2008-08-10 15:35:02 -06:00
|
|
|
a = optoas(OXOR, nl->type);
|
|
|
|
regalloc(&n1, nl->type, N);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
nodconst(&n2, nl->type, -1);
|
|
|
|
gins(a, &n2, &n1);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OMINUS:
|
2008-06-04 15:37:38 -06:00
|
|
|
a = optoas(n->op, nl->type);
|
|
|
|
goto uop;
|
|
|
|
|
|
|
|
// symmetric binary
|
|
|
|
case OAND:
|
|
|
|
case OOR:
|
|
|
|
case OXOR:
|
|
|
|
case OADD:
|
|
|
|
case OMUL:
|
|
|
|
a = optoas(n->op, nl->type);
|
|
|
|
goto sbop;
|
|
|
|
|
|
|
|
// asymmetric binary
|
|
|
|
case OSUB:
|
|
|
|
a = optoas(n->op, nl->type);
|
|
|
|
goto abop;
|
|
|
|
|
|
|
|
case OCONV:
|
|
|
|
if(eqtype(n->type, nl->type, 0)) {
|
|
|
|
cgen(nl, res);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
regalloc(&n1, nl->type, res);
|
|
|
|
cgen(nl, &n1);
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrarray(n->type) && isptrdarray(nl->type)) {
|
2008-08-27 18:28:30 -06:00
|
|
|
// convert dynamic array to static array
|
|
|
|
n2 = n1;
|
|
|
|
n2.op = OINDREG;
|
|
|
|
n2.xoffset = offsetof(Array,array);
|
|
|
|
n2.type = types[tptr];
|
|
|
|
gins(AMOVQ, &n2, &n1);
|
|
|
|
}
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrdarray(n->type) && isptrarray(nl->type)) {
|
2008-08-27 18:28:30 -06:00
|
|
|
// conver static array to dynamic array
|
|
|
|
// it is assumed that the dope is just before the array
|
|
|
|
nodconst(&n2, types[tptr], offsetof(Array,b));
|
|
|
|
gins(ASUBQ, &n2, &n1);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OS2I:
|
|
|
|
case OI2I:
|
|
|
|
case OI2S:
|
|
|
|
|
|
|
|
case OINDEXPTR:
|
|
|
|
case OINDEX:
|
|
|
|
case ODOT:
|
|
|
|
case ODOTPTR:
|
|
|
|
case OIND:
|
|
|
|
igen(n, &n1, res);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OLEN:
|
|
|
|
if(isptrto(nl->type, TSTRING)) {
|
|
|
|
regalloc(&n1, types[tptr], res);
|
2008-06-08 18:46:28 -06:00
|
|
|
cgen(nl, &n1);
|
2008-06-04 15:37:38 -06:00
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[TINT32];
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
}
|
2008-06-24 15:11:20 -06:00
|
|
|
if(isptrto(nl->type, TMAP)) {
|
|
|
|
regalloc(&n1, types[tptr], res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[TINT32];
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
}
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrdarray(nl->type)) {
|
2008-08-27 18:28:30 -06:00
|
|
|
regalloc(&n1, types[tptr], res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[TUINT32];
|
|
|
|
n1.xoffset = offsetof(Array,nel);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
fatal("cgen: OLEN: unknown type %lT", nl->type);
|
|
|
|
break;
|
|
|
|
|
2008-08-27 18:28:30 -06:00
|
|
|
case OCAP:
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrdarray(nl->type)) {
|
2008-08-27 18:28:30 -06:00
|
|
|
regalloc(&n1, types[tptr], res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[TUINT32];
|
|
|
|
n1.xoffset = offsetof(Array,cap);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fatal("cgen: OCAP: unknown type %lT", nl->type);
|
|
|
|
break;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case OADDR:
|
|
|
|
agen(nl, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALLMETH:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_callmeth(n, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
cgen_callret(n, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALLINTER:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_callinter(n, res, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
cgen_callret(n, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALL:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_call(n, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
cgen_callret(n, res);
|
|
|
|
break;
|
2008-06-06 21:43:29 -06:00
|
|
|
|
|
|
|
case OMOD:
|
|
|
|
case ODIV:
|
2008-06-09 14:16:50 -06:00
|
|
|
if(isfloat[n->type->etype]) {
|
|
|
|
a = optoas(n->op, nl->type);
|
|
|
|
goto abop;
|
|
|
|
}
|
2008-06-06 21:43:29 -06:00
|
|
|
cgen_div(n->op, nl, nr, res);
|
|
|
|
break;
|
2008-06-08 18:21:46 -06:00
|
|
|
|
2008-06-07 16:21:02 -06:00
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
|
|
|
cgen_shift(n->op, nl, nr, res);
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
sbop: // symmetric binary
|
|
|
|
if(nl->ullman < nr->ullman) {
|
|
|
|
r = nl;
|
|
|
|
nl = nr;
|
|
|
|
nr = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
abop: // asymmetric binary
|
2008-06-07 16:21:02 -06:00
|
|
|
if(nl->ullman >= nr->ullman) {
|
|
|
|
regalloc(&n1, nl->type, res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
regalloc(&n2, nr->type, N);
|
|
|
|
cgen(nr, &n2);
|
|
|
|
} else {
|
|
|
|
regalloc(&n2, nr->type, N);
|
|
|
|
cgen(nr, &n2);
|
2008-06-04 15:37:38 -06:00
|
|
|
regalloc(&n1, nl->type, res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
}
|
2008-06-07 16:21:02 -06:00
|
|
|
gins(a, &n2, &n1);
|
2008-06-04 15:37:38 -06:00
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
2008-06-07 16:21:02 -06:00
|
|
|
regfree(&n2);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
uop: // unary
|
|
|
|
regalloc(&n1, nl->type, res);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
gins(a, N, &n1);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
ret:
|
2008-06-28 18:27:39 -06:00
|
|
|
;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
agen(Node *n, Node *res)
|
|
|
|
{
|
|
|
|
Node *nl, *nr;
|
|
|
|
Node n1, n2, n3, tmp;
|
2008-08-27 18:28:30 -06:00
|
|
|
Prog *p1;
|
2008-08-03 18:25:15 -06:00
|
|
|
uint32 w;
|
2008-06-04 15:37:38 -06:00
|
|
|
Type *t;
|
2008-06-21 16:11:29 -06:00
|
|
|
|
|
|
|
if(debug['g']) {
|
|
|
|
dump("\nagen-res", res);
|
|
|
|
dump("agen-r", n);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
if(n == N || n->type == T)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(!isptr[res->type->etype])
|
|
|
|
fatal("agen: not tptr: %T", res->type);
|
|
|
|
|
|
|
|
if(n->addable) {
|
|
|
|
regalloc(&n1, types[tptr], res);
|
|
|
|
gins(ALEAQ, n, &n1);
|
|
|
|
gmove(&n1, res);
|
|
|
|
regfree(&n1);
|
2008-06-08 18:21:46 -06:00
|
|
|
goto ret;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-06-08 18:21:46 -06:00
|
|
|
nl = n->left;
|
|
|
|
nr = n->right;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
fatal("agen: unknown op %N", n);
|
|
|
|
break;
|
|
|
|
|
2008-06-21 16:11:29 -06:00
|
|
|
case OCALLMETH:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_callmeth(n, 0);
|
2008-06-21 16:11:29 -06:00
|
|
|
cgen_aret(n, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALLINTER:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_callinter(n, res, 0);
|
2008-06-21 16:11:29 -06:00
|
|
|
cgen_aret(n, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCALL:
|
2008-07-07 18:59:32 -06:00
|
|
|
cgen_call(n, 0);
|
2008-06-21 16:11:29 -06:00
|
|
|
cgen_aret(n, res);
|
|
|
|
break;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case OINDEXPTR:
|
|
|
|
w = n->type->width;
|
|
|
|
if(nr->addable)
|
|
|
|
goto iprad;
|
|
|
|
if(nl->addable) {
|
|
|
|
regalloc(&n1, nr->type, N);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
cgen(nl, res);
|
|
|
|
goto index;
|
|
|
|
}
|
|
|
|
cgen(nr, res);
|
|
|
|
tempname(&tmp, nr->type);
|
|
|
|
gmove(res, &tmp);
|
|
|
|
|
|
|
|
iprad:
|
|
|
|
cgen(nl, res);
|
|
|
|
regalloc(&n1, nr->type, N);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
goto index;
|
|
|
|
|
|
|
|
case OS2I:
|
|
|
|
case OI2I:
|
|
|
|
case OI2S:
|
|
|
|
agen_inter(n, res);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OINDEX:
|
|
|
|
w = n->type->width;
|
|
|
|
if(nr->addable)
|
|
|
|
goto irad;
|
|
|
|
if(nl->addable) {
|
|
|
|
regalloc(&n1, nr->type, N);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
agen(nl, res);
|
|
|
|
goto index;
|
|
|
|
}
|
|
|
|
cgen(nr, res);
|
|
|
|
tempname(&tmp, nr->type);
|
|
|
|
gmove(res, &tmp);
|
|
|
|
|
|
|
|
irad:
|
|
|
|
agen(nl, res);
|
|
|
|
regalloc(&n1, nr->type, N);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
goto index;
|
|
|
|
|
|
|
|
index:
|
|
|
|
// &a is in res
|
|
|
|
// i is in &n1
|
|
|
|
// w is width
|
2008-08-27 18:28:30 -06:00
|
|
|
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrdarray(nl->type)) {
|
2008-08-27 18:28:30 -06:00
|
|
|
regalloc(&n2, types[tptr], res);
|
|
|
|
gmove(res, &n2);
|
|
|
|
|
|
|
|
if(!debug['B']) {
|
|
|
|
// check bounds
|
|
|
|
n3 = n2;
|
|
|
|
n3.op = OINDREG;
|
|
|
|
n3.type = types[tptr];
|
|
|
|
n3.xoffset = offsetof(Array, nel);
|
|
|
|
gins(optoas(OCMP, types[TUINT32]), &n1, &n3);
|
|
|
|
|
|
|
|
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
|
|
|
|
nodconst(&n3, types[TUINT8], 5); // 5 is range trap
|
|
|
|
gins(AINT, &n3, N);
|
|
|
|
patch(p1, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetch array base from dope
|
|
|
|
n3 = n2;
|
|
|
|
n3.op = OINDREG;
|
|
|
|
n3.type = types[tptr];
|
|
|
|
n3.xoffset = offsetof(Array, array);
|
|
|
|
gins(AMOVQ, &n3, &n2);
|
|
|
|
gmove(&n2, res);
|
|
|
|
regfree(&n2);
|
|
|
|
} else
|
|
|
|
if(!debug['B']) {
|
|
|
|
// check bounds
|
|
|
|
nodconst(&n3, types[TUINT32], nl->type->bound);
|
2008-08-28 16:17:37 -06:00
|
|
|
if(isptrarray(nl->type))
|
2008-08-27 18:28:30 -06:00
|
|
|
nodconst(&n3, types[TUINT32], nl->type->type->bound);
|
|
|
|
gins(optoas(OCMP, types[TUINT32]), &n1, &n3);
|
|
|
|
|
|
|
|
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
|
|
|
|
|
|
|
|
nodconst(&n3, types[TUINT8], 5); // 5 is range trap
|
|
|
|
gins(AINT, &n3, N);
|
|
|
|
patch(p1, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
t = types[TUINT64];
|
2008-06-07 16:21:02 -06:00
|
|
|
if(issigned[n1.type->etype])
|
2008-08-27 18:28:30 -06:00
|
|
|
t = types[TINT64];
|
|
|
|
|
|
|
|
regalloc(&n2, t, &n1); // i
|
2008-06-07 16:21:02 -06:00
|
|
|
gmove(&n1, &n2);
|
|
|
|
regfree(&n1);
|
2008-08-27 18:28:30 -06:00
|
|
|
|
|
|
|
nodconst(&n3, t, w); // w
|
|
|
|
gins(optoas(OMUL, t), &n3, &n2);
|
|
|
|
gins(optoas(OADD, types[tptr]), &n2, res);
|
2008-06-07 16:21:02 -06:00
|
|
|
regfree(&n2);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
|
2008-06-15 21:24:30 -06:00
|
|
|
case OIND:
|
|
|
|
cgen(nl, res);
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
case ODOT:
|
|
|
|
t = nl->type;
|
|
|
|
agen(nl, res);
|
|
|
|
if(n->xoffset != 0) {
|
|
|
|
nodconst(&n1, types[TINT64], n->xoffset);
|
|
|
|
gins(optoas(OADD, types[tptr]), &n1, res);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ODOTPTR:
|
|
|
|
t = nl->type;
|
|
|
|
if(!isptr[t->etype])
|
|
|
|
fatal("agen: not ptr %N", n);
|
|
|
|
cgen(nl, res);
|
|
|
|
if(n->xoffset != 0) {
|
|
|
|
nodconst(&n1, types[TINT64], n->xoffset);
|
|
|
|
gins(optoas(OADD, types[tptr]), &n1, res);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-06-08 18:21:46 -06:00
|
|
|
|
|
|
|
ret:
|
2008-06-28 18:27:39 -06:00
|
|
|
;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
vlong
|
|
|
|
fieldoffset(Type *t, Node *n)
|
|
|
|
{
|
|
|
|
if(t->etype != TSTRUCT)
|
|
|
|
fatal("fieldoffset: not struct %lT", t);
|
|
|
|
if(n->op != ONAME)
|
|
|
|
fatal("fieldoffset: not field name %N", n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
igen(Node *n, Node *a, Node *res)
|
|
|
|
{
|
|
|
|
regalloc(a, types[tptr], res);
|
|
|
|
agen(n, a);
|
|
|
|
a->op = OINDREG;
|
|
|
|
a->type = n->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bgen(Node *n, int true, Prog *to)
|
|
|
|
{
|
2008-06-08 17:11:14 -06:00
|
|
|
int et, a;
|
2008-06-04 15:37:38 -06:00
|
|
|
Node *nl, *nr, *r;
|
2008-06-08 18:21:46 -06:00
|
|
|
Node n1, n2, tmp;
|
2008-06-04 15:37:38 -06:00
|
|
|
Prog *p1, *p2;
|
|
|
|
|
2008-06-21 16:11:29 -06:00
|
|
|
if(debug['g']) {
|
|
|
|
dump("\nbgen", n);
|
|
|
|
}
|
2008-06-28 18:27:39 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(n == N)
|
|
|
|
n = booltrue;
|
|
|
|
|
2008-06-08 18:21:46 -06:00
|
|
|
nl = n->left;
|
|
|
|
nr = n->right;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(n->type == T) {
|
|
|
|
convlit(n, types[TBOOL]);
|
|
|
|
if(n->type == T)
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
et = n->type->etype;
|
|
|
|
if(et != TBOOL) {
|
|
|
|
yyerror("cgen: bad type %T for %O", n->type, n->op);
|
|
|
|
patch(gins(AEND, N, N), to);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
nl = N;
|
|
|
|
nr = N;
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
regalloc(&n1, n->type, N);
|
|
|
|
cgen(n, &n1);
|
|
|
|
nodconst(&n2, n->type, 0);
|
|
|
|
gins(optoas(OCMP, n->type), &n1, &n2);
|
|
|
|
a = AJNE;
|
|
|
|
if(!true)
|
|
|
|
a = AJEQ;
|
|
|
|
patch(gbranch(a, n->type), to);
|
|
|
|
regfree(&n1);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OLITERAL:
|
2008-08-08 18:13:31 -06:00
|
|
|
// need to ask if it is bool?
|
|
|
|
if(!true == !n->val.u.bval)
|
2008-06-04 15:37:38 -06:00
|
|
|
patch(gbranch(AJMP, T), to);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ONAME:
|
|
|
|
nodconst(&n1, n->type, 0);
|
|
|
|
gins(optoas(OCMP, n->type), n, &n1);
|
|
|
|
a = AJNE;
|
|
|
|
if(!true)
|
|
|
|
a = AJEQ;
|
|
|
|
patch(gbranch(a, n->type), to);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OANDAND:
|
|
|
|
if(!true)
|
|
|
|
goto caseor;
|
|
|
|
|
|
|
|
caseand:
|
|
|
|
p1 = gbranch(AJMP, T);
|
|
|
|
p2 = gbranch(AJMP, T);
|
|
|
|
patch(p1, pc);
|
|
|
|
bgen(n->left, !true, p2);
|
|
|
|
bgen(n->right, !true, p2);
|
|
|
|
p1 = gbranch(AJMP, T);
|
|
|
|
patch(p1, to);
|
|
|
|
patch(p2, pc);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OOROR:
|
|
|
|
if(!true)
|
|
|
|
goto caseand;
|
|
|
|
|
|
|
|
caseor:
|
|
|
|
bgen(n->left, true, to);
|
|
|
|
bgen(n->right, true, to);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OEQ:
|
|
|
|
case ONE:
|
|
|
|
case OLT:
|
|
|
|
case OGT:
|
|
|
|
case OLE:
|
|
|
|
case OGE:
|
|
|
|
nr = n->right;
|
|
|
|
if(nr == N || nr->type == T)
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ONOT: // unary
|
|
|
|
nl = n->left;
|
|
|
|
if(nl == N || nl->type == T)
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
|
|
|
|
case ONOT:
|
|
|
|
bgen(nl, !true, to);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OEQ:
|
|
|
|
case ONE:
|
|
|
|
case OLT:
|
|
|
|
case OGT:
|
|
|
|
case OLE:
|
|
|
|
case OGE:
|
|
|
|
a = n->op;
|
|
|
|
if(!true)
|
|
|
|
a = brcom(a);
|
|
|
|
|
|
|
|
// make simplest on right
|
|
|
|
if(nl->ullman < nr->ullman) {
|
|
|
|
a = brrev(a);
|
|
|
|
r = nl;
|
|
|
|
nl = nr;
|
|
|
|
nr = r;
|
|
|
|
}
|
2008-06-08 18:21:46 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
a = optoas(a, nr->type);
|
|
|
|
|
2008-06-08 18:21:46 -06:00
|
|
|
if(nr->ullman >= UINF) {
|
|
|
|
regalloc(&n1, nr->type, N);
|
|
|
|
cgen(nr, &n1);
|
|
|
|
|
|
|
|
tempname(&tmp, nr->type);
|
|
|
|
gmove(&n1, &tmp);
|
|
|
|
regfree(&n1);
|
|
|
|
|
|
|
|
regalloc(&n1, nl->type, N);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
|
|
|
|
regalloc(&n2, nr->type, &n2);
|
|
|
|
cgen(&tmp, &n2);
|
|
|
|
|
|
|
|
gins(optoas(OCMP, nr->type), &n1, &n2);
|
|
|
|
patch(gbranch(a, nr->type), to);
|
|
|
|
|
|
|
|
regfree(&n1);
|
|
|
|
regfree(&n2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
regalloc(&n1, nl->type, N);
|
|
|
|
cgen(nl, &n1);
|
|
|
|
|
2008-06-08 17:11:14 -06:00
|
|
|
regalloc(&n2, nr->type, N);
|
|
|
|
cgen(nr, &n2);
|
|
|
|
|
|
|
|
gins(optoas(OCMP, nr->type), &n1, &n2);
|
2008-06-04 15:37:38 -06:00
|
|
|
patch(gbranch(a, nr->type), to);
|
2008-06-08 17:11:14 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
regfree(&n1);
|
2008-06-08 17:11:14 -06:00
|
|
|
regfree(&n2);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
ret:
|
2008-06-28 18:27:39 -06:00
|
|
|
;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-08-21 21:49:04 -06:00
|
|
|
int32
|
|
|
|
stkof(Node *n)
|
|
|
|
{
|
|
|
|
switch(n->op) {
|
|
|
|
case OS2I:
|
|
|
|
return 2*widthptr;
|
|
|
|
case OI2I:
|
|
|
|
return 1*widthptr;
|
|
|
|
case OINDREG:
|
|
|
|
return n->xoffset;
|
|
|
|
}
|
|
|
|
// botch - probably failing to recognize address
|
|
|
|
// arithmetic on the above. eg INDEX and DOT
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2008-08-03 18:25:15 -06:00
|
|
|
sgen(Node *n, Node *ns, uint32 w)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Node nodl, nodr;
|
2008-08-21 21:49:04 -06:00
|
|
|
int32 c, q, odst, osrc;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-06-21 16:11:29 -06:00
|
|
|
if(debug['g']) {
|
|
|
|
dump("\nsgen-res", ns);
|
|
|
|
dump("sgen-r", n);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
if(w == 0)
|
|
|
|
return;
|
|
|
|
if(n->ullman >= UINF && ns->ullman >= UINF) {
|
|
|
|
fatal("sgen UINF");
|
|
|
|
}
|
|
|
|
|
2008-08-21 21:49:04 -06:00
|
|
|
// offset on the stack
|
|
|
|
odst = stkof(ns);
|
|
|
|
osrc = stkof(n);
|
|
|
|
if(osrc < 0)
|
|
|
|
odst = odst;
|
|
|
|
if(odst < 0)
|
|
|
|
osrc = odst;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
nodreg(&nodl, types[tptr], D_DI);
|
|
|
|
nodreg(&nodr, types[tptr], D_SI);
|
|
|
|
|
|
|
|
if(n->ullman >= ns->ullman) {
|
|
|
|
agen(n, &nodr);
|
|
|
|
agen(ns, &nodl);
|
|
|
|
} else {
|
|
|
|
agen(ns, &nodl);
|
|
|
|
agen(n, &nodr);
|
|
|
|
}
|
|
|
|
|
2008-08-21 21:49:04 -06:00
|
|
|
c = w % 8; // bytes
|
|
|
|
q = w / 8; // quads
|
|
|
|
|
|
|
|
// if we are copying forward on the stack and
|
|
|
|
// the src and dst overlap, then reverse direction
|
|
|
|
if(odst > osrc && odst-osrc < w) {
|
|
|
|
// reverse direction
|
|
|
|
gins(ASTD, N, N); // set direction flag
|
|
|
|
if(c > 0) {
|
|
|
|
gconreg(AADDQ, w-1, D_SI);
|
|
|
|
gconreg(AADDQ, w-1, D_DI);
|
|
|
|
|
|
|
|
gconreg(AMOVQ, c, D_CX);
|
|
|
|
gins(AREP, N, N); // repeat
|
|
|
|
gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-08-21 21:49:04 -06:00
|
|
|
if(q > 0) {
|
|
|
|
if(c > 0) {
|
|
|
|
gconreg(AADDQ, -7, D_SI);
|
|
|
|
gconreg(AADDQ, -7, D_DI);
|
|
|
|
} else {
|
|
|
|
gconreg(AADDQ, w-8, D_SI);
|
|
|
|
gconreg(AADDQ, w-8, D_DI);
|
|
|
|
}
|
|
|
|
gconreg(AMOVQ, q, D_CX);
|
|
|
|
gins(AREP, N, N); // repeat
|
|
|
|
gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
|
|
|
|
}
|
|
|
|
// for future optimization
|
|
|
|
// we leave with the flag clear
|
|
|
|
gins(ACLD, N, N);
|
|
|
|
} else {
|
|
|
|
// normal direction
|
|
|
|
gins(ACLD, N, N); // clear direction flag
|
|
|
|
if(q > 0) {
|
|
|
|
gconreg(AMOVQ, q, D_CX);
|
|
|
|
gins(AREP, N, N); // repeat
|
|
|
|
gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
|
|
|
|
}
|
2008-06-26 18:54:44 -06:00
|
|
|
|
2008-08-21 21:49:04 -06:00
|
|
|
if(c > 0) {
|
|
|
|
gconreg(AMOVQ, c, D_CX);
|
|
|
|
gins(AREP, N, N); // repeat
|
|
|
|
gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
|
|
|
|
}
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|