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