// 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), "

"); 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), ""); 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; ilexical != 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; }