2008-03-28 14:41:41 -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 "go.h"
|
|
|
|
#include "gen.h"
|
|
|
|
|
|
|
|
Prog*
|
|
|
|
gbranch(int op, Node *t)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = prog(op);
|
|
|
|
p->addr.type = ABRANCH;
|
|
|
|
p->pt = conv2pt(t);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
Prog*
|
|
|
|
gopcode(int op, int pt, Node *n)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = prog(op);
|
|
|
|
p->pt = pt;
|
|
|
|
p->addr.node = n;
|
|
|
|
if(n == N) {
|
|
|
|
p->addr.type = ANONE;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
if(n->op == OTYPE) {
|
|
|
|
p->pt1 = conv2pt(n);
|
|
|
|
p->addr.type = ANONE;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
p->addr.type = ANODE;
|
|
|
|
// p->param = n->param;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
Prog*
|
|
|
|
gopcodet(int op, Node *t, Node *n)
|
|
|
|
{
|
|
|
|
return gopcode(op, conv2pt(t), n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gaddoffset(Node *n)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
if(n == N || n->op != ONAME || n->sym == S)
|
|
|
|
goto bad;
|
|
|
|
p = gopcode(PADDO, PTADDR, n);
|
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
fatal("gaddoffset: %N", n);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gconv(int t1, int t2)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = gopcode(PCONV, t1, N);
|
|
|
|
p->pt1 = t2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
conv2pt(Node *t)
|
|
|
|
{
|
|
|
|
if(t == N)
|
|
|
|
return PTxxx;
|
|
|
|
switch(t->etype) {
|
|
|
|
case TPTR:
|
|
|
|
t = t->type;
|
|
|
|
if(t == N)
|
|
|
|
return PTERROR;
|
|
|
|
switch(t->etype) {
|
|
|
|
case PTSTRING:
|
|
|
|
case PTCHAN:
|
|
|
|
case PTMAP:
|
|
|
|
return t->etype;
|
|
|
|
}
|
|
|
|
return TPTR;
|
|
|
|
}
|
|
|
|
return t->etype;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
patch(Prog *p, Prog *to)
|
|
|
|
{
|
|
|
|
if(p->addr.type != ABRANCH)
|
|
|
|
yyerror("patch: not a branch");
|
|
|
|
p->addr.branch = to;
|
|
|
|
}
|
|
|
|
|
|
|
|
Prog*
|
|
|
|
prog(int as)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = pc;
|
|
|
|
pc = mal(sizeof(*pc));
|
|
|
|
|
|
|
|
pc->op = PEND;
|
|
|
|
pc->addr.type = ANONE;
|
|
|
|
pc->loc = p->loc+1;
|
|
|
|
|
|
|
|
p->op = as;
|
|
|
|
p->lineno = dynlineno;
|
|
|
|
p->link = pc;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
proglist(void)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
print("--- prog list ---\n");
|
|
|
|
for(p=firstpc; p!=P; p=p->link)
|
|
|
|
print("%P\n", p);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* ptnames[] =
|
|
|
|
{
|
|
|
|
[PTxxx] = "",
|
|
|
|
[PTINT8] = "I8",
|
|
|
|
[PTUINT8] = "U8",
|
|
|
|
[PTINT16] = "I16",
|
|
|
|
[PTUINT16] = "U16",
|
|
|
|
[PTINT32] = "I32",
|
|
|
|
[PTUINT32] = "U32",
|
|
|
|
[PTINT64] = "I64",
|
|
|
|
[PTUINT64] = "U64",
|
|
|
|
[PTFLOAT32] = "F32",
|
|
|
|
[PTFLOAT64] = "F64",
|
|
|
|
[PTFLOAT80] = "F80",
|
|
|
|
[PTBOOL] = "B",
|
|
|
|
[PTPTR] = "P",
|
|
|
|
[PTADDR] = "A",
|
|
|
|
[PTINTER] = "I",
|
|
|
|
[PTNIL] = "N",
|
|
|
|
[PTSTRUCT] = "S",
|
|
|
|
[PTSTRING] = "Z",
|
|
|
|
[PTCHAN] = "C",
|
|
|
|
[PTMAP] = "M",
|
|
|
|
[PTERROR] = "?",
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
Xconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
int pt;
|
|
|
|
|
|
|
|
pt = va_arg(fp->args, int);
|
|
|
|
if(pt < 0 || pt >= nelem(ptnames) || ptnames[pt] == nil) {
|
|
|
|
snprint(buf, sizeof(buf), "PT(%d)", pt);
|
|
|
|
return fmtstrcpy(fp, buf);
|
|
|
|
}
|
|
|
|
return fmtstrcpy(fp, ptnames[pt]);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
Qconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
int pt;
|
|
|
|
|
|
|
|
pt = va_arg(fp->args, int);
|
|
|
|
if(pt == PTADDR)
|
|
|
|
pt = PTPTR;
|
|
|
|
snprint(buf, sizeof(buf), "_T_%X", pt);
|
|
|
|
return fmtstrcpy(fp, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
Rconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
int pt;
|
|
|
|
|
|
|
|
pt = va_arg(fp->args, int);
|
|
|
|
if(pt == PTADDR)
|
|
|
|
snprint(buf, sizeof(buf), "_R_%X", pt);
|
|
|
|
else
|
|
|
|
snprint(buf, sizeof(buf), "_U._R_%X", pt);
|
|
|
|
return fmtstrcpy(fp, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
s%[ ]*%%g
|
|
|
|
s%(\/\*.*)*%%g
|
|
|
|
s%,%\n%g
|
|
|
|
s%\n+%\n%g
|
|
|
|
s%(=0)*%%g
|
|
|
|
s%^P(.+)% [P\1] = "\1",%g
|
|
|
|
s%^ ........*\] =%&~%g
|
|
|
|
s% =~%=%g
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char*
|
|
|
|
pnames[] =
|
|
|
|
{
|
|
|
|
[PXXX] = "XXX",
|
|
|
|
[PERROR] = "ERROR",
|
|
|
|
[PPANIC] = "PANIC",
|
|
|
|
[PPRINT] = "PRINT",
|
|
|
|
[PGOTO] = "GOTO",
|
|
|
|
[PGOTOX] = "GOTOX",
|
|
|
|
[PCMP] = "CMP",
|
|
|
|
[PNEW] = "NEW",
|
|
|
|
[PLEN] = "LEN",
|
|
|
|
[PTEST] = "TEST",
|
|
|
|
[PCALL1] = "CALL1",
|
|
|
|
[PCALL2] = "CALL2",
|
|
|
|
[PCALLI2] = "CALLI2",
|
|
|
|
[PCALLM2] = "CALLM2",
|
|
|
|
[PCALLF2] = "CALLF2",
|
|
|
|
[PCALL3] = "CALL3",
|
|
|
|
[PRETURN] = "RETURN",
|
|
|
|
[PBEQ] = "BEQ",
|
|
|
|
[PBNE] = "BNE",
|
|
|
|
[PBLT] = "BLT",
|
|
|
|
[PBLE] = "BLE",
|
|
|
|
[PBGE] = "BGE",
|
|
|
|
[PBGT] = "BGT",
|
|
|
|
[PBTRUE] = "BTRUE",
|
|
|
|
[PBFALSE] = "BFALSE",
|
|
|
|
[PLOAD] = "LOAD",
|
|
|
|
[PLOADI] = "LOADI",
|
|
|
|
[PSTORE] = "STORE",
|
|
|
|
[PSTOREI] = "STOREI",
|
|
|
|
[PSTOREZ] = "STOREZ",
|
2008-03-31 20:19:37 -06:00
|
|
|
[PSTOREZI] = "STOREZI",
|
2008-03-28 14:41:41 -06:00
|
|
|
[PCONV] = "CONV",
|
|
|
|
[PADDR] = "ADDR",
|
|
|
|
[PADDO] = "ADDO",
|
|
|
|
[PINDEX] = "INDEX",
|
|
|
|
[PINDEXZ] = "INDEXZ",
|
|
|
|
[PCAT] = "CAT",
|
|
|
|
[PADD] = "ADD",
|
|
|
|
[PSUB] = "SUB",
|
|
|
|
[PSLICE] = "SLICE",
|
|
|
|
[PMUL] = "MUL",
|
|
|
|
[PDIV] = "DIV",
|
|
|
|
[PLSH] = "LSH",
|
|
|
|
[PRSH] = "RSH",
|
|
|
|
[PMOD] = "MOD",
|
|
|
|
[PMINUS] = "MINUS",
|
|
|
|
[PCOM] = "COM",
|
|
|
|
[PAND] = "AND",
|
|
|
|
[POR] = "OR",
|
|
|
|
[PXOR] = "XOR",
|
|
|
|
[PEND] = "END",
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
Aconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[100], buf1[100];
|
|
|
|
Prog *p;
|
|
|
|
int o;
|
|
|
|
|
|
|
|
p = va_arg(fp->args, Prog*);
|
|
|
|
if(p == P) {
|
|
|
|
snprint(buf, sizeof(buf), "<P>");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
o = p->op;
|
|
|
|
if(o < 0 || o >= nelem(pnames) || pnames[o] == nil)
|
|
|
|
snprint(buf, sizeof(buf), "(A%d)", o);
|
|
|
|
else
|
|
|
|
snprint(buf, sizeof(buf), "%s", pnames[o]);
|
|
|
|
|
|
|
|
o = p->pt;
|
|
|
|
if(o != PTxxx) {
|
|
|
|
snprint(buf1, sizeof(buf1), "-%X", o);
|
|
|
|
strncat(buf, buf1, sizeof(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
o = p->pt1;
|
|
|
|
if(o != PTxxx) {
|
|
|
|
snprint(buf1, sizeof(buf1), "-%X", o);
|
|
|
|
strncat(buf, buf1, sizeof(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
return fmtstrcpy(fp, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
Pconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[500], buf1[500];
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = va_arg(fp->args, Prog*);
|
|
|
|
snprint(buf1, sizeof(buf1), "%4ld %4ld %-9A", p->loc, p->lineno, p);
|
|
|
|
|
|
|
|
switch(p->addr.type) {
|
|
|
|
default:
|
|
|
|
snprint(buf, sizeof(buf), "?%d", p->addr.type);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ANONE:
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
case ANODE:
|
|
|
|
snprint(buf, sizeof(buf), "%N", p->addr.node);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ABRANCH:
|
|
|
|
if(p->addr.branch == P) {
|
|
|
|
snprint(buf, sizeof(buf), "<nil>");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
snprint(buf, sizeof(buf), "%ld", p->addr.branch->loc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncat(buf1, " ", sizeof(buf1));
|
|
|
|
strncat(buf1, buf, sizeof(buf1));
|
|
|
|
|
|
|
|
out:
|
|
|
|
return fmtstrcpy(fp, buf1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
typedefs[] =
|
|
|
|
{
|
|
|
|
"int", "int32",
|
|
|
|
"uint", "uint32",
|
|
|
|
"rune", "uint32",
|
|
|
|
"short", "int16",
|
|
|
|
"ushort", "uint16",
|
|
|
|
"long", "int32",
|
|
|
|
"ulong", "uint32",
|
|
|
|
"vlong", "int64",
|
|
|
|
"uvlong", "uint64",
|
|
|
|
"float", "float32",
|
|
|
|
"double", "float64",
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
belexinit(int lextype)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Sym *s0, *s1;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(typedefs); i+=2) {
|
|
|
|
s1 = lookup(typedefs[i+1]);
|
|
|
|
if(s1->lexical != lextype)
|
|
|
|
yyerror("need %s to define %s",
|
|
|
|
typedefs[i+1], typedefs[i+0]);
|
|
|
|
s0 = lookup(typedefs[i+0]);
|
|
|
|
s0->lexical = s1->lexical;
|
|
|
|
s0->otype = s1->otype;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmtinstall('A', Aconv); // asm opcodes
|
|
|
|
fmtinstall('P', Pconv); // asm instruction
|
|
|
|
fmtinstall('R', Rconv); // interpreted register
|
|
|
|
fmtinstall('Q', Qconv); // interpreted etype
|
|
|
|
fmtinstall('X', Xconv); // interpreted etype
|
|
|
|
|
|
|
|
fmtinstall('D', Dconv); // addressed operand
|
|
|
|
fmtinstall('C', Cconv); // C type
|
|
|
|
}
|
|
|
|
|
|
|
|
vlong
|
|
|
|
convvtox(vlong v, int et)
|
|
|
|
{
|
|
|
|
/* botch - do truncation conversion when energetic */
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return !(op)
|
|
|
|
* eg == <=> !=
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
brcom(int a)
|
|
|
|
{
|
|
|
|
switch(a) {
|
|
|
|
case PBEQ: return PBNE;
|
|
|
|
case PBNE: return PBEQ;
|
|
|
|
case PBLT: return PBGE;
|
|
|
|
case PBGT: return PBLE;
|
|
|
|
case PBLE: return PBGT;
|
|
|
|
case PBGE: return PBLT;
|
|
|
|
case PBTRUE: return PBFALSE;
|
|
|
|
case PBFALSE: return PBTRUE;
|
|
|
|
}
|
|
|
|
fatal("brcom: no com for %A\n", a);
|
|
|
|
return PERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return reverse(op)
|
|
|
|
* eg a op b <=> b r(op) a
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
brrev(int a)
|
|
|
|
{
|
|
|
|
switch(a) {
|
|
|
|
case PBEQ: return PBEQ;
|
|
|
|
case PBNE: return PBNE;
|
|
|
|
case PBLT: return PBGT;
|
|
|
|
case PBGT: return PBLT;
|
|
|
|
case PBLE: return PBGE;
|
|
|
|
case PBGE: return PBLE;
|
|
|
|
}
|
|
|
|
fatal("brcom: no rev for %A\n", a);
|
|
|
|
return PERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* codegen the address of the ith
|
|
|
|
* element in the jth argument.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fnparam(Node *t, int j, int i)
|
|
|
|
{
|
|
|
|
Node *a, *f;
|
|
|
|
|
|
|
|
switch(j) {
|
|
|
|
default:
|
|
|
|
fatal("fnparam: bad j");
|
|
|
|
case 0:
|
|
|
|
a = getthisx(t);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
a = getoutargx(t);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
a = getinargx(t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = a->type;
|
|
|
|
while(i > 0) {
|
|
|
|
f = f->down;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
if(f->etype != TFIELD)
|
|
|
|
fatal("fnparam: not field");
|
|
|
|
|
|
|
|
gopcode(PLOAD, PTADDR, a->nname);
|
|
|
|
gopcode(PADDO, PTADDR, f->nname);
|
|
|
|
}
|
|
|
|
|
|
|
|
Sig*
|
|
|
|
lsort(Sig *l, int(*f)(Sig*, Sig*))
|
|
|
|
{
|
|
|
|
Sig *l1, *l2, *le;
|
|
|
|
|
|
|
|
if(l == 0 || l->link == 0)
|
|
|
|
return l;
|
|
|
|
|
|
|
|
l1 = l;
|
|
|
|
l2 = l;
|
|
|
|
for(;;) {
|
|
|
|
l2 = l2->link;
|
|
|
|
if(l2 == 0)
|
|
|
|
break;
|
|
|
|
l2 = l2->link;
|
|
|
|
if(l2 == 0)
|
|
|
|
break;
|
|
|
|
l1 = l1->link;
|
|
|
|
}
|
|
|
|
|
|
|
|
l2 = l1->link;
|
|
|
|
l1->link = 0;
|
|
|
|
l1 = lsort(l, f);
|
|
|
|
l2 = lsort(l2, f);
|
|
|
|
|
|
|
|
/* set up lead element */
|
|
|
|
if((*f)(l1, l2) < 0) {
|
|
|
|
l = l1;
|
|
|
|
l1 = l1->link;
|
|
|
|
} else {
|
|
|
|
l = l2;
|
|
|
|
l2 = l2->link;
|
|
|
|
}
|
|
|
|
le = l;
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
if(l1 == 0) {
|
|
|
|
while(l2) {
|
|
|
|
le->link = l2;
|
|
|
|
le = l2;
|
|
|
|
l2 = l2->link;
|
|
|
|
}
|
|
|
|
le->link = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(l2 == 0) {
|
|
|
|
while(l1) {
|
|
|
|
le->link = l1;
|
|
|
|
le = l1;
|
|
|
|
l1 = l1->link;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if((*f)(l1, l2) < 0) {
|
|
|
|
le->link = l1;
|
|
|
|
le = l1;
|
|
|
|
l1 = l1->link;
|
|
|
|
} else {
|
|
|
|
le->link = l2;
|
|
|
|
le = l2;
|
|
|
|
l2 = l2->link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
le->link = 0;
|
|
|
|
return l;
|
|
|
|
}
|