blob: 2ac8ea8cf0b700f25a31c48b14fd0ccfad019e0f [file] [log] [blame]
// 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",
[PSTOREZI] = "STOREZI",
[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;
}