aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/5g/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5g/cgen.c')
-rw-r--r--src/cmd/5g/cgen.c1840
1 files changed, 0 insertions, 1840 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
deleted file mode 100644
index 354e0cbfd6..0000000000
--- a/src/cmd/5g/cgen.c
+++ /dev/null
@@ -1,1840 +0,0 @@
-// 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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2, f0, f1;
- int a, w, rg;
- Prog *p1, *p2, *p3;
- Addr addr;
-
- if(debug['g']) {
- dump("\ncgen-n", n);
- dump("cgen-res", res);
- }
- if(n == N || n->type == T)
- goto ret;
-
- if(res == N || res->type == T)
- fatal("cgen: res nil");
-
- switch(n->op) {
- case OSLICE:
- case OSLICEARR:
- case OSLICESTR:
- case OSLICE3:
- case OSLICE3ARR:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_slice(n, &n1);
- cgen(&n1, res);
- } else
- cgen_slice(n, res);
- return;
- case OEFACE:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_eface(n, &n1);
- cgen(&n1, res);
- } else
- cgen_eface(n, res);
- return;
- }
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(n->ullman >= UINF) {
- if(n->op == OINDREG)
- fatal("cgen: this is going to misscompile");
- if(res->ullman >= UINF) {
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- goto ret;
- }
- }
-
- if(isfat(n->type)) {
- if(n->type->width < 0)
- fatal("forgot to compute width for %T", n->type);
- sgen(n, res, n->type->width);
- goto ret;
- }
-
-
- // update addressability for string, slice
- // can't do in walk because n->left->addable
- // changes if n->left is an escaping local variable.
- switch(n->op) {
- case OSPTR:
- case OLEN:
- if(isslice(n->left->type) || istype(n->left->type, TSTRING))
- n->addable = n->left->addable;
- break;
- case OCAP:
- if(isslice(n->left->type))
- n->addable = n->left->addable;
- break;
- case OITAB:
- n->addable = n->left->addable;
- break;
- }
-
- // if both are addressable, move
- if(n->addable && res->addable) {
- if(is64(n->type) || is64(res->type) ||
- n->op == OREGISTER || res->op == OREGISTER ||
- iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
- gmove(n, res);
- } else {
- regalloc(&n1, n->type, N);
- gmove(n, &n1);
- cgen(&n1, res);
- regfree(&n1);
- }
- goto ret;
- }
-
- // if both are not addressable, use a temporary.
- if(!n->addable && !res->addable) {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
-
- if(complexop(n, res)) {
- complexgen(n, res);
- return;
- }
-
- // if n is sudoaddable generate addr and move
- if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
- a = optoas(OAS, n->type);
- if(sudoaddable(a, n, &addr, &w)) {
- if (res->op != OREGISTER) {
- regalloc(&n2, res->type, N);
- p1 = gins(a, N, &n2);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- gmove(&n2, res);
- regfree(&n2);
- } else {
- p1 = gins(a, N, res);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- }
- sudoclean();
- goto ret;
- }
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- nl = n->left;
- nr = n->right;
-
- if(nl != N && nl->ullman >= UINF)
- if(nr != N && nr->ullman >= UINF) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- n2 = *n;
- n2.left = &n1;
- cgen(&n2, res);
- goto ret;
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
- switch(n->op) {
- // math goes to cgen64.
- case OMINUS:
- case OCOM:
- case OADD:
- case OSUB:
- case OMUL:
- case OLROT:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- cgen64(n, res);
- return;
- }
- }
-
- if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
- goto flt;
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen: unknown op %+hN", n);
- break;
-
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- fatal("unexpected complex");
- break;
-
- // these call bgen to get a bool value
- case OOROR:
- case OANDAND:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case ONOT:
- p1 = gbranch(AB, T, 0);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AB, T, 0);
- patch(p1, pc);
- bgen(n, 1, 0, p2);
- gmove(nodbool(0), res);
- patch(p3, pc);
- goto ret;
-
- case OPLUS:
- cgen(nl, res);
- goto ret;
-
- // unary
- case OCOM:
- a = optoas(OXOR, nl->type);
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, -1);
- gins(a, &n2, &n1);
- goto norm;
-
- case OMINUS:
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, 0);
- gins(optoas(OMINUS, nl->type), &n2, &n1);
- goto norm;
-
- // symmetric binary
- case OAND:
- case OOR:
- case OXOR:
- case OADD:
- case OMUL:
- a = optoas(n->op, nl->type);
- goto sbop;
-
- // asymmetric binary
- case OSUB:
- a = optoas(n->op, nl->type);
- goto abop;
-
- case OHMUL:
- cgen_hmul(nl, nr, res);
- break;
-
- case OLROT:
- case OLSH:
- case ORSH:
- cgen_shift(n->op, n->bounded, nl, nr, res);
- break;
-
- case OCONV:
- if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- break;
- }
- if(nl->addable && !is64(nl->type)) {
- regalloc(&n1, nl->type, res);
- gmove(nl, &n1);
- } else {
- if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
- tempname(&n1, nl->type);
- else
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- }
- if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
- tempname(&n2, n->type);
- else
- regalloc(&n2, n->type, N);
- gmove(&n1, &n2);
- gmove(&n2, res);
- if(n1.op == OREGISTER)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- break;
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME: // PHEAP or PPARAMREF var
- igen(n, &n1, res);
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OITAB:
- // interface table is first word of interface value
- igen(nl, &n1, res);
- n1.type = n->type;
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OSPTR:
- // pointer is the first word of string or slice.
- if(isconst(nl, CTSTR)) {
- regalloc(&n1, types[tptr], res);
- p1 = gins(AMOVW, N, &n1);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- igen(nl, &n1, res);
- n1.type = n->type;
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(istype(nl->type, TSTRING) || isslice(nl->type)) {
- // both slice and string have len one pointer into the struct.
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_nel;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OLEN: unknown type %lT", nl->type);
- break;
-
- case OCAP:
- if(istype(nl->type, TCHAN)) {
- // chan has cap in the second 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- rg = -1;
- if(n->ullman >= UINF) {
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- rg = res->val.u.reg;
- reg[rg]--;
- }
- }
- if(n->op == OCALLMETH)
- cgen_callmeth(n, 0);
- else
- cgen_call(n, 0);
- if(rg >= 0)
- reg[rg]++;
- cgen_callret(n, res);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_callret(n, res);
- break;
-
- case OMOD:
- case ODIV:
- a = optoas(n->op, nl->type);
- goto abop;
- }
- goto ret;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- // TODO(kaib): use fewer registers here.
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- switch(n->op) {
- case OADD:
- case OSUB:
- case OAND:
- case OOR:
- case OXOR:
- if(smallintconst(nr)) {
- n2 = *nr;
- break;
- }
- default:
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- }
- } else {
- switch(n->op) {
- case OADD:
- case OSUB:
- case OAND:
- case OOR:
- case OXOR:
- if(smallintconst(nr)) {
- n2 = *nr;
- break;
- }
- default:
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
- }
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- }
- gins(a, &n2, &n1);
-norm:
- // Normalize result for types smaller than word.
- if(n->type->width < widthptr) {
- switch(n->op) {
- case OADD:
- case OSUB:
- case OMUL:
- case OCOM:
- case OMINUS:
- gins(optoas(OAS, n->type), &n1, &n1);
- break;
- }
- }
- gmove(&n1, res);
- regfree(&n1);
- if(n2.op != OLITERAL)
- regfree(&n2);
- goto ret;
-
-flt: // floating-point.
- regalloc(&f0, nl->type, res);
- if(nr != N)
- goto flt2;
-
- if(n->op == OMINUS) {
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- n->op = OMUL;
- goto flt2;
- }
-
- // unary
- cgen(nl, &f0);
- if(n->op != OCONV && n->op != OPLUS)
- gins(optoas(n->op, n->type), &f0, &f0);
- gmove(&f0, res);
- regfree(&f0);
- goto ret;
-
-flt2: // binary
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &f0);
- regalloc(&f1, n->type, N);
- gmove(&f0, &f1);
- cgen(nr, &f0);
- gins(optoas(n->op, n->type), &f0, &f1);
- } else {
- cgen(nr, &f0);
- regalloc(&f1, n->type, N);
- cgen(nl, &f1);
- gins(optoas(n->op, n->type), &f0, &f1);
- }
- gmove(&f1, res);
- regfree(&f0);
- regfree(&f1);
- goto ret;
-
-ret:
- ;
-}
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-Prog*
-cgenindex(Node *n, Node *res, int bounded)
-{
- Node tmp, lo, hi, zero, n1, n2;
-
- if(!is64(n->type)) {
- cgen(n, res);
- return nil;
- }
-
- tempname(&tmp, types[TINT64]);
- cgen(n, &tmp);
- split64(&tmp, &lo, &hi);
- gmove(&lo, res);
- if(bounded) {
- splitclean();
- return nil;
- }
- regalloc(&n1, types[TINT32], N);
- regalloc(&n2, types[TINT32], N);
- nodconst(&zero, types[TINT32], 0);
- gmove(&hi, &n1);
- gmove(&zero, &n2);
- gcmp(ACMP, &n1, &n2);
- regfree(&n2);
- regfree(&n1);
- splitclean();
- return gbranch(ABNE, T, -1);
-}
-
-/*
- * generate:
- * res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl;
- Node n1, n2, n3;
- int r;
-
- if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T || res == N || res->type == T)
- fatal("agen");
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(isconst(n, CTNIL) && n->type->width > widthptr) {
- // Use of a nil interface or nil slice.
- // Create a temporary we can take the address of and read.
- // The generated code is just going to panic, so it need not
- // be terribly efficient. See issue 3670.
- tempname(&n1, n->type);
- gvardef(&n1);
- clearfat(&n1);
- regalloc(&n2, types[tptr], res);
- gins(AMOVW, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
-
- if(n->addable) {
- memset(&n1, 0, sizeof n1);
- n1.op = OADDR;
- n1.left = n;
- regalloc(&n2, types[tptr], res);
- gins(AMOVW, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
- nl = n->left;
-
- switch(n->op) {
- default:
- fatal("agen: unknown op %+hN", n);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- r = -1;
- if(n->ullman >= UINF) {
- if(res->op == OREGISTER || res->op == OINDREG) {
- r = res->val.u.reg;
- reg[r]--;
- }
- }
- if(n->op == OCALLMETH)
- cgen_callmeth(n, 0);
- else
- cgen_call(n, 0);
- if(r >= 0)
- reg[r]++;
- cgen_aret(n, res);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_aret(n, res);
- break;
-
- case OSLICE:
- case OSLICEARR:
- case OSLICESTR:
- case OSLICE3:
- case OSLICE3ARR:
- tempname(&n1, n->type);
- cgen_slice(n, &n1);
- agen(&n1, res);
- break;
-
- case OEFACE:
- tempname(&n1, n->type);
- cgen_eface(n, &n1);
- agen(&n1, res);
- break;
-
- case OINDEX:
- agenr(n, &n1, res);
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case ONAME:
- // should only get here with names in this func.
- if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
- dump("bad agen", n);
- fatal("agen: bad ONAME funcdepth %d != %d",
- n->funcdepth, funcdepth);
- }
-
- // should only get here for heap vars or paramref
- if(!(n->class & PHEAP) && n->class != PPARAMREF) {
- dump("bad agen", n);
- fatal("agen: bad ONAME class %#x", n->class);
- }
- cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- cgen_checknil(res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- cgen_checknil(res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[tptr], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
- }
-
-ret:
- ;
-}
-
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
- Node n1;
- int r;
-
- if(debug['g']) {
- dump("\nigen-n", n);
- }
- switch(n->op) {
- case ONAME:
- if((n->class&PHEAP) || n->class == PPARAMREF)
- break;
- *a = *n;
- return;
-
- case OINDREG:
- // Increase the refcount of the register so that igen's caller
- // has to call regfree.
- if(n->val.u.reg != REGSP)
- reg[n->val.u.reg]++;
- *a = *n;
- return;
-
- case ODOT:
- igen(n->left, a, res);
- a->xoffset += n->xoffset;
- a->type = n->type;
- return;
-
- case ODOTPTR:
- if(n->left->addable
- || n->left->op == OCALLFUNC
- || n->left->op == OCALLMETH
- || n->left->op == OCALLINTER) {
- // igen-able nodes.
- igen(n->left, &n1, res);
- regalloc(a, types[tptr], &n1);
- gmove(&n1, a);
- regfree(&n1);
- } else {
- regalloc(a, types[tptr], res);
- cgen(n->left, a);
- }
- cgen_checknil(a);
- a->op = OINDREG;
- a->xoffset = n->xoffset;
- a->type = n->type;
- return;
-
- case OCALLMETH:
- case OCALLFUNC:
- case OCALLINTER:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- r = -1;
- if(n->ullman >= UINF) {
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- r = res->val.u.reg;
- reg[r]--;
- }
- }
- switch(n->op) {
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
- case OCALLFUNC:
- cgen_call(n, 0);
- break;
- case OCALLINTER:
- cgen_callinter(n, N, 0);
- break;
- }
- if(r >= 0)
- reg[r]++;
- regalloc(a, types[tptr], res);
- cgen_aret(n, a);
- a->op = OINDREG;
- a->type = n->type;
- return;
- }
-
- agenr(n, a, res);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * allocate a register in res and generate
- * newreg = &n
- * The caller must call regfree(a).
- */
-void
-cgenr(Node *n, Node *a, Node *res)
-{
- Node n1;
-
- if(debug['g'])
- dump("cgenr-n", n);
-
- if(isfat(n->type))
- fatal("cgenr on fat node");
-
- if(n->addable) {
- regalloc(a, types[tptr], res);
- gmove(n, a);
- return;
- }
-
- switch(n->op) {
- case ONAME:
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- igen(n, &n1, res);
- regalloc(a, types[tptr], &n1);
- gmove(&n1, a);
- regfree(&n1);
- break;
- default:
- regalloc(a, n->type, res);
- cgen(n, a);
- break;
- }
-}
-
-/*
- * generate:
- * newreg = &n;
- *
- * caller must regfree(a).
- * The generated code checks that the result is not nil.
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
- Node *nl, *nr;
- Node n1, n2, n3, n4, tmp;
- Prog *p1, *p2;
- uint32 w;
- uint64 v;
- int bounded;
-
- if(debug['g'])
- dump("agenr-n", n);
-
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- case ODOT:
- case ODOTPTR:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- igen(n, &n1, res);
- regalloc(a, types[tptr], &n1);
- agen(&n1, a);
- regfree(&n1);
- break;
-
- case OIND:
- cgenr(n->left, a, res);
- cgen_checknil(a);
- break;
-
- case OINDEX:
- p2 = nil; // to be patched to panicindex.
- w = n->type->width;
- bounded = debug['B'] || n->bounded;
- if(nr->addable) {
- if(!isconst(nr, CTINT))
- tempname(&tmp, types[TINT32]);
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
- p2 = cgenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- } else
- if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- if(!isconst(nl, CTSTR)) {
- agenr(nl, &n3, res);
- }
- } else {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp, bounded);
- nr = &tmp;
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- regalloc(&n1, tmp.type, N);
- gins(optoas(OAS, tmp.type), &tmp, &n1);
- }
-
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // w is width
-
- // constant index
- if(isconst(nr, CTINT)) {
- if(isconst(nl, CTSTR))
- fatal("constant string constant index");
- v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->bounded) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- regalloc(&n4, n1.type, N);
- gmove(&n1, &n4);
- nodconst(&n2, types[TUINT32], v);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
- regfree(&n4);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- *a = n3;
- break;
- }
-
- regalloc(&n2, types[TINT32], &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->bounded) {
- // check bounds
- if(isconst(nl, CTSTR)) {
- nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- regalloc(&n4, types[TUINT32], N);
- gmove(&n1, &n4);
- } else {
- nodconst(&n4, types[TUINT32], nl->type->bound);
- }
- gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
- if(n4.op == OREGISTER)
- regfree(&n4);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(AMOVW, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.type = TYPE_ADDR;
- } else
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- if(w == 0) {
- // nothing to do
- } else if(w == 1 || w == 2 || w == 4 || w == 8) {
- memset(&n4, 0, sizeof n4);
- n4.op = OADDR;
- n4.left = &n2;
- cgen(&n4, &n3);
- if (w == 1)
- gins(AADD, &n2, &n3);
- else if(w == 2)
- gshift(AADD, &n2, SHIFT_LL, 1, &n3);
- else if(w == 4)
- gshift(AADD, &n2, SHIFT_LL, 2, &n3);
- else if(w == 8)
- gshift(AADD, &n2, SHIFT_LL, 3, &n3);
- } else {
- regalloc(&n4, types[TUINT32], N);
- nodconst(&n1, types[TUINT32], w);
- gmove(&n1, &n4);
- gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- regfree(&n4);
- }
-
- *a = n3;
- regfree(&n2);
- break;
-
- default:
- regalloc(a, types[tptr], res);
- agen(n, a);
- break;
- }
-}
-
-void
-gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
-{
- Node n1, n2, n3;
- int a;
-
- regalloc(&n1, t, N);
- cgen(n, &n1);
- a = optoas(OCMP, t);
- if(a != ACMP) {
- nodconst(&n2, t, 0);
- regalloc(&n3, t, N);
- gmove(&n2, &n3);
- gcmp(a, &n1, &n3);
- regfree(&n3);
- } else
- gins(ATST, &n1, N);
- a = optoas(o, t);
- patch(gbranch(a, t, likely), to);
- regfree(&n1);
-}
-
-/*
- * generate:
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, n3, tmp;
- NodeList *ll;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nbgen", n);
- }
-
- if(n == N)
- n = nodbool(1);
-
- if(n->ninit != nil)
- genlist(n->ninit);
-
- if(n->type == T) {
- convlit(&n, types[TBOOL]);
- if(n->type == T)
- goto ret;
- }
-
- et = n->type->etype;
- if(et != TBOOL) {
- yyerror("cgen: bad type %T for %O", n->type, n->op);
- patch(gins(AEND, N, N), to);
- goto ret;
- }
- nr = N;
-
- switch(n->op) {
- default:
- a = ONE;
- if(!true)
- a = OEQ;
- gencmp0(n, n->type, a, likely, to);
- goto ret;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AB, T, 0), to);
- goto ret;
-
- case OANDAND:
- case OOROR:
- if((n->op == OANDAND) == true) {
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- } else {
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
- }
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- goto ret;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- goto ret;
- }
-
- switch(n->op) {
-
- case ONOT:
- bgen(nl, !true, likely, to);
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- a = n->op;
- if(!true) {
- if(isfloat[nl->type->etype]) {
- // brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AB, T, 0);
- p2 = gbranch(AB, T, 0);
- patch(p1, pc);
- ll = n->ninit;
- n->ninit = nil;
- bgen(n, 1, -likely, p2);
- n->ninit = ll;
- patch(gbranch(AB, T, 0), to);
- patch(p2, pc);
- goto ret;
- }
- a = brcom(a);
- true = !true;
- }
-
- // make simplest on right
- if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
- a = brrev(a);
- r = nl;
- nl = nr;
- nr = r;
- }
-
- if(isslice(nl->type)) {
- // only valid to cmp darray to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal array comparison");
- break;
- }
-
- igen(nl, &n1, N);
- n1.xoffset += Array_array;
- n1.type = types[tptr];
- gencmp0(&n1, types[tptr], a, likely, to);
- regfree(&n1);
- break;
- }
-
- if(isinter(nl->type)) {
- // front end shold only leave cmp to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal interface comparison");
- break;
- }
-
- igen(nl, &n1, N);
- n1.type = types[tptr];
- n1.xoffset += 0;
- gencmp0(&n1, types[tptr], a, likely, to);
- regfree(&n1);
- break;
- }
-
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, likely, to);
- break;
- }
-
- if(is64(nr->type)) {
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- cmp64(nl, nr, a, likely, to);
- break;
- }
-
- if(nr->op == OLITERAL) {
- if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) {
- gencmp0(nl, nl->type, a, likely, to);
- break;
- }
- if(nr->val.ctype == CTNIL) {
- gencmp0(nl, nl->type, a, likely, to);
- break;
- }
- }
-
- a = optoas(a, nr->type);
-
- if(nr->ullman >= UINF) {
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
-
- tempname(&tmp, nl->type);
- gmove(&n1, &tmp);
- regfree(&n1);
-
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
-
- regalloc(&n1, nl->type, N);
- cgen(&tmp, &n1);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type, likely), to);
-
- regfree(&n1);
- regfree(&n2);
- break;
- }
-
- tempname(&n3, nl->type);
- cgen(nl, &n3);
-
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
-
- regalloc(&n1, nl->type, N);
- gmove(&n3, &n1);
-
- regalloc(&n2, nr->type, N);
- gmove(&tmp, &n2);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- if(isfloat[nl->type->etype]) {
- if(n->op == ONE) {
- p1 = gbranch(ABVS, nr->type, likely);
- patch(gbranch(a, nr->type, likely), to);
- patch(p1, to);
- } else {
- p1 = gbranch(ABVS, nr->type, -likely);
- patch(gbranch(a, nr->type, likely), to);
- patch(p1, pc);
- }
- } else {
- patch(gbranch(a, nr->type, likely), to);
- }
- regfree(&n1);
- regfree(&n2);
- break;
- }
- goto ret;
-
-ret:
- ;
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 off;
-
- switch(n->op) {
- case OINDREG:
- return n->xoffset;
-
- case ODOT:
- t = n->left->type;
- if(isptr[t->etype])
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- return off + n->xoffset;
-
- case OINDEX:
- t = n->left->type;
- if(!isfixedarray(t))
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- if(isconst(n->right, CTINT))
- return off + t->type->width * mpgetfix(n->right->val.u.xval);
- return 1000;
-
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- t = structfirst(&flist, getoutarg(t));
- if(t != T)
- return t->width + 4; // correct for LR
- break;
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000;
-}
-
-/*
- * block copy:
- * memmove(&res, &n, w);
- * NB: character copy assumed little endian architecture
- */
-void
-sgen(Node *n, Node *res, int64 w)
-{
- Node dst, src, tmp, nend, r0, r1, r2, *f;
- int32 c, odst, osrc;
- int dir, align, op;
- Prog *p, *ploop;
- NodeList *l;
-
- if(debug['g']) {
- print("\nsgen w=%lld\n", w);
- dump("r", n);
- dump("res", res);
- }
-
- if(n->ullman >= UINF && res->ullman >= UINF)
- fatal("sgen UINF");
-
- if(w < 0 || (int32)w != w)
- fatal("sgen copy %lld", w);
-
- if(n->type == T)
- fatal("sgen: missing type");
-
- if(w == 0) {
- // evaluate side effects only.
- regalloc(&dst, types[tptr], N);
- agen(res, &dst);
- agen(n, &dst);
- regfree(&dst);
- return;
- }
-
- // If copying .args, that's all the results, so record definition sites
- // for them for the liveness analysis.
- if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
- for(l = curfn->dcl; l != nil; l = l->next)
- if(l->n->class == PPARAMOUT)
- gvardef(l->n);
-
- // Avoid taking the address for simple enough types.
- if(componentgen(n, res))
- return;
-
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align = n->type->align;
- switch(align) {
- default:
- fatal("sgen: invalid alignment %d for %T", align, n->type);
- case 1:
- op = AMOVB;
- break;
- case 2:
- op = AMOVH;
- break;
- case 4:
- op = AMOVW;
- break;
- }
- if(w%align)
- fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
- c = w / align;
-
- // offset on the stack
- osrc = stkof(n);
- odst = stkof(res);
- if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
- // osrc and odst both on stack, and at least one is in
- // an unknown position. Could generate code to test
- // for forward/backward copy, but instead just copy
- // to a temporary location first.
- tempname(&tmp, n->type);
- sgen(n, &tmp, w);
- sgen(&tmp, res, w);
- return;
- }
- if(osrc%align != 0 || odst%align != 0)
- fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir = align;
- if(osrc < odst && odst < osrc+w)
- dir = -dir;
-
- if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) {
- r0.op = OREGISTER;
- r0.val.u.reg = REGALLOC_R0;
- r1.op = OREGISTER;
- r1.val.u.reg = REGALLOC_R0 + 1;
- r2.op = OREGISTER;
- r2.val.u.reg = REGALLOC_R0 + 2;
-
- regalloc(&src, types[tptr], &r1);
- regalloc(&dst, types[tptr], &r2);
- if(n->ullman >= res->ullman) {
- // eval n first
- agen(n, &src);
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- } else {
- // eval res first
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- agen(n, &src);
- }
- regalloc(&tmp, types[tptr], &r0);
- f = sysfunc("duffcopy");
- p = gins(ADUFFCOPY, N, f);
- afunclit(&p->to, f);
- // 8 and 128 = magic constants: see ../../runtime/asm_arm.s
- p->to.offset = 8*(128-c);
-
- regfree(&tmp);
- regfree(&src);
- regfree(&dst);
- return;
- }
-
- if(n->ullman >= res->ullman) {
- agenr(n, &dst, res); // temporarily use dst
- regalloc(&src, types[tptr], N);
- gins(AMOVW, &dst, &src);
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- } else {
- if(res->op == ONAME)
- gvardef(res);
- agenr(res, &dst, res);
- agenr(n, &src, N);
- }
-
- regalloc(&tmp, types[TUINT32], N);
-
- // set up end marker
- memset(&nend, 0, sizeof nend);
- if(c >= 4) {
- regalloc(&nend, types[TUINT32], N);
-
- p = gins(AMOVW, &src, &nend);
- p->from.type = TYPE_ADDR;
- if(dir < 0)
- p->from.offset = dir;
- else
- p->from.offset = w;
- }
-
- // move src and dest to the end of block if necessary
- if(dir < 0) {
- p = gins(AMOVW, &src, &src);
- p->from.type = TYPE_ADDR;
- p->from.offset = w + dir;
-
- p = gins(AMOVW, &dst, &dst);
- p->from.type = TYPE_ADDR;
- p->from.offset = w + dir;
- }
-
- // move
- if(c >= 4) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
- p->scond |= C_PBIT;
- ploop = p;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = dir;
- p->scond |= C_PBIT;
-
- p = gins(ACMP, &src, N);
- raddr(&nend, p);
-
- patch(gbranch(ABNE, T, 0), ploop);
- regfree(&nend);
- } else {
- while(c-- > 0) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
- p->scond |= C_PBIT;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = dir;
- p->scond |= C_PBIT;
- }
- }
-
- regfree(&dst);
- regfree(&src);
- regfree(&tmp);
-}
-
-static int
-cadable(Node *n)
-{
- if(!n->addable) {
- // dont know how it happens,
- // but it does
- return 0;
- }
-
- switch(n->op) {
- case ONAME:
- return 1;
- }
- return 0;
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if cant.
- */
-int
-componentgen(Node *nr, Node *nl)
-{
- Node nodl, nodr, tmp;
- Type *t;
- int freel, freer;
- vlong fldcount;
- vlong loffset, roffset;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- t = nl->type;
-
- // Slices are ok.
- if(isslice(t))
- break;
- // Small arrays are ok.
- if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
- break;
-
- goto no;
-
- case TSTRUCT:
- // Small structs with non-fat types are ok.
- // Zero-sized structs are treated separately elsewhere.
- fldcount = 0;
- for(t=nl->type->type; t; t=t->down) {
- if(isfat(t->type))
- goto no;
- if(t->etype != TFIELD)
- fatal("componentgen: not a TFIELD: %lT", t);
- fldcount++;
- }
- if(fldcount == 0 || fldcount > 4)
- goto no;
-
- break;
-
- case TSTRING:
- case TINTER:
- break;
- }
-
- nodl = *nl;
- if(!cadable(nl)) {
- if(nr != N && !cadable(nr))
- goto no;
- igen(nl, &nodl, N);
- freel = 1;
- }
-
- if(nr != N) {
- nodr = *nr;
- if(!cadable(nr)) {
- igen(nr, &nodr, N);
- freer = 1;
- }
- } else {
- // When zeroing, prepare a register containing zero.
- nodconst(&tmp, nl->type, 0);
- regalloc(&nodr, types[TUINT], N);
- gmove(&tmp, &nodr);
- freer = 1;
- }
-
- // nl and nr are 'cadable' which basically means they are names (variables) now.
- // If they are the same variable, don't generate any code, because the
- // VARDEF we generate will mark the old value as dead incorrectly.
- // (And also the assignments are useless.)
- if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
- goto yes;
-
- switch(nl->type->etype) {
- case TARRAY:
- // componentgen for arrays.
- if(nl->op == ONAME)
- gvardef(nl);
- t = nl->type;
- if(!isslice(t)) {
- nodl.type = t->type;
- nodr.type = nodl.type;
- for(fldcount=0; fldcount < t->bound; fldcount++) {
- if(nr == N)
- clearslim(&nodl);
- else
- gmove(&nodr, &nodl);
- nodl.xoffset += t->type->width;
- nodr.xoffset += t->type->width;
- }
- goto yes;
- }
-
- // componentgen for slices.
- nodl.xoffset += Array_array;
- nodl.type = ptrto(nl->type->type);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_cap-Array_nel;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRING:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TINTER:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRUCT:
- if(nl->op == ONAME)
- gvardef(nl);
- loffset = nodl.xoffset;
- roffset = nodr.xoffset;
- // funarg structs may not begin at offset zero.
- if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
- loffset -= nl->type->type->width;
- if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
- roffset -= nr->type->type->width;
-
- for(t=nl->type->type; t; t=t->down) {
- nodl.xoffset = loffset + t->width;
- nodl.type = t->type;
-
- if(nr == N)
- clearslim(&nodl);
- else {
- nodr.xoffset = roffset + t->width;
- nodr.type = nodl.type;
- gmove(&nodr, &nodl);
- }
- }
- goto yes;
- }
-
-no:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 0;
-
-yes:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 1;
-}