blob: f44a0f08323f06a7ad4c08b17fdc00ed2018edd5 [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"
static Prog* firstp;
static Prog* lastp;
static int typeexpand;
void
dumpobj(void)
{
Plist *pl;
Prog *p;
long lno;
Bprint(bout, "\n\n/*\n");
Bprint(bout, " * automatic code generated from\n");
Bprint(bout, " * %s in package \"%s\"\n", curio.infile, package);
dumpexport();
Bprint(bout, " */\n", curio.infile, package);
Bprint(bout, "#include \"gort.h\"\n");
// put out external variables and types
doframe(externdcl, "external");
dumpmethods();
// put out signatures
dumpsignatures();
// put out functions
for(pl=plist; pl!=nil; pl=pl->link) {
/* print out the function header */
dumpfunct(pl);
/* clear the marks */
for(p=pl->firstpc; p!=nil; p=p->link)
p->mark = 0;
/* relinearize the object code */
firstp = mal(sizeof(*firstp));
lastp = firstp;
follow(pl->firstpc);
lastp->link = P;
pl->firstpc = firstp->link;
/* clear the marks - relabel the locations */
for(p=pl->firstpc; p!=nil; p=p->link)
p->mark = 0;
/* mark the labels */
for(p=pl->firstpc; p!=nil; p=p->link) {
if(p->addr.branch != P)
p->addr.branch->mark = 1;
}
/* interpret the instructions */
lno = dynlineno;
for(p=pl->firstpc; p!=nil; p=p->link) {
dynlineno = p->lineno;
dynloc = p->loc;
obj(p);
}
dynlineno = lno;
Bprint(bout, "}\n");
}
}
void
obj1(Prog *p)
{
Node *n;
static long uloc, olino;
Bprint(bout, "\n\t// %P\n", p);
if(p->mark)
Bprint(bout, "_L%ld:\n", p->loc);
uloc++;
if(p->lineno != 0)
olino = p->lineno;
Bprint(bout, "\tgotrace(%ld, %ld);\n", uloc, olino);
switch(p->op) {
default:
warn("obj: unknown opcode %A", p);
Bprint(bout, "\tprintf(\"unknown line %ld-%ld: %A\\n\");\n",
dynloc, dynlineno, p);
case PPANIC:
Bprint(bout, "\tprintf(\"panic line %ld\\n\");\n", dynlineno);
Bprint(bout, "\tgoexit(1);\n");
break;
case PPRINT:
Bprint(bout, "\tprint%s(%R);\n", getfmt(p->pt), p->pt);
break;
case PGOTO:
Bprint(bout, "\tgoto %D;\n", p);
break;
case PGOTOX:
yyerror("label not declared: %S", p->addr.node->left->sym);
break;
case PCMP:
if(p->pt == PTSTRING)
goto pcmpz;
switch(p->link->op) {
case PBEQ:
Bprint(bout, "\tif(%R == %D) {\n", p->pt, p);
break;
case PBNE:
Bprint(bout, "\tif(%R != %D) {\n", p->pt, p);
break;
case PBLT:
Bprint(bout, "\tif(%R < %D) {\n", p->pt, p);
break;
case PBLE:
Bprint(bout, "\tif(%R <= %D) {\n", p->pt, p);
break;
case PBGE:
Bprint(bout, "\tif(%R >= %D) {\n", p->pt, p);
break;
case PBGT:
Bprint(bout, "\tif(%R > %D) {\n", p->pt, p);
break;
}
break;
pcmpz:
Bprint(bout, "\tif(cmpZ(%D) ", p);
switch(p->link->op) {
case PBEQ:
Bprint(bout, "== 0) {\n");
break;
case PBNE:
Bprint(bout, "!= 0) {\n");
break;
case PBLT:
Bprint(bout, "< 0) {\n");
break;
case PBLE:
Bprint(bout, "<= 0) {\n");
break;
case PBGE:
Bprint(bout, ">= 0) {\n");
break;
case PBGT:
Bprint(bout, "> 0) {\n");
break;
}
break;
case PTEST:
switch(p->link->op) {
case PBTRUE:
Bprint(bout, "\tif(%D != 0) {\n", p);
break;
case PBFALSE:
Bprint(bout, "\tif(%D == 0) {\n", p);
break;
}
break;
case PBEQ:
case PBNE:
case PBLT:
case PBLE:
case PBGE:
case PBGT:
case PBTRUE:
case PBFALSE:
Bprint(bout, "\t\tgoto %D; }\n", p);
break;
case PLEN:
Bprint(bout, "\t%R = %D->len;\n", PTINT32, p);
break;
case PNEW:
if(p->addr.type != ANODE)
goto bad;
n = p->addr.node;
n = n->type;
n = n->type;
if(n == N || n->op != OTYPE)
goto bad;
Bprint(bout, "\t%R = gomal(sizeof(%C%lC));\n", p->pt, n, n);
break;
case PLOAD:
if(p->pt == PTPTR || p->pt == PTADDR) {
Bprint(bout, "\t%R = (%Q)%D;\n", p->pt, PTPTR, p);
break;
}
Bprint(bout, "\t%R = %D;\n", p->pt, p);
break;
case PLOADI: // R/D = *(A)
Bprint(bout, "\t%D = *(%Q*)%R;\n", p, p->pt, PTADDR);
break;
case PSTORE:
if(p->pt == PTPTR || p->pt == PTADDR) {
if(p->addr.type != ANODE)
goto bad;
n = p->addr.node;
if(n == N || n->type == N)
goto bad;
Bprint(bout, "\t%D = (%C)%R;\n", p, n->type, p->pt);
break;
}
Bprint(bout, "\t%D = %R;\n", p, p->pt);
break;
case PSTOREI: // *(A) = R/D
Bprint(bout, "\t*(%Q*)%R = %D;\n", p->pt, PTADDR, p);
break;
case PSTOREZ:
switch(p->pt) {
default:
Bprint(bout, "\t%D = 0;\n", p);
break;
case PTARRAY:
case PTSTRUCT:
Bprint(bout, "\tmemset(&%D, 0, sizeof(%D));\n", p, p);
break;
case PTINTER:
Bprint(bout, "\t%D.s = 0; %D.m = 0;\n", p, p);
break;
case PTSTRING:
Bprint(bout, "\t%D = &nilstring;\n", p);
break;
}
break;
case PSTOREZI:
switch(p->pt) {
default:
Bprint(bout, "\t*(%Q*)%R = 0;\n", p->pt, PTADDR);
break;
case PTARRAY:
case PTSTRUCT:
Bprint(bout, "\tmemset((%Q*)%R, 0, sizeof((%Q*)%R));\n", p->pt, PTADDR, p->pt, PTADDR);
break;
case PTINTER:
Bprint(bout, "\t((%Q*)%R)->s = 0; ((%Q*)%R)->m = 0;\n", p->pt, PTADDR, p->pt, PTADDR);
break;
case PTSTRING:
Bprint(bout, "\t(%Q*)%R = &nilstring;\n", p->pt, PTADDR);
break;
}
break;
case PCONV:
doconv(p);
break;
case PADDR:
Bprint(bout, "\t%R = (%Q)&%D;\n", p->pt, p->pt, p);
break;
case PADDO:
if(p->addr.type != ANODE)
goto bad;
n = p->addr.node;
if(n == N || n->op != ONAME || n->sym == S)
goto bad;
if(n->uberstruct == N || n->uberstruct->etype != TSTRUCT)
goto bad;
Bprint(bout, "\t%R = (%Q)((char*)%R + offsetof(_T_%ld, %s));\n",
p->pt, PTADDR, p->pt,
// n->uberstruct->nname->sym->package,
n->uberstruct->vargen, n->sym->name);
break;
case PINDEXZ:
Bprint(bout, "\t%R = %D->string[%R];\n",
PTUINT8, p, p->pt);
break;
case PINDEX:
if(p->addr.type != ANODE)
goto bad;
n = p->addr.node;
Bprint(bout, "\t%R += (%R)*sizeof(%C);\n",
PTADDR, p->pt, n->type);
break;
case PSLICE:
if(p->addr.type != ANODE)
goto bad;
n = p->addr.node;
Bprint(bout, "\tsliceZ(%R, %D);\n", p->pt, p);
break;
case PCAT:
Bprint(bout, "\tcatZ(%D);\n", p);
break;
case PADD:
Bprint(bout, "\t%R += %D;\n", p->pt, p);
break;
case PSUB:
Bprint(bout, "\t%R -= %D;\n", p->pt, p);
break;
case PMUL:
Bprint(bout, "\t%R *= %D;\n", p->pt, p);
break;
case PDIV:
Bprint(bout, "\t%R /= %D;\n", p->pt, p);
break;
case PLSH:
Bprint(bout, "\t%R <<= %D;\n", p->pt, p);
break;
case PRSH:
Bprint(bout, "\t%R >>= %D;\n", p->pt, p);
break;
case PMOD:
Bprint(bout, "\t%R %%= %D;\n", p->pt, p);
break;
case PAND:
Bprint(bout, "\t%R &= %D;\n", p->pt, p);
break;
case POR:
Bprint(bout, "\t%R |= %D;\n", p->pt, p);
break;
case PXOR:
Bprint(bout, "\t%R ^= %D;\n", p->pt, p);
break;
case PMINUS:
Bprint(bout, "\t%R = -%R;\n", p->pt, p->pt);
break;
case PCOM:
Bprint(bout, "\t%R = ~%R;\n", p->pt, p->pt);
break;
case PRETURN:
Bprint(bout, "\treturn;\n");
break;
case PCALL1: // process the arguments
docall1(p);
break;
case PCALL2: // call the normal function
docall2(p);
break;
case PCALLI2: // call the indirect function
docalli2(p);
break;
case PCALLM2: // call the method function
docallm2(p);
break;
case PCALLF2: // call the interface method function
docallf2(p);
break;
case PCALL3: // process the return
docall3(p);
break;
case PEND:
Bprint(bout, "\treturn;\n");
break;
}
return;
bad:
print("bad code generation on\n\t// %P\n", p);
}
void
follow(Prog *p)
{
Prog *q;
int i, op;
loop:
if(p == P)
return;
if(p->op == PGOTO) {
q = p->addr.branch;
if(q != P) {
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
}
if(p->mark) {
/* copy up to 4 instructions to avoid branch */
for(i=0, q=p; i<4; i++, q=q->link) {
if(q == P)
break;
if(q == lastp)
break;
if(q->op == PGOTO)
break;
if(q->addr.branch == P)
continue;
if(q->addr.branch->mark)
continue;
if(q->op == PCALL1)
continue;
// we found an invertable now copy
// for(;;) {
// q = copyp(p);
// p = p->link;
// q->mark = 1;
// lastp->link = q;
// lastp = q;
// if(q->op != a || q->addr.branch == P || q->addr.branch->mark)
// continue;
//
// q->op = relinv(q->op);
// p = q->addr.branch;
// q->addr.branch = q->link;
// q->link = p;
// follow(q->link);
// p = q->link;
// if(p->mark)
// return;
// goto loop;
// }
}
q = mal(sizeof(*q));
q->op = PGOTO;
q->lineno = p->lineno;
q->addr.type = ABRANCH;
q->addr.branch = gotochain(p);
p = q;
}
p->mark = 1;
p->loc = lastp->loc+1;
lastp->link = p;
lastp = p;
op = p->op;
if(op == PGOTO || op == PRETURN || op == OEND)
return;
if(op == PCALL1 || p->addr.branch == P) {
p = p->link;
goto loop;
}
q = gotochain(p->link);
if(q != P && q->mark) {
p->op = brcom(op);
p->link = p->addr.branch;
p->addr.branch = q;
}
follow(p->link);
q = gotochain(p->addr.branch);
p->addr.branch = q;
if(q != P && q->mark)
return;
p = q;
goto loop;
}
void
obj(Prog *p)
{
Node *n;
String *s;
long i;
if(p->addr.type != ANODE)
goto out;
n = p->addr.node;
if(n == N || n->op != OLITERAL)
goto out;
if(p->pt != PTSTRING)
goto out;
s = n->val.sval;
Bprint(bout, "\t{ static struct {_T_U32 l;_T_U8 s[%d]; } slit = { %d", s->len, s->len);
for(i=0; i<s->len; i++) {
if(i%16 == 0)
Bprint(bout, "\n\t\t");
Bprint(bout, ",%d", s->s[i]);
}
Bprint(bout, " };\n");
obj1(p);
Bprint(bout, "\t}\n");
return;
out:
obj1(p);
}
Prog*
gotochain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->op != PGOTO)
return p;
p = p->addr.branch;
}
return P;
}
/*
* print a C type
*/
int
Cconv(Fmt *fp)
{
char buf[1000], buf1[100];
Node *t, *f, *n;
Iter it;
int pt;
long v1, v2;
t = va_arg(fp->args, Node*);
if(t == N)
return fmtstrcpy(fp, "<C>");
t->recur++;
if(t->op != OTYPE) {
snprint(buf, sizeof(buf), "C-%O", t->op);
goto out;
}
if(t->recur > 5) {
snprint(buf, sizeof(buf), "C-%E ...", t->etype);
goto out;
}
// post-name format
if(fp->flags & FmtLong) {
strcpy(buf, "");
switch(t->etype) {
default:
break;
case TARRAY:
snprint(buf, sizeof(buf), "[%ld]", t->bound);
break;
case TFUNC:
if(t->thistuple > 0) {
f = *getthis(t);
v1 = 9999;
v2 = 9999;
if(f != N) {
v1 = f->vargen;
if(f->nname != N)
v2 = f->nname->vargen;
}
snprint(buf1, sizeof(buf1), "(_T_%ld* _V_%ld",
v1, v2);
strncat(buf, buf1, sizeof(buf));
} else
strncat(buf, "(void* _dummythis", sizeof(buf));
if(t->outtuple > 0) {
f = *getoutarg(t);
v1 = 9999;
v2 = 9999;
if(f != N) {
v1 = f->vargen;
if(f->nname != N)
v2 = f->nname->vargen;
}
snprint(buf1, sizeof(buf1), ", _T_%ld* _V_%ld",
v1, v2);
strncat(buf, buf1, sizeof(buf));
} else
strncat(buf, ", void* _dummyout", sizeof(buf));
if(t->intuple > 0) {
f = *getinarg(t);
v1 = 9999;
v2 = 9999;
if(f != N) {
v1 = f->vargen;
if(f->nname != N)
v2 = f->nname->vargen;
}
snprint(buf1, sizeof(buf1), ", _T_%ld* _V_%ld)",
v1, v2);
strncat(buf, buf1, sizeof(buf));
} else
strncat(buf, ", void* _dummyin)", sizeof(buf));
break;
}
goto out;
}
if(t->vargen != 0 && !typeexpand) {
if(t->etype == TFUNC) {
strcpy(buf, "void");
goto out;
}
snprint(buf, sizeof(buf), "_T_%ld", t->vargen);
goto out;
}
switch(t->etype) {
default:
pt = conv2pt(t);
snprint(buf, sizeof(buf), "%Q", pt);
break;
case TSTRUCT:
if(fp->flags & FmtShort) {
strcpy(buf, "{");
} else {
if(t->vargen != 0) {
snprint(buf, sizeof(buf), "_T_%ld", t->vargen);
goto out;
}
strcpy(buf, "struct{");
}
f = structfirst(&it, &t);
while(f != N) {
n = f->type;
if(n->etype == TFUNC)
goto next;
if(f->sym == S)
snprint(buf1, sizeof(buf1), "%C;", n);
else
snprint(buf1, sizeof(buf1), "%C %s;", n, f->sym->name);
strncat(buf, buf1, sizeof(buf));
next:
f = structnext(&it);
}
strncat(buf, "}", sizeof(buf));
break;
case TPTR:
if(isptrto(t, TSTRING)) {
snprint(buf, sizeof(buf), "%C", t->type);
break;
}
snprint(buf, sizeof(buf), "%C*", t->type);
break;
case TARRAY:
snprint(buf, sizeof(buf), "%C", t->type);
break;
case TFUNC:
strcpy(buf, "void");
break;
}
out:
t->recur--;
return fmtstrcpy(fp, buf);
}
/*
* print Prog operand
*/
int
Dconv(Fmt *fp)
{
char buf[500];
Prog *p;
Node *n;
if(fp->flags & FmtLong) {
p = nil;
n = va_arg(fp->args, Node*);
goto prnode;
}
p = va_arg(fp->args, Prog*);
switch(p->addr.type) {
default:
snprint(buf, sizeof(buf), "addr.type=%d", p->addr.type);
break;
case ANONE:
snprint(buf, sizeof(buf), "%R", p->pt);
break;
case ANODE:
n = p->addr.node;
goto prnode;
case ABRANCH:
p = p->addr.branch;
if(p == P) {
snprint(buf, sizeof(buf), "addr.branch=nil");
break;
}
snprint(buf, sizeof(buf), "_L%ld", p->loc);
break;
}
goto out;
prnode:
if(n == N) {
snprint(buf, sizeof(buf), "addr.node=nil");
goto out;
}
switch(n->op) {
default:
snprint(buf, sizeof(buf), "%N", p->addr.node);
break;
case ONAME:
if(n->vargen != 0) {
snprint(buf, sizeof(buf), "_V_%ld", n->vargen);
break;
}
snprint(buf, sizeof(buf), "%s_%s", n->sym->opackage, n->sym->name);
break;
case OLITERAL:
switch(p->pt) {
badlit:
default:
snprint(buf, sizeof(buf), "BADLIT-%d pt-%d", p->pt, n->val.ctype);
break;
case PTINT8:
case PTINT16:
case PTINT32:
case PTUINT8:
case PTUINT16:
case PTUINT32:
switch(n->val.ctype) {
default:
goto badlit;
case CTINT:
case CTSINT:
case CTUINT:
if(n->val.vval < 0)
snprint(buf, sizeof(buf), "-0x%llux", -n->val.vval);
else
snprint(buf, sizeof(buf), "0x%llux", n->val.vval);
break;
}
break;
case PTINT64:
case PTUINT64:
switch(n->val.ctype) {
default:
goto badlit;
case CTINT:
case CTSINT:
case CTUINT:
snprint(buf, sizeof(buf), "0x%lluxll", n->val.vval);
break;
}
break;
case PTFLOAT32:
case PTFLOAT64:
case PTFLOAT80:
switch(n->val.ctype) {
default:
goto badlit;
case CTFLT:
snprint(buf, sizeof(buf), "%.17e", n->val.dval);
break;
}
break;
case PTBOOL:
switch(n->val.ctype) {
default:
goto badlit;
case CTBOOL:
snprint(buf, sizeof(buf), "%lld", n->val.vval);
break;
}
break;
case PTPTR:
switch(n->val.ctype) {
default:
goto badlit;
case CTSTR:
snprint(buf, sizeof(buf), "\"%Z\"", n->val.sval);
break;
case CTNIL:
snprint(buf, sizeof(buf), "(void*)0", n->val.sval);
break;
}
break;
case PTSTRING:
snprint(buf, sizeof(buf), "(_T_Z)&slit");
break;
}
break;
}
out:
return fmtstrcpy(fp, buf);
}
char*
thistypenam(Node *t)
{
char *typ;
Node *n;
typ = "???";
if(t == N)
return typ;
n = getthisx(t); // struct{field a *T}
if(n != N)
n = n->type; // field a *T
if(n != N)
n = n->type; // *T
if(n != N)
n = n->type; // T
if(n != N && n->sym != S)
typ = n->sym->name;
return typ;
}
void
dumpfunct(Plist *pl)
{
Node *t;
char *pkg, *typ, *fun;
t = pl->name->type;
pkg = pl->name->sym->opackage;
fun = pl->name->sym->name;
if(t->thistuple > 0) {
typ = thistypenam(t); // struct{field a *T}
Bprint(bout, "\n%C %s_%s_%s%lC", t, pkg, typ, fun, t);
} else {
Bprint(bout, "\n%C %s_%s%lC", t, pkg, fun, t);
}
Bprint(bout, "\n{\n");
doframe(pl->locals, "local");
}
void
dumpmethods()
{
Node *t;
char *pkg, *typ, *fun;
Plist *pl;
for(pl=plist; pl!=nil; pl=pl->link) {
t = pl->name->type;
if(t->thistuple > 0) {
pkg = pl->name->sym->opackage;
fun = pl->name->sym->name;
typ = thistypenam(t);
Bprint(bout, "\n%C %s_%s_%s%lC;\n", t, pkg, typ, fun, t);
}
}
}
static int
sigcmp(Sig *a, Sig *b)
{
return strcmp(a->fun, b->fun);
}
void
dumpsignatures(void)
{
Dcl *d;
Node *t, *f;
Sym *s1, *s;
char *pkg, *typ, *fun;
int et, o, any;
Sig *a, *b;
/* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
any = 1;
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dnode;
et = t->etype;
if(et != TSTRUCT && et != TINTER)
continue;
s = d->dsym;
if(s == S)
continue;
typ = s->name;
if(typ[0] == '_')
continue;
pkg = s->opackage;
if(pkg != package) {
if(et == TINTER)
Bprint(bout, "extern _Sigi sig_%s_%s[];\n", pkg, typ);
else
Bprint(bout, "extern _Sigs sig_%s_%s[];\n", pkg, typ);
continue;
}
a = nil;
o = 0;
for(f=t->type; f!=N; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
fun = s1->name;
if(fun[0] == '_')
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->fun = fun;
a->hash = PRIME8*stringhash(fun) + PRIME9*typehash(f->type, 0);
a->offset = o;
o++;
}
if(1 || et == TINTER || a != nil) {
if(any) {
Bprint(bout, "\n");
any = 0;
}
a = lsort(a, sigcmp);
if(et == TINTER) {
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
Bprint(bout, "_Sigi sig_%s_%s[] =\n", pkg, typ);
Bprint(bout, "{\n");
Bprint(bout, "\t{ \"\", 0, %d}, // count\n", o);
for(b=a; b!=nil; b=b->link) {
Bprint(bout, "\t{ \"%s\", 0x%.8lux, %d},\n",
b->fun, b->hash, b->offset);
}
} else {
Bprint(bout, "_Sigs sig_%s_%s[] =\n", pkg, typ);
Bprint(bout, "{\n");
for(b=a; b!=nil; b=b->link) {
Bprint(bout, "\t{ \"%s\", 0x%.8lux, &%s_%s_%s },\n",
b->fun, b->hash, pkg, typ, b->fun);
}
}
Bprint(bout, "\t{ 0,0,0 }\n");
Bprint(bout, "};\n");
}
}
}
int
istypstr(Node *t)
{
if(t == N)
fatal("istypstr: t nil");
if(t->etype == TSTRUCT)
return 1;
return 0;
}
static int XXX = 0;
static int YYY = 0;
int
alldefined(Node *t, int first)
{
Node *t1;
if(t == N)
return 1;
if(t->op != OTYPE)
fatal("alldefined: not OTYPE: %O", t->op);
if(t->recur)
return 1;
if(!first && t->sym!=S && t->sym->undef != 0)
return 1;
t->recur++;
switch(t->etype) {
default:
// should be basic types
return 1;
case TPTR:
case TARRAY:
case TFIELD:
if(!alldefined(t->type, 0))
goto no;
break;
case TSTRUCT:
case TFUNC:
for(t1=t->type; t1!=N; t1=t1->down) {
if(!alldefined(t1, 0))
goto no;
}
break;
}
t->recur--;
return 1;
no:
t->recur--;
return 0;
}
void
doframe(Dcl *r, char *msg)
{
Sym *s;
Dcl *d;
Node *n, *t;
int flag, pass, any;
char *tab, *nam, *pkg, *typ;
tab = "\t";
if(msg[0] != 'l')
tab = "";
// put out types
flag = 1;
typeexpand = 1;
for(pass=0;; pass++) {
if(XXX)print("\npass %d\n\n", pass);
any = 0;
for(d=r; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
if(flag) {
Bprint(bout, "\n%s// %s types\n", tab, msg);
flag = 0;
}
n = d->dnode;
nam = "???";
s = d->dsym;
if(s != S)
nam = s->name;
if(pass == 0) {
if(s != S)
s->undef = 0;
if(istypstr(n)) {
Bprint(bout, "%stypedef struct _T_%ld _T_%ld; // %s\n",
tab, n->vargen, n->vargen, nam);
if(XXX)print("\t1 pass-%d ", pass);
if(XXX)print("typedef struct _T_%ld _T_%ld; // %s\n", n->vargen, n->vargen, nam);
}
any = 1;
continue;
}
if(XXX)if(s != S) print("looking at %s undef=%d: %lT\n", s->name, s->undef, n);
if(s != S && s->undef == 0 && alldefined(n, 1)) {
if(XXX)print("\t2 pass-%d ", pass);
if(istypstr(n)) {
Bprint(bout, "%sstruct _T_%ld %hC; // %s\n",
tab, n->vargen, n, nam);
if(XXX)print("struct _T_%ld %hC; // %s\n", n->vargen, n, nam);
} else {
if(n->etype != TFUNC)
Bprint(bout, "%stypedef %C _T_%ld%lC; // %s\n",
tab, n, n->vargen, n, nam);
if(XXX)print("typedef %C _T_%ld%lC; // %s\n", n, n->vargen, n, nam);
}
s->undef = 1;
any = 1;
}
}
if(any)
continue;
for(d=r; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
n = d->dnode;
s = d->dsym;
if(s != S) {
if(s->undef == 0)
fatal("doframe: couldnt resolve type %s %lT\n",
s->name, n);
continue;
}
if(XXX)print("\t-3 pass-%d ", pass);
if(istypstr(n)) {
Bprint(bout, "%sstruct _T_%ld %hC;\n",
tab, n->vargen, n);
if(XXX)print("struct _T_%ld %hC;\n", n->vargen, n);
} else {
Bprint(bout, "%stypedef %C _T_%ld%lC;\n",
tab, n, n->vargen, n);
if(XXX)print("typedef %C _T_%ld%lC;\n", n, n->vargen, n);
}
}
break;
}
typeexpand = 0;
flag = 1;
for(d=r; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
if(flag) {
Bprint(bout, "\n%s// %s variables\n", tab, msg);
flag = 0;
}
nam = "???";
pkg = nam;
s = d->dsym;
if(s != S) {
nam = s->name;
pkg = s->opackage;
}
n = d->dnode;
t = n->type;
if(n->vargen != 0) {
if(YYY) print("nam-1 %s\n", nam);
Bprint(bout, "%s%C _V_%ld%lC; // %s\n",
tab, t, n->vargen, t, nam);
continue;
}
if(t->etype == TFUNC && t->thistuple > 0) {
if(YYY) print("nam-2 %s\n", nam);
typ = thistypenam(t);
Bprint(bout, "%s%C %s_%s_%s%lC;\n",
tab, t, pkg, typ, nam, t);
continue;
}
if(YYY) print("nam-3 %E %s %lT\n", t->etype, nam, t);
Bprint(bout, "%s%C %s_%s%lC;\n",
tab, t, pkg, nam, t);
}
}
/*
* open the frame
* declare dummy this/in/out args
*/
void
docall1(Prog *p)
{
Node *f, *t, *n;
if(p->addr.type != ANODE)
goto bad;
f = p->addr.node;
if(f == N)
goto bad;
t = f->type;
if(t == N)
goto bad;
if(t->etype == TPTR)
t = t->type;
if(t->etype != TFUNC)
goto bad;
Bprint(bout, "\t{\n"); // open a block - closed in CALL2/CALL3
if(t->thistuple > 0) {
n = *getthis(t);
if(n->nname == N)
goto bad;
Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
}
if(t->outtuple > 0) {
n = *getoutarg(t);
if(n->nname == N)
goto bad;
Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
}
if(t->intuple > 0) {
n = *getinarg(t);
if(n->nname == N)
goto bad;
Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
}
return;
bad:
fatal("docall1: bad %P", p);
}
/*
* call the function
*/
void
docall2(Prog *p)
{
Node *f, *t, *n;
if(p->addr.type != ANODE)
goto bad;
f = p->addr.node;
if(f == N)
goto bad;
t = f->type;
if(t == N || t->etype != TFUNC)
goto bad;
Bprint(bout, "\t%D(", p);
if(t->thistuple > 0) {
n = *getthis(t);
Bprint(bout, "&_V_%ld", n->nname->vargen);
} else
Bprint(bout, "0");
if(t->outtuple > 0) {
n = *getoutarg(t);
Bprint(bout, ", &_V_%ld", n->nname->vargen);
} else
Bprint(bout, ", 0");
if(t->intuple > 0) {
n = *getinarg(t);
Bprint(bout, ", &_V_%ld);\n", n->nname->vargen);
} else
Bprint(bout, ", 0);\n");
return;
bad:
fatal("docall2: bad");
}
/*
* call the function indirect
*/
void
docalli2(Prog *p)
{
Node *f, *t, *n;
if(p->addr.type != ANODE)
goto bad;
f = p->addr.node;
if(f == N)
goto bad;
t = f->type;
if(t == N || t->etype != TPTR)
goto bad;
t = t->type;
if(t->etype != TFUNC)
goto bad;
// pass one -- declare the prototype
if(t->outtuple > 0) {
n = *getoutarg(t);
Bprint(bout, "\t(*(void(*)(void*, _T_%ld*", n->vargen);
} else
Bprint(bout, "\t(*(void(*)(void*, void*");
if(t->intuple > 0) {
n = *getinarg(t);
Bprint(bout, ", _T_%ld*)", n->vargen);
} else
Bprint(bout, ", void*)");
// pass two -- pass the arguments
if(t->outtuple > 0) {
n = *getoutarg(t);
Bprint(bout, ")%R)(0, &_V_%ld", PTPTR, n->nname->vargen);
} else
Bprint(bout, ")%R)(0, 0", PTPTR);
if(t->intuple > 0) {
n = *getinarg(t);
Bprint(bout, ", &_V_%ld);\n", n->nname->vargen);
} else
Bprint(bout, ", 0);\n");
return;
bad:
fatal("docalli2: bad");
}
/*
* call the method
*/
void
docallm2(Prog *p)
{
Node *f, *t, *n;
char *pkg, *typ, *nam;
if(p->addr.type != ANODE)
goto bad;
f = p->addr.node;
if(f == N || f->op != ODOTMETH)
goto bad;
t = f->type;
if(t == N || t->etype != TFUNC)
goto bad;
nam = "???";
pkg = nam;
typ = nam;
// get the structure name
n = f->left;
if(n != N)
n = n->type;
if(n->op == OTYPE && n->etype == TPTR)
n = n->type;
if(n->sym != S) {
typ = n->sym->name;
pkg = n->sym->opackage;
}
// get the function name
n = f->right;
if(n != N && n->op == ONAME && n->sym != S)
nam = n->sym->name;
Bprint(bout, "\t%s_%s_%s(%R", pkg, typ, nam, PTPTR);
if(t->outtuple > 0) {
n = *getoutarg(t);
Bprint(bout, ", (void*)&_V_%ld", n->nname->vargen);
} else
Bprint(bout, ", 0");
if(t->intuple > 0) {
n = *getinarg(t);
Bprint(bout, ", (void*)&_V_%ld);\n", n->nname->vargen);
} else
Bprint(bout, ", 0);\n");
return;
bad:
fatal("docallm2: bad");
}
/*
* call the interface method
*/
void
docallf2(Prog *p)
{
Node *f, *t, *n;
int offset;
if(p->addr.type != ANODE)
goto bad;
f = p->addr.node;
if(f == N || f->op != ODOTINTER)
goto bad;
t = f->type;
if(t == N || t->etype != TFUNC)
goto bad;
offset = 0;
Bprint(bout, "\t(_U._R_I.m->fun[%d])(_U._R_I.s", f->kaka);
if(t->outtuple > 0) {
n = *getoutarg(t);
Bprint(bout, ", (void*)&_V_%ld", n->nname->vargen);
} else
Bprint(bout, ", 0");
if(t->intuple > 0) {
n = *getinarg(t);
Bprint(bout, ", (void*)&_V_%ld);\n", n->nname->vargen);
} else
Bprint(bout, ", 0);\n");
return;
bad:
fatal("docallf2: bad");
}
/*
* close the frame
*/
void
docall3(Prog *p)
{
Bprint(bout, "\t}\n");
}
char*
signame(Node *t)
{
// this code sb merged with thistypename
static char name[100];
char *typ, *pkg;
typ = "???";
pkg = typ;
if(t == N || t->op != OTYPE)
goto out;
if(t->etype == TPTR) {
t = t->type;
if(t == N)
goto out;
}
if(t->sym == S)
goto out;
typ = t->sym->name;
pkg = t->sym->opackage; // this may not be correct
out:
snprint(name, sizeof(name), "sig_%s_%s", pkg, typ);
return name;
}
void
doconv(Prog *p)
{
Node *n, *tl, *tr;
int l, pt;
if(p->pt != PTNIL) {
Bprint(bout, "\t%R = %R;\n", p->pt, p->pt1);
return;
}
n = p->addr.node;
if(p->addr.type != ANODE || n == N || n->op != OCONV)
fatal("doconv: PCONV-N not OCONV");
tl = n->left;
tr = n->right;
if(isinter(tl)) {
if(isptrto(tr, TSTRUCT)) {
Bprint(bout, "\tconvertStoI(%s, ", signame(tl));
Bprint(bout, "%s); // _U._R_I = _U._R_P\n",
signame(tr));
return;
}
if(isinter(tr)) {
Bprint(bout, "\tconvertItoI(%s); // _U._R_I = _U._R_I\n",
signame(tl));
return;
}
}
if(isptrto(tl, TSTRUCT) && isinter(tr)) {
Bprint(bout, "\t%R = %R.s;\n", TPTR, PTINTER);
return;
}
if(isint[tl->etype] || isfloat[tl->etype]) {
if(isint[tr->etype] || isfloat[tr->etype]) {
Bprint(bout, "\t%R = %R;\n", conv2pt(tl), conv2pt(tr));
return;
}
}
if(isptrto(tl, TSTRING)) {
if(isint[tr->etype]) {
Bprint(bout, "\tconvertItoZ(%R);\n", conv2pt(tr));
return;
}
l = isbytearray(tr);
if(l > 0) {
pt = PTADDR;
if(tr->etype == TPTR)
pt = TPTR;
Bprint(bout, "\tconvertBtoZ(%R, %d);\n", pt, l-1);
return;
}
}
fatal("doconv: %T = %T", tl, tr);
}
char*
getfmt(int pt)
{
switch(pt) {
default:
return "D";
case PTUINT8:
case PTUINT16:
case PTUINT32:
case PTUINT64:
return "UD";
case PTFLOAT32:
case PTFLOAT64:
case PTFLOAT80:
return "F";
case PTSTRING:
return "Z";
}
}