| // 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; | |
| } |