]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.power64] build: merge default into dev.power64
authorAustin Clements <austin@google.com>
Wed, 22 Oct 2014 15:21:16 +0000 (11:21 -0400)
committerAustin Clements <austin@google.com>
Wed, 22 Oct 2014 15:21:16 +0000 (11:21 -0400)
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/160200044

54 files changed:
1  2 
include/link.h
lib/codereview/codereview.cfg
lib/codereview/codereview.py
src/cmd/9c/cgen.c
src/cmd/9c/gc.h
src/cmd/9c/sgen.c
src/cmd/9c/swt.c
src/cmd/9c/txt.c
src/cmd/9g/cgen.c
src/cmd/9g/gg.h
src/cmd/9g/gsubr.c
src/cmd/9l/asm.c
src/cmd/cc/cc.y
src/cmd/cc/pgen.c
src/cmd/dist/build.c
src/cmd/dist/buildruntime.c
src/cmd/dist/unix.c
src/cmd/gc/plive.c
src/cmd/gc/popt.c
src/cmd/gc/walk.c
src/cmd/ld/data.c
src/cmd/ld/lib.c
src/cmd/ld/symtab.c
src/liblink/objfile.c
src/pkg/debug/elf/elf.go
src/pkg/debug/elf/file.go
src/pkg/debug/elf/file_test.go
src/pkg/go/build/build.go
src/pkg/math/abs_power64x.s
src/pkg/math/big/arith_power64x.s
src/pkg/os/signal/sig.s
src/pkg/reflect/all_test.go
src/pkg/reflect/asm_power64x.s
src/pkg/reflect/value.go
src/pkg/runtime/defs1_linux.go
src/pkg/runtime/defs_linux_power64.h
src/pkg/runtime/gcinfo_test.go
src/pkg/runtime/heapdump.c
src/pkg/runtime/malloc.c
src/pkg/runtime/malloc.go
src/pkg/runtime/malloc.h
src/pkg/runtime/mem_linux.c
src/pkg/runtime/mgc0.c
src/pkg/runtime/mgc0.h
src/pkg/runtime/os_linux.c
src/pkg/runtime/panic.c
src/pkg/runtime/panic.go
src/pkg/runtime/panic1.go
src/pkg/runtime/proc.c
src/pkg/runtime/stack.c
src/pkg/runtime/string.go
src/pkg/runtime/thunk.s
src/pkg/syscall/mkall.sh
test/nosplit.go

diff --cc include/link.h
Simple merge
index 2801ebf8d6ea0e5b4c9f3b8918dc91989ed96279,2801ebf8d6ea0e5b4c9f3b8918dc91989ed96279..43dbf3ce3b817d7998070c0fe33078c4479a63d4
@@@ -1,1 -1,1 +1,2 @@@
  defaultcc: golang-codereviews@googlegroups.com
++contributors: http://go.googlecode.com/hg/CONTRIBUTORS
index fdf11d1f48f924ed261319c61af3a0a4329f42db,fdf11d1f48f924ed261319c61af3a0a4329f42db..263385b79f991090a6dc4abcc0dc5adad39d4286
@@@ -3603,11 -3603,11 +3603,17 @@@ class MercurialVCS(VersionControlSystem
                        if use_hg_shell:
                                base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
                        else:
--                              base_content = str(self.repo[base_rev][oldrelpath].data())
++                                try:
++                                        base_content = str(self.repo[base_rev][oldrelpath].data())
++                                except Exception:
++                                        pass
                        is_binary = "\0" in base_content  # Mercurial's heuristic
                if status != "R":
--                      new_content = open(relpath, "rb").read()
--                      is_binary = is_binary or "\0" in new_content
++                        try:
++                                new_content = open(relpath, "rb").read()
++                                is_binary = is_binary or "\0" in new_content
++                        except Exception:
++                                pass
                if is_binary and base_content and use_hg_shell:
                        # Fetch again without converting newlines
                        base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
index 0d7a4029455da9fd87ba685145c17fe0ab6d6aa6,0000000000000000000000000000000000000000..aeedc60c06525da006f1cbdfb4c137960a0dcc6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1135 -1,0 +1,1151 @@@
-       if(typesu[n->type->etype]) {
 +// cmd/9c/cgen.c from Vita Nuova.
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include "gc.h"
 +#include "../../pkg/runtime/funcdata.h"
 +
 +void
 +cgen(Node *n, Node *nn)
 +{
 +      Node *l, *r;
 +      Prog *p1;
 +      Node nod, nod1, nod2, nod3, nod4;
 +      int o;
 +      int32 v, curs;
 +
 +      if(debug['g']) {
 +              prtree(nn, "cgen lhs");
 +              prtree(n, "cgen");
 +      }
 +      if(n == Z || n->type == T)
 +              return;
-               regret(&nod, r);
++      if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
 +              sugen(n, nn, n->type->width);
 +              return;
 +      }
 +      l = n->left;
 +      r = n->right;
 +      o = n->op;
 +      if(n->addable >= INDEXED) {
 +              if(nn == Z) {
 +                      switch(o) {
 +                      default:
 +                              nullwarn(Z, Z);
 +                              break;
 +                      case OINDEX:
 +                              nullwarn(l, r);
 +                              break;
 +                      }
 +                      return;
 +              }
 +              gmove(n, nn);
 +              return;
 +      }
 +      curs = cursafe;
 +
 +      if(n->complex >= FNX)
 +      if(l->complex >= FNX)
 +      if(r != Z && r->complex >= FNX)
 +      switch(o) {
 +      default:
-                       regret(&nod, l->left);
++              regret(&nod, r, 0, 0);
 +              cgen(r, &nod);
 +
 +              regsalloc(&nod1, r);
 +              gopcode(OAS, &nod, Z, &nod1);
 +
 +              regfree(&nod);
 +              nod = *n;
 +              nod.right = &nod1;
 +              cgen(&nod, nn);
 +              return;
 +
 +      case OFUNC:
 +      case OCOMMA:
 +      case OANDAND:
 +      case OOROR:
 +      case OCOND:
 +      case ODOT:
 +              break;
 +      }
 +
 +      switch(o) {
 +      default:
 +              diag(n, "unknown op in cgen: %O", o);
 +              break;
 +
 +      case OAS:
 +              if(l->op == OBIT)
 +                      goto bitas;
 +              if(l->addable >= INDEXED) {
 +                      if(nn != Z || r->addable < INDEXED) {
 +                              regalloc(&nod, r, nn);
 +                              cgen(r, &nod);
 +                              gmove(&nod, l);
 +                              regfree(&nod);
 +                      } else
 +                              gmove(r, l);
 +                      break;
 +              }
 +              if(l->complex >= r->complex) {
 +                      reglcgen(&nod1, l, Z);
 +                      if(r->addable >= INDEXED) {
 +                              gmove(r, &nod1);
 +                              if(nn != Z)
 +                                      gmove(r, nn);
 +                              regfree(&nod1);
 +                              break;
 +                      }
 +                      regalloc(&nod, r, nn);
 +                      cgen(r, &nod);
 +              } else {
 +                      regalloc(&nod, r, nn);
 +                      cgen(r, &nod);
 +                      reglcgen(&nod1, l, Z);
 +              }
 +              gmove(&nod, &nod1);
 +              regfree(&nod);
 +              regfree(&nod1);
 +              break;
 +
 +      bitas:
 +              n = l->left;
 +              regalloc(&nod, r, nn);
 +              if(l->complex >= r->complex) {
 +                      reglcgen(&nod1, n, Z);
 +                      cgen(r, &nod);
 +              } else {
 +                      cgen(r, &nod);
 +                      reglcgen(&nod1, n, Z);
 +              }
 +              regalloc(&nod2, n, Z);
 +              gopcode(OAS, &nod1, Z, &nod2);
 +              bitstore(l, &nod, &nod1, &nod2, nn);
 +              break;
 +
 +      case OBIT:
 +              if(nn == Z) {
 +                      nullwarn(l, Z);
 +                      break;
 +              }
 +              bitload(n, &nod, Z, Z, nn);
 +              gopcode(OAS, &nod, Z, nn);
 +              regfree(&nod);
 +              break;
 +
 +      case OXOR:
 +              if(nn != Z)
 +              if(r->op == OCONST && r->vconst == -1){
 +                      cgen(l, nn);
 +                      gopcode(OCOM, nn, Z, nn);
 +                      break;
 +              }
 +
 +      case OADD:
 +      case OSUB:
 +      case OAND:
 +      case OOR:
 +      case OLSHR:
 +      case OASHL:
 +      case OASHR:
 +              /*
 +               * immediate operands
 +               */
 +              if(nn != Z &&
 +                 r->op == OCONST &&
 +                 !typefd[n->type->etype] &&
 +                 immconst(r)) {
 +                      cgen(l, nn);
 +                      if(r->vconst == 0)
 +                      if(o != OAND)
 +                              break;
 +                      if(nn != Z)
 +                              gopcode(o, r, Z, nn);
 +                      break;
 +              }
 +
 +      case OMUL:
 +      case OLMUL:
 +      case OLDIV:
 +      case OLMOD:
 +      case ODIV:
 +      case OMOD:
 +              if(nn == Z) {
 +                      nullwarn(l, r);
 +                      break;
 +              }
 +              if(o == OMUL || o == OLMUL) {
 +                      if(mulcon(n, nn))
 +                              break;
 +                      if(debug['M'])
 +                              print("%L multiply\n", n->lineno);
 +              }
 +              if(l->complex >= r->complex) {
 +                      regalloc(&nod, l, nn);
 +                      cgen(l, &nod);
 +                      regalloc(&nod1, l, Z);          /* note: l used for type, so shifts work! */
 +                      cgen(r, &nod1);
 +                      gopcode(o, &nod1, Z, &nod);
 +              } else {
 +                      regalloc(&nod, l, nn);          /* note: l used for type, so shifts work! */
 +                      cgen(r, &nod);
 +                      regalloc(&nod1, l, Z);
 +                      cgen(l, &nod1);
 +                      gopcode(o, &nod, &nod1, &nod);
 +              }
 +              gopcode(OAS, &nod, Z, nn);
 +              regfree(&nod);
 +              regfree(&nod1);
 +              break;
 +
 +      case OASLSHR:
 +      case OASASHL:
 +      case OASASHR:
 +      case OASAND:
 +      case OASADD:
 +      case OASSUB:
 +      case OASXOR:
 +      case OASOR:
 +              if(l->op == OBIT)
 +                      goto asbitop;
 +              if(r->op == OCONST &&
 +                 !typefd[n->type->etype] &&
 +                 immconst(r)) {
 +                      if(l->addable < INDEXED)
 +                              reglcgen(&nod2, l, Z);
 +                      else
 +                              nod2 = *l;
 +                      regalloc(&nod, l, nn);          /* note: l used for type, so shifts work! */
 +                      gopcode(OAS, &nod2, Z, &nod);
 +                      gopcode(o, r, Z, &nod);
 +                      gopcode(OAS, &nod, Z, &nod2);
 +      
 +                      regfree(&nod);
 +                      if(l->addable < INDEXED)
 +                              regfree(&nod2);
 +                      break;
 +              }
 +
 +      case OASLMUL:
 +      case OASLDIV:
 +      case OASLMOD:
 +      case OASMUL:
 +      case OASDIV:
 +      case OASMOD:
 +              if(l->op == OBIT)
 +                      goto asbitop;
 +              if(l->complex >= r->complex) {
 +                      if(l->addable < INDEXED)
 +                              reglcgen(&nod2, l, Z);
 +                      else
 +                              nod2 = *l;
 +                      regalloc(&nod, n, nn);
 +                      cgen(r, &nod);
 +              } else {
 +                      regalloc(&nod, n, nn);
 +                      cgen(r, &nod);
 +                      if(l->addable < INDEXED)
 +                              reglcgen(&nod2, l, Z);
 +                      else
 +                              nod2 = *l;
 +              }
 +              regalloc(&nod1, n, Z);
 +              gopcode(OAS, &nod2, Z, &nod1);
 +              if(nod1.type->etype != nod.type->etype){
 +                      regalloc(&nod3, &nod, Z);
 +                      gmove(&nod1, &nod3);
 +                      regfree(&nod1);
 +                      nod1 = nod3;
 +              }
 +              gopcode(o, &nod, &nod1, &nod);
 +              gmove(&nod, &nod2);
 +              if(nn != Z)
 +                      gmove(&nod, nn);
 +              regfree(&nod);
 +              regfree(&nod1);
 +              if(l->addable < INDEXED)
 +                      regfree(&nod2);
 +              break;
 +
 +      asbitop:
 +              regalloc(&nod4, n, nn);
 +              regalloc(&nod3, r, Z);
 +              if(l->complex >= r->complex) {
 +                      bitload(l, &nod, &nod1, &nod2, &nod4);
 +                      cgen(r, &nod3);
 +              } else {
 +                      cgen(r, &nod3);
 +                      bitload(l, &nod, &nod1, &nod2, &nod4);
 +              }
 +              gmove(&nod, &nod4);
 +              gopcode(n->op, &nod3, Z, &nod4);
 +              regfree(&nod3);
 +              gmove(&nod4, &nod);
 +              regfree(&nod4);
 +              bitstore(l, &nod, &nod1, &nod2, nn);
 +              break;
 +
 +      case OADDR:
 +              if(nn == Z) {
 +                      nullwarn(l, Z);
 +                      break;
 +              }
 +              lcgen(l, nn);
 +              break;
 +
 +      case OFUNC:
 +              if(l->complex >= FNX) {
 +                      if(l->op != OIND)
 +                              diag(n, "bad function call");
 +
-               if(nn != Z) {
-                       regret(&nod, n);
++                      regret(&nod, l->left, 0, 0);
 +                      cgen(l->left, &nod);
 +                      regsalloc(&nod1, l->left);
 +                      gopcode(OAS, &nod, Z, &nod1);
 +                      regfree(&nod);
 +
 +                      nod = *n;
 +                      nod.left = &nod2;
 +                      nod2 = *l;
 +                      nod2.left = &nod1;
 +                      nod2.complex = 1;
 +                      cgen(&nod, nn);
 +
 +                      return;
 +              }
 +              if(REGARG >= 0)
 +                      o = reg[REGARG];
 +              gargs(r, &nod, &nod1);
 +              gpcdata(PCDATA_ArgSize, curarg);
 +              if(l->addable < INDEXED) {
 +                      reglcgen(&nod, l, Z);
 +                      gopcode(OFUNC, Z, Z, &nod);
 +                      regfree(&nod);
 +              } else
 +                      gopcode(OFUNC, Z, Z, l);
 +              gpcdata(PCDATA_ArgSize, -1);
 +              if(REGARG>=0)
 +                      if(o != reg[REGARG])
 +                              reg[REGARG]--;
-               }
++              regret(&nod, n, l->type, 1); // update maxarg if nothing else
++              gpcdata(PCDATA_ArgSize, curarg);
++              gpcdata(PCDATA_ArgSize, -1);
++              if(nn != Z)
 +                      gopcode(OAS, &nod, Z, nn);
++              if(nod.op == OREGISTER)
 +                      regfree(&nod);
-                       regret(&nod, r);
 +              break;
 +
 +      case OIND:
 +              if(nn == Z) {
 +                      cgen(l, nn);
 +                      break;
 +              }
 +              regialloc(&nod, n, nn);
 +              r = l;
 +              while(r->op == OADD)
 +                      r = r->right;
 +              if(sconst(r)) {
 +                      v = r->vconst;
 +                      r->vconst = 0;
 +                      cgen(l, &nod);
 +                      nod.xoffset += v;
 +                      r->vconst = v;
 +              } else
 +                      cgen(l, &nod);
 +              regind(&nod, n);
 +              gopcode(OAS, &nod, Z, nn);
 +              regfree(&nod);
 +              break;
 +
 +      case OEQ:
 +      case ONE:
 +      case OLE:
 +      case OLT:
 +      case OGE:
 +      case OGT:
 +      case OLO:
 +      case OLS:
 +      case OHI:
 +      case OHS:
 +              if(nn == Z) {
 +                      nullwarn(l, r);
 +                      break;
 +              }
 +              boolgen(n, 1, nn);
 +              break;
 +
 +      case OANDAND:
 +      case OOROR:
 +              boolgen(n, 1, nn);
 +              if(nn == Z)
 +                      patch(p, pc);
 +              break;
 +
 +      case ONOT:
 +              if(nn == Z) {
 +                      nullwarn(l, Z);
 +                      break;
 +              }
 +              boolgen(n, 1, nn);
 +              break;
 +
 +      case OCOMMA:
 +              cgen(l, Z);
 +              cgen(r, nn);
 +              break;
 +
 +      case OCAST:
 +              if(nn == Z) {
 +                      nullwarn(l, Z);
 +                      break;
 +              }
 +              /*
 +               * convert from types l->n->nn
 +               */
 +              if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
 +                      /* both null, gen l->nn */
 +                      cgen(l, nn);
 +                      break;
 +              }
 +              regalloc(&nod, l, nn);
 +              cgen(l, &nod);
 +              regalloc(&nod1, n, &nod);
 +              gopcode(OAS, &nod, Z, &nod1);
 +              gopcode(OAS, &nod1, Z, nn);
 +              regfree(&nod1);
 +              regfree(&nod);
 +              break;
 +
 +      case ODOT:
 +              sugen(l, nodrat, l->type->width);
 +              if(nn != Z) {
 +                      warn(n, "non-interruptable temporary");
 +                      nod = *nodrat;
 +                      if(!r || r->op != OCONST) {
 +                              diag(n, "DOT and no offset");
 +                              break;
 +                      }
 +                      nod.xoffset += (int32)r->vconst;
 +                      nod.type = n->type;
 +                      cgen(&nod, nn);
 +              }
 +              break;
 +
 +      case OCOND:
 +              bcgen(l, 1);
 +              p1 = p;
 +              cgen(r->left, nn);
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              p1 = p;
 +              cgen(r->right, nn);
 +              patch(p1, pc);
 +              break;
 +
 +      case OPOSTINC:
 +      case OPOSTDEC:
 +              v = 1;
 +              if(l->type->etype == TIND)
 +                      v = l->type->link->width;
 +              if(o == OPOSTDEC)
 +                      v = -v;
 +              if(l->op == OBIT)
 +                      goto bitinc;
 +              if(nn == Z)
 +                      goto pre;
 +
 +              if(l->addable < INDEXED)
 +                      reglcgen(&nod2, l, Z);
 +              else
 +                      nod2 = *l;
 +
 +              regalloc(&nod, l, nn);
 +              gopcode(OAS, &nod2, Z, &nod);
 +              regalloc(&nod1, l, Z);
 +              if(typefd[l->type->etype]) {
 +                      regalloc(&nod3, l, Z);
 +                      if(v < 0) {
 +                              gopcode(OAS, nodfconst(-v), Z, &nod3);
 +                              gopcode(OSUB, &nod3, &nod, &nod1);
 +                      } else {
 +                              gopcode(OAS, nodfconst(v), Z, &nod3);
 +                              gopcode(OADD, &nod3, &nod, &nod1);
 +                      }
 +                      regfree(&nod3);
 +              } else
 +                      gopcode(OADD, nodconst(v), &nod, &nod1);
 +              gopcode(OAS, &nod1, Z, &nod2);
 +
 +              regfree(&nod);
 +              regfree(&nod1);
 +              if(l->addable < INDEXED)
 +                      regfree(&nod2);
 +              break;
 +
 +      case OPREINC:
 +      case OPREDEC:
 +              v = 1;
 +              if(l->type->etype == TIND)
 +                      v = l->type->link->width;
 +              if(o == OPREDEC)
 +                      v = -v;
 +              if(l->op == OBIT)
 +                      goto bitinc;
 +
 +      pre:
 +              if(l->addable < INDEXED)
 +                      reglcgen(&nod2, l, Z);
 +              else
 +                      nod2 = *l;
 +
 +              regalloc(&nod, l, nn);
 +              gopcode(OAS, &nod2, Z, &nod);
 +              if(typefd[l->type->etype]) {
 +                      regalloc(&nod3, l, Z);
 +                      if(v < 0) {
 +                              gopcode(OAS, nodfconst(-v), Z, &nod3);
 +                              gopcode(OSUB, &nod3, Z, &nod);
 +                      } else {
 +                              gopcode(OAS, nodfconst(v), Z, &nod3);
 +                              gopcode(OADD, &nod3, Z, &nod);
 +                      }
 +                      regfree(&nod3);
 +              } else
 +                      gopcode(OADD, nodconst(v), Z, &nod);
 +              gopcode(OAS, &nod, Z, &nod2);
 +              if(nn && l->op == ONAME)        /* in x=++i, emit USED(i) */
 +                      gins(ANOP, l, Z);
 +
 +              regfree(&nod);
 +              if(l->addable < INDEXED)
 +                      regfree(&nod2);
 +              break;
 +
 +      bitinc:
 +              if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
 +                      bitload(l, &nod, &nod1, &nod2, Z);
 +                      gopcode(OAS, &nod, Z, nn);
 +                      gopcode(OADD, nodconst(v), Z, &nod);
 +                      bitstore(l, &nod, &nod1, &nod2, Z);
 +                      break;
 +              }
 +              bitload(l, &nod, &nod1, &nod2, nn);
 +              gopcode(OADD, nodconst(v), Z, &nod);
 +              bitstore(l, &nod, &nod1, &nod2, nn);
 +              break;
 +      }
 +      cursafe = curs;
 +}
 +
 +void
 +reglcgen(Node *t, Node *n, Node *nn)
 +{
 +      Node *r;
 +      int32 v;
 +
 +      regialloc(t, n, nn);
 +      if(n->op == OIND) {
 +              r = n->left;
 +              while(r->op == OADD)
 +                      r = r->right;
 +              if(sconst(r)) {
 +                      v = r->vconst;
 +                      r->vconst = 0;
 +                      lcgen(n, t);
 +                      t->xoffset += v;
 +                      r->vconst = v;
 +                      regind(t, n);
 +                      return;
 +              }
 +      }
 +      lcgen(n, t);
 +      regind(t, n);
 +}
 +
 +void
 +lcgen(Node *n, Node *nn)
 +{
 +      Prog *p1;
 +      Node nod;
 +
 +      if(debug['g']) {
 +              prtree(nn, "lcgen lhs");
 +              prtree(n, "lcgen");
 +      }
 +      if(n == Z || n->type == T)
 +              return;
 +      if(nn == Z) {
 +              nn = &nod;
 +              regalloc(&nod, n, Z);
 +      }
 +      switch(n->op) {
 +      default:
 +              if(n->addable < INDEXED) {
 +                      diag(n, "unknown op in lcgen: %O", n->op);
 +                      break;
 +              }
 +              nod = *n;
 +              nod.op = OADDR;
 +              nod.left = n;
 +              nod.right = Z;
 +              nod.type = types[TIND];
 +              gopcode(OAS, &nod, Z, nn);
 +              break;
 +
 +      case OCOMMA:
 +              cgen(n->left, n->left);
 +              lcgen(n->right, nn);
 +              break;
 +
 +      case OIND:
 +              cgen(n->left, nn);
 +              break;
 +
 +      case OCOND:
 +              bcgen(n->left, 1);
 +              p1 = p;
 +              lcgen(n->right->left, nn);
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              p1 = p;
 +              lcgen(n->right->right, nn);
 +              patch(p1, pc);
 +              break;
 +      }
 +}
 +
 +void
 +bcgen(Node *n, int true)
 +{
 +
 +      if(n->type == T)
 +              gbranch(OGOTO);
 +      else
 +              boolgen(n, true, Z);
 +}
 +
 +void
 +boolgen(Node *n, int true, Node *nn)
 +{
 +      int o;
 +      Prog *p1, *p2;
 +      Node *l, *r, nod, nod1;
 +      int32 curs;
 +
 +      if(debug['g']) {
 +              prtree(nn, "boolgen lhs");
 +              prtree(n, "boolgen");
 +      }
 +      curs = cursafe;
 +      l = n->left;
 +      r = n->right;
 +      switch(n->op) {
 +
 +      default:
 +              if(n->op == OCONST) {
 +                      o = vconst(n);
 +                      if(!true)
 +                              o = !o;
 +                      gbranch(OGOTO);
 +                      if(o) {
 +                              p1 = p;
 +                              gbranch(OGOTO);
 +                              patch(p1, pc);
 +                      }
 +                      goto com;
 +              }
 +              regalloc(&nod, n, nn);
 +              cgen(n, &nod);
 +              o = ONE;
 +              if(true)
 +                      o = comrel[relindex(o)];
 +              if(typefd[n->type->etype]) {
 +                      nodreg(&nod1, n, NREG+FREGZERO);
 +                      gopcode(o, &nod, Z, &nod1);
 +              } else
 +                      gopcode(o, &nod, Z, nodconst(0));
 +              regfree(&nod);
 +              goto com;
 +
 +      case OCOMMA:
 +              cgen(l, Z);
 +              boolgen(r, true, nn);
 +              break;
 +
 +      case ONOT:
 +              boolgen(l, !true, nn);
 +              break;
 +
 +      case OCOND:
 +              bcgen(l, 1);
 +              p1 = p;
 +              bcgen(r->left, true);
 +              p2 = p;
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              p1 = p;
 +              bcgen(r->right, !true);
 +              patch(p2, pc);
 +              p2 = p;
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              patch(p2, pc);
 +              goto com;
 +
 +      case OANDAND:
 +              if(!true)
 +                      goto caseor;
 +
 +      caseand:
 +              bcgen(l, true);
 +              p1 = p;
 +              bcgen(r, !true);
 +              p2 = p;
 +              patch(p1, pc);
 +              gbranch(OGOTO);
 +              patch(p2, pc);
 +              goto com;
 +
 +      case OOROR:
 +              if(!true)
 +                      goto caseand;
 +
 +      caseor:
 +              bcgen(l, !true);
 +              p1 = p;
 +              bcgen(r, !true);
 +              p2 = p;
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              patch(p2, pc);
 +              goto com;
 +
 +      case OEQ:
 +      case ONE:
 +      case OLE:
 +      case OLT:
 +      case OGE:
 +      case OGT:
 +      case OHI:
 +      case OHS:
 +      case OLO:
 +      case OLS:
 +              o = n->op;
 +              if(true)
 +                      o = comrel[relindex(o)];
 +              if(l->complex >= FNX && r->complex >= FNX) {
++                      regret(&nod, r, 0, 0);
 +                      cgen(r, &nod);
 +                      regsalloc(&nod1, r);
 +                      gopcode(OAS, &nod, Z, &nod1);
 +                      regfree(&nod);
 +                      nod = *n;
 +                      nod.right = &nod1;
 +                      boolgen(&nod, true, nn);
 +                      break;
 +              }
 +              if(sconst(r)) {
 +                      regalloc(&nod, l, nn);
 +                      cgen(l, &nod);
 +                      gopcode(o, &nod, Z, r);
 +                      regfree(&nod);
 +                      goto com;
 +              }
 +              if(l->complex >= r->complex) {
 +                      regalloc(&nod1, l, nn);
 +                      cgen(l, &nod1);
 +                      regalloc(&nod, r, Z);
 +                      cgen(r, &nod);
 +              } else {
 +                      regalloc(&nod, r, nn);
 +                      cgen(r, &nod);
 +                      regalloc(&nod1, l, Z);
 +                      cgen(l, &nod1);
 +              }
 +              gopcode(o, &nod1, Z, &nod);
 +              regfree(&nod);
 +              regfree(&nod1);
 +
 +      com:
 +              if(nn != Z) {
 +                      p1 = p;
 +                      gopcode(OAS, nodconst(1L), Z, nn);
 +                      gbranch(OGOTO);
 +                      p2 = p;
 +                      patch(p1, pc);
 +                      gopcode(OAS, nodconst(0L), Z, nn);
 +                      patch(p2, pc);
 +              }
 +              break;
 +      }
 +      cursafe = curs;
 +}
 +
 +void
 +sugen(Node *n, Node *nn, int32 w)
 +{
 +      Prog *p1;
 +      Node nod0, nod1, nod2, nod3, nod4, *l, *r;
 +      Type *t;
 +      int32 pc1;
 +      int i, m, c;
 +
 +      if(n == Z || n->type == T)
 +              return;
 +      if(debug['g']) {
 +              prtree(nn, "sugen lhs");
 +              prtree(n, "sugen");
 +      }
 +      if(nn == nodrat)
 +              if(w > nrathole)
 +                      nrathole = w;
 +      switch(n->op) {
 +      case OIND:
 +              if(nn == Z) {
 +                      nullwarn(n->left, Z);
 +                      break;
 +              }
 +
 +      default:
 +              goto copy;
 +
 +      case OCONST:
 +              if(n->type && typev[n->type->etype]) {
 +                      if(nn == Z) {
 +                              nullwarn(n->left, Z);
 +                              break;
 +                      }
 +
 +                      t = nn->type;
 +                      nn->type = types[TLONG];
 +                      reglcgen(&nod1, nn, Z);
 +                      nn->type = t;
 +
 +                      if(align(0, types[TCHAR], Aarg1, nil))  /* isbigendian */
 +                              gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
 +                      else
 +                              gopcode(OAS, nod32const(n->vconst), Z, &nod1);
 +                      nod1.xoffset += SZ_LONG;
 +                      if(align(0, types[TCHAR], Aarg1, nil))  /* isbigendian */
 +                              gopcode(OAS, nod32const(n->vconst), Z, &nod1);
 +                      else
 +                              gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
 +
 +                      regfree(&nod1);
 +                      break;
 +              }
 +              goto copy;
 +
 +      case ODOT:
 +              l = n->left;
 +              sugen(l, nodrat, l->type->width);
 +              if(nn != Z) {
 +                      warn(n, "non-interruptable temporary");
 +                      nod1 = *nodrat;
 +                      r = n->right;
 +                      if(!r || r->op != OCONST) {
 +                              diag(n, "DOT and no offset");
 +                              break;
 +                      }
 +                      nod1.xoffset += (int32)r->vconst;
 +                      nod1.type = n->type;
 +                      sugen(&nod1, nn, w);
 +              }
 +              break;
 +
 +      case OSTRUCT:
 +              /*
 +               * rewrite so lhs has no side effects
 +               */
 +              if(nn != Z && side(nn)) {
 +                      nod1 = *n;
 +                      nod1.type = typ(TIND, n->type);
 +                      regalloc(&nod2, &nod1, Z);
 +                      lcgen(nn, &nod2);
 +                      regsalloc(&nod0, &nod1);
 +                      gopcode(OAS, &nod2, Z, &nod0);
 +                      regfree(&nod2);
 +
 +                      nod1 = *n;
 +                      nod1.op = OIND;
 +                      nod1.left = &nod0;
 +                      nod1.right = Z;
 +                      nod1.complex = 1;
 +
 +                      sugen(n, &nod1, w);
 +                      return;
 +              }
 +
 +              r = n->left;
 +              for(t = n->type->link; t != T; t = t->down) {
 +                      l = r;
 +                      if(r->op == OLIST) {
 +                              l = r->left;
 +                              r = r->right;
 +                      }
 +                      if(nn == Z) {
 +                              cgen(l, nn);
 +                              continue;
 +                      }
 +                      /*
 +                       * hand craft *(&nn + o) = l
 +                       */
 +                      nod0 = znode;
 +                      nod0.op = OAS;
 +                      nod0.type = t;
 +                      nod0.left = &nod1;
 +                      nod0.right = l;
 +
 +                      nod1 = znode;
 +                      nod1.op = OIND;
 +                      nod1.type = t;
 +                      nod1.left = &nod2;
 +
 +                      nod2 = znode;
 +                      nod2.op = OADD;
 +                      nod2.type = typ(TIND, t);
 +                      nod2.left = &nod3;
 +                      nod2.right = &nod4;
 +
 +                      nod3 = znode;
 +                      nod3.op = OADDR;
 +                      nod3.type = nod2.type;
 +                      nod3.left = nn;
 +
 +                      nod4 = znode;
 +                      nod4.op = OCONST;
 +                      nod4.type = nod2.type;
 +                      nod4.vconst = t->offset;
 +
 +                      ccom(&nod0);
 +                      acom(&nod0);
 +                      xcom(&nod0);
 +                      nod0.addable = 0;
 +
 +                      /* prtree(&nod0, "hand craft"); /* */
 +                      cgen(&nod0, Z);
 +              }
 +              break;
 +
 +      case OAS:
 +              if(nn == Z) {
 +                      if(n->addable < INDEXED)
 +                              sugen(n->right, n->left, w);
 +                      break;
 +              }
 +              /* BOTCH -- functions can clobber rathole */
 +              sugen(n->right, nodrat, w);
 +              warn(n, "non-interruptable temporary");
 +              sugen(nodrat, n->left, w);
 +              sugen(nodrat, nn, w);
 +              break;
 +
 +      case OFUNC:
++              if(!hasdotdotdot(n->left->type)) {
++                      cgen(n, Z);
++                      if(nn != Z) {
++                              curarg -= n->type->width;
++                              regret(&nod1, n, n->left->type, 1);
++                              if(nn->complex >= FNX) {
++                                      regsalloc(&nod2, n);
++                                      cgen(&nod1, &nod2);
++                                      nod1 = nod2;
++                              }
++                              cgen(&nod1, nn);
++                      }
++                      break;
++              }
 +              if(nn == Z) {
 +                      sugen(n, nodrat, w);
 +                      break;
 +              }
 +              if(nn->op != OIND) {
 +                      nn = new1(OADDR, nn, Z);
 +                      nn->type = types[TIND];
 +                      nn->addable = 0;
 +              } else
 +                      nn = nn->left;
 +              n = new(OFUNC, n->left, new(OLIST, nn, n->right));
 +              n->type = types[TVOID];
 +              n->left->type = types[TVOID];
 +              cgen(n, Z);
 +              break;
 +
 +      case OCOND:
 +              bcgen(n->left, 1);
 +              p1 = p;
 +              sugen(n->right->left, nn, w);
 +              gbranch(OGOTO);
 +              patch(p1, pc);
 +              p1 = p;
 +              sugen(n->right->right, nn, w);
 +              patch(p1, pc);
 +              break;
 +
 +      case OCOMMA:
 +              cgen(n->left, Z);
 +              sugen(n->right, nn, w);
 +              break;
 +      }
 +      return;
 +
 +copy:
 +      if(nn == Z)
 +              return;
 +      if(n->complex >= FNX && nn->complex >= FNX) {
 +              t = nn->type;
 +              nn->type = types[TLONG];
 +              regialloc(&nod1, nn, Z);
 +              lcgen(nn, &nod1);
 +              regsalloc(&nod2, nn);
 +              nn->type = t;
 +
 +              gopcode(OAS, &nod1, Z, &nod2);
 +              regfree(&nod1);
 +
 +              nod2.type = typ(TIND, t);
 +
 +              nod1 = nod2;
 +              nod1.op = OIND;
 +              nod1.left = &nod2;
 +              nod1.right = Z;
 +              nod1.complex = 1;
 +              nod1.type = t;
 +
 +              sugen(n, &nod1, w);
 +              return;
 +      }
 +
 +      if(n->complex > nn->complex) {
 +              t = n->type;
 +              n->type = types[TLONG];
 +              reglcgen(&nod1, n, Z);
 +              n->type = t;
 +
 +              t = nn->type;
 +              nn->type = types[TLONG];
 +              reglcgen(&nod2, nn, Z);
 +              nn->type = t;
 +      } else {
 +              t = nn->type;
 +              nn->type = types[TLONG];
 +              reglcgen(&nod2, nn, Z);
 +              nn->type = t;
 +
 +              t = n->type;
 +              n->type = types[TLONG];
 +              reglcgen(&nod1, n, Z);
 +              n->type = t;
 +      }
 +
 +      w /= SZ_LONG;
 +      if(w <= 5) {
 +              layout(&nod1, &nod2, w, 0, Z);
 +              goto out;
 +      }
 +
 +      /*
 +       * minimize space for unrolling loop
 +       * 3,4,5 times. (6 or more is never minimum)
 +       * if small structure, try 2 also.
 +       */
 +      c = 0; /* set */
 +      m = 100;
 +      i = 3;
 +      if(w <= 15)
 +              i = 2;
 +      for(; i<=5; i++)
 +              if(i + w%i <= m) {
 +                      c = i;
 +                      m = c + w%c;
 +              }
 +
 +      regalloc(&nod3, &regnode, Z);
 +      layout(&nod1, &nod2, w%c, w/c, &nod3);
 +      
 +      pc1 = pc;
 +      layout(&nod1, &nod2, c, 0, Z);
 +
 +      gopcode(OSUB, nodconst(1L), Z, &nod3);
 +      nod1.op = OREGISTER;
 +      gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
 +      nod2.op = OREGISTER;
 +      gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
 +      
 +      gopcode(OGT, &nod3, Z, nodconst(0));
 +      patch(p, pc1);
 +
 +      regfree(&nod3);
 +out:
 +      regfree(&nod1);
 +      regfree(&nod2);
 +}
 +
 +void
 +layout(Node *f, Node *t, int c, int cv, Node *cn)
 +{
 +      Node t1, t2;
 +
 +      while(c > 3) {
 +              layout(f, t, 2, 0, Z);
 +              c -= 2;
 +      }
 +
 +      regalloc(&t1, &regnode, Z);
 +      regalloc(&t2, &regnode, Z);
 +      if(c > 0) {
 +              gopcode(OAS, f, Z, &t1);
 +              f->xoffset += SZ_LONG;
 +      }
 +      if(cn != Z)
 +              gopcode(OAS, nodconst(cv), Z, cn);
 +      if(c > 1) {
 +              gopcode(OAS, f, Z, &t2);
 +              f->xoffset += SZ_LONG;
 +      }
 +      if(c > 0) {
 +              gopcode(OAS, &t1, Z, t);
 +              t->xoffset += SZ_LONG;
 +      }
 +      if(c > 2) {
 +              gopcode(OAS, f, Z, &t1);
 +              f->xoffset += SZ_LONG;
 +      }
 +      if(c > 1) {
 +              gopcode(OAS, &t2, Z, t);
 +              t->xoffset += SZ_LONG;
 +      }
 +      if(c > 2) {
 +              gopcode(OAS, &t1, Z, t);
 +              t->xoffset += SZ_LONG;
 +      }
 +      regfree(&t1);
 +      regfree(&t2);
 +}
diff --cc src/cmd/9c/gc.h
index 82204902b78b4347d6007d0c8acd35db277056cf,0000000000000000000000000000000000000000..fbe5099fe83717e9b15570c5e1a69bc9d94324cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,351 -1,0 +1,350 @@@
- EXTERN        int     retok;
 +// cmd/9c/gc.h from Vita Nuova.
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include      <u.h>
 +#include      "../cc/cc.h"
 +#include      "../9l/9.out.h"
 +
 +/*
 + * 9c/powerpc64
 + */
 +#define       SZ_CHAR         1
 +#define       SZ_SHORT        2
 +#define       SZ_INT          4
 +#define       SZ_LONG         4
 +#define       SZ_IND          8
 +#define       SZ_FLOAT        4
 +#define       SZ_VLONG        8
 +#define       SZ_DOUBLE       8
 +#define       FNX             100
 +
 +typedef       struct  Case    Case;
 +typedef       struct  C1      C1;
 +typedef       struct  Multab  Multab;
 +typedef       struct  Hintab  Hintab;
 +typedef       struct  Reg     Reg;
 +typedef       struct  Rgn     Rgn;
 +
 +#define       A       ((Adr*)0)
 +
 +#define       INDEXED 9
 +#define       P       ((Prog*)0)
 +
 +struct        Case
 +{
 +      Case*   link;
 +      vlong   val;
 +      int32   label;
 +      char    def;
 +      char isv;
 +};
 +#define       C       ((Case*)0)
 +
 +struct        C1
 +{
 +      vlong   val;
 +      int32   label;
 +};
 +
 +struct        Multab
 +{
 +      int32   val;
 +      char    code[20];
 +};
 +
 +struct        Hintab
 +{
 +      ushort  val;
 +      char    hint[10];
 +};
 +
 +struct        Reg
 +{
 +      int32   pc;
 +      int32   rpo;            /* reverse post ordering */
 +
 +      Bits    set;
 +      Bits    use1;
 +      Bits    use2;
 +
 +      Bits    refbehind;
 +      Bits    refahead;
 +      Bits    calbehind;
 +      Bits    calahead;
 +      Bits    regdiff;
 +      Bits    act;
 +
 +      int32   regu;
 +      int32   loop;           /* could be shorter */
 +
 +      union
 +      {
 +              Reg*    log5;
 +              int32   active;
 +      };
 +      Reg*    p1;
 +      Reg*    p2;
 +      Reg*    p2link;
 +      Reg*    s1;
 +      Reg*    s2;
 +      Reg*    link;
 +      Prog*   prog;
 +};
 +#define       R       ((Reg*)0)
 +
 +#define       NRGN    600
 +struct        Rgn
 +{
 +      Reg*    enter;
 +      short   cost;
 +      short   varno;
 +      short   regno;
 +};
 +
 +EXTERN        int32   breakpc;
 +EXTERN        int32   nbreak;
 +EXTERN        Case*   cases;
 +EXTERN        Node    constnode;
 +EXTERN        Node    fconstnode;
 +EXTERN        Node    vconstnode;
 +EXTERN        int32   continpc;
 +EXTERN        int32   curarg;
 +EXTERN        int32   cursafe;
 +EXTERN        Prog*   lastp;
 +extern        int     hintabsize;
 +EXTERN        int32   maxargsafe;
 +EXTERN        Multab  multab[20];
 +EXTERN        int     mnstring;
- vlong argsize(void);
 +EXTERN        Node*   nodrat;
 +EXTERN        Node*   nodret;
 +EXTERN        Node*   nodsafe;
 +EXTERN        int32   nrathole;
 +EXTERN        int32   nstring;
 +EXTERN        Prog*   p;
 +EXTERN        int32   pc;
 +EXTERN        Node    regnode;
 +EXTERN        Node    qregnode;
 +EXTERN        char    string[NSNAME];
 +EXTERN        Sym*    symrathole;
 +EXTERN        Node    znode;
 +EXTERN        Prog    zprog;
 +EXTERN        int     reg[NREG+NREG];
 +EXTERN        int32   exregoffset;
 +EXTERN        int32   exfregoffset;
 +EXTERN        uchar   typechlpv[NTYPE];
 +
 +#define       BLOAD(r)        band(bnot(r->refbehind), r->refahead)
 +#define       BSTORE(r)       band(bnot(r->calbehind), r->calahead)
 +#define       LOAD(r)         (~r->refbehind.b[z] & r->refahead.b[z])
 +#define       STORE(r)        (~r->calbehind.b[z] & r->calahead.b[z])
 +
 +#define       bset(a,n)       ((a).b[(n)/32]&(1L<<(n)%32))
 +
 +#define       CLOAD   5
 +#define       CREF    5
 +#define       CINF    1000
 +#define       LOOP    3
 +
 +EXTERN        Rgn     region[NRGN];
 +EXTERN        Rgn*    rgp;
 +EXTERN        int     nregion;
 +EXTERN        int     nvar;
 +
 +EXTERN        Bits    externs;
 +EXTERN        Bits    params;
 +EXTERN        Bits    consts;
 +EXTERN        Bits    addrs;
 +
 +EXTERN        int32   regbits;
 +EXTERN        int32   exregbits;
 +
 +EXTERN        int     change;
 +EXTERN        int     suppress;
 +
 +EXTERN        Reg*    firstr;
 +EXTERN        Reg*    lastr;
 +EXTERN        Reg     zreg;
 +EXTERN        Reg*    freer;
 +EXTERN        Var     var[NVAR];
 +EXTERN        int32*  idom;
 +EXTERN        Reg**   rpo2r;
 +EXTERN        int32   maxnr;
 +
 +#define       R0ISZERO        (debug['0']==0)
 +
 +extern        char*   anames[];
 +extern        Hintab  hintab[];
 +
 +/*
 + * sgen.c
 + */
 +void  codgen(Node*, Node*);
 +void  gen(Node*);
 +void  usedset(Node*, int);
 +void  noretval(int);
 +void  xcom(Node*);
 +int   bcomplex(Node*, Node*);
 +Prog* gtext(Sym*, int32);
- void  regret(Node*, Node*);
++vlong argsize(int);
 +
 +/*
 + * cgen.c
 + */
 +void  cgen(Node*, Node*);
 +void  reglcgen(Node*, Node*, Node*);
 +void  lcgen(Node*, Node*);
 +void  bcgen(Node*, int);
 +void  boolgen(Node*, int, Node*);
 +void  sugen(Node*, Node*, int32);
 +void  layout(Node*, Node*, int, int, Node*);
 +
 +/*
 + * txt.c
 + */
 +void  ginit(void);
 +void  gclean(void);
 +void  nextpc(void);
 +void  gargs(Node*, Node*, Node*);
 +void  garg1(Node*, Node*, Node*, int, Node**);
 +Node* nodconst(int32);
 +Node* nod32const(vlong);
 +Node* nodfconst(double);
 +Node* nodgconst(vlong v, Type *t);
 +void  nodreg(Node*, Node*, int);
++void  regret(Node*, Node*, Type*, int);
 +void  regalloc(Node*, Node*, Node*);
 +void  regfree(Node*);
 +void  regialloc(Node*, Node*, Node*);
 +void  regsalloc(Node*, Node*);
 +void  regaalloc1(Node*, Node*);
 +void  regaalloc(Node*, Node*);
 +void  regind(Node*, Node*);
 +void  gprep(Node*, Node*);
 +void  raddr(Node*, Prog*);
 +void  naddr(Node*, Addr*);
 +void  gmove(Node*, Node*);
 +void  gins(int a, Node*, Node*);
 +void  gopcode(int, Node*, Node*, Node*);
 +int   samaddr(Node*, Node*);
 +void  gbranch(int);
 +int   immconst(Node*);
 +void  patch(Prog*, int32);
 +int   sconst(Node*);
 +int   sval(int32);
 +int   uconst(Node*);
 +void  gpseudo(int, Sym*, Node*);
 +void  gprefetch(Node*);
 +void  gpcdata(int, int);
 +
 +/*
 + * swt.c
 + */
 +int   swcmp(const void*, const void*);
 +void  doswit(Node*);
 +void  swit1(C1*, int, int32, Node*);
 +void  swit2(C1*, int, int32, Node*, Node*);
 +void  newcase(void);
 +void  bitload(Node*, Node*, Node*, Node*, Node*);
 +void  bitstore(Node*, Node*, Node*, Node*, Node*);
 +int32 outstring(char*, int32);
 +int   mulcon(Node*, Node*);
 +Multab*       mulcon0(Node*, int32);
 +int   mulcon1(Node*, int32, Node*);
 +void  nullwarn(Node*, Node*);
 +void  sextern(Sym*, Node*, int32, int32);
 +void  gextern(Sym*, Node*, int32, int32);
 +void  outcode(void);
 +
 +/*
 + * list
 + */
 +void  listinit(void);
 +int   Pconv(Fmt*);
 +int   Aconv(Fmt*);
 +int   Dconv(Fmt*);
 +int   Sconv(Fmt*);
 +int   Nconv(Fmt*);
 +int   Bconv(Fmt*);
 +
 +/*
 + * reg.c
 + */
 +Reg*  rega(void);
 +int   rcmp(const void*, const void*);
 +void  regopt(Prog*);
 +void  addmove(Reg*, int, int, int);
 +Bits  mkvar(Addr*, int);
 +void  prop(Reg*, Bits, Bits);
 +void  loopit(Reg*, int32);
 +void  synch(Reg*, Bits);
 +uint32        allreg(uint32, Rgn*);
 +void  paint1(Reg*, int);
 +uint32        paint2(Reg*, int);
 +void  paint3(Reg*, int, int32, int);
 +void  addreg(Addr*, int);
 +
 +/*
 + * peep.c
 + */
 +void  peep(void);
 +void  excise(Reg*);
 +Reg*  uniqp(Reg*);
 +Reg*  uniqs(Reg*);
 +int   regtyp(Addr*);
 +int   regzer(Addr*);
 +int   anyvar(Addr*);
 +int   subprop(Reg*);
 +int   copyprop(Reg*);
 +int   copy1(Addr*, Addr*, Reg*, int);
 +int   copyu(Prog*, Addr*, Addr*);
 +
 +int   copyas(Addr*, Addr*);
 +int   copyau(Addr*, Addr*);
 +int   copyau1(Prog*, Addr*);
 +int   copysub(Addr*, Addr*, Addr*, int);
 +int   copysub1(Prog*, Addr*, Addr*, int);
 +
 +int32 RtoB(int);
 +int32 FtoB(int);
 +int   BtoR(int32);
 +int   BtoF(int32);
 +
 +/*
 + * com64.c
 + */
 +int   com64(Node*);
 +void  com64init(void);
 +void  bool64(Node*);
 +
 +#pragma       varargck        type    "A"     int
 +#pragma       varargck        type    "B"     Bits
 +#pragma       varargck        type    "D"     Addr*
 +#pragma       varargck        type    "N"     Addr*
 +#pragma       varargck        type    "P"     Prog*
 +#pragma       varargck        type    "S"     char*
index 25f0438e58b41d808eaa11c9de193ca9b03f556a,0000000000000000000000000000000000000000..b03c17267d46208dcaa798ba5f1cf5d4cc805fe7
mode 100644,000000..100644
--- /dev/null
@@@ -1,291 -1,0 +1,291 @@@
-       v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff);
 +// cmd/9c/sgen.c from Vita Nuova.
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include "gc.h"
 +
 +Prog*
 +gtext(Sym *s, int32 stkoff)
 +{
 +      vlong v;
 +
++      v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
 +      if((textflag & NOSPLIT) && stkoff >= 128)
 +              yyerror("stack frame too large for NOSPLIT function");
 +
 +      gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
 +      return p;
 +}
 +
 +
 +void
 +noretval(int n)
 +{
 +
 +      if(n & 1) {
 +              gins(ANOP, Z, Z);
 +              p->to.type = D_REG;
 +              p->to.reg = REGRET;
 +      }
 +      if(n & 2) {
 +              gins(ANOP, Z, Z);
 +              p->to.type = D_FREG;
 +              p->to.reg = FREGRET;
 +      }
 +}
 +
 +/*
 + *    calculate addressability as follows
 + *            CONST ==> 20            $value
 + *            NAME ==> 10             name
 + *            REGISTER ==> 11         register
 + *            INDREG ==> 12           *[(reg)+offset]
 + *            &10 ==> 2               $name
 + *            ADD(2, 20) ==> 2        $name+offset
 + *            ADD(3, 20) ==> 3        $(reg)+offset
 + *            &12 ==> 3               $(reg)+offset
 + *            *11 ==> 11              ??
 + *            *2 ==> 10               name
 + *            *3 ==> 12               *(reg)+offset
 + *    calculate complexity (number of registers)
 + */
 +void
 +xcom(Node *n)
 +{
 +      Node *l, *r;
 +      int v;
 +
 +      if(n == Z)
 +              return;
 +      l = n->left;
 +      r = n->right;
 +      n->addable = 0;
 +      n->complex = 0;
 +      switch(n->op) {
 +      case OCONST:
 +              n->addable = 20;
 +              return;
 +
 +      case OREGISTER:
 +              n->addable = 11;
 +              return;
 +
 +      case OINDREG:
 +              n->addable = 12;
 +              return;
 +
 +      case ONAME:
 +              n->addable = 10;
 +              return;
 +
 +      case OADDR:
 +              xcom(l);
 +              if(l->addable == 10)
 +                      n->addable = 2;
 +              if(l->addable == 12)
 +                      n->addable = 3;
 +              break;
 +
 +      case OIND:
 +              xcom(l);
 +              if(l->addable == 11)
 +                      n->addable = 12;
 +              if(l->addable == 3)
 +                      n->addable = 12;
 +              if(l->addable == 2)
 +                      n->addable = 10;
 +              break;
 +
 +      case OADD:
 +              xcom(l);
 +              xcom(r);
 +              if(l->addable == 20) {
 +                      if(r->addable == 2)
 +                              n->addable = 2;
 +                      if(r->addable == 3)
 +                              n->addable = 3;
 +              }
 +              if(r->addable == 20) {
 +                      if(l->addable == 2)
 +                              n->addable = 2;
 +                      if(l->addable == 3)
 +                              n->addable = 3;
 +              }
 +              break;
 +
 +      case OASMUL:
 +      case OASLMUL:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OASASHL;
 +                      r->vconst = v;
 +                      r->type = types[TINT];
 +              }
 +              break;
 +
 +      case OMUL:
 +      case OLMUL:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OASHL;
 +                      r->vconst = v;
 +                      r->type = types[TINT];
 +              }
 +              v = vlog(l);
 +              if(v >= 0) {
 +                      n->op = OASHL;
 +                      n->left = r;
 +                      n->right = l;
 +                      r = l;
 +                      l = n->left;
 +                      r->vconst = v;
 +                      r->type = types[TINT];
 +                      simplifyshift(n);
 +              }
 +              break;
 +
 +      case OASLDIV:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OASLSHR;
 +                      r->vconst = v;
 +                      r->type = types[TINT];
 +              }
 +              break;
 +
 +      case OLDIV:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OLSHR;
 +                      r->vconst = v;
 +                      r->type = types[TINT];
 +                      simplifyshift(n);
 +              }
 +              break;
 +
 +      case OASLMOD:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OASAND;
 +                      r->vconst--;
 +              }
 +              break;
 +
 +      case OLMOD:
 +              xcom(l);
 +              xcom(r);
 +              v = vlog(r);
 +              if(v >= 0) {
 +                      n->op = OAND;
 +                      r->vconst--;
 +              }
 +              break;
 +
 +      case OLSHR:
 +      case OASHL:
 +      case OASHR:
 +              xcom(l);
 +              xcom(r);
 +              simplifyshift(n);
 +              break;
 +
 +      default:
 +              if(l != Z)
 +                      xcom(l);
 +              if(r != Z)
 +                      xcom(r);
 +              break;
 +      }
 +      if(n->addable >= 10)
 +              return;
 +      if(l != Z)
 +              n->complex = l->complex;
 +      if(r != Z) {
 +              if(r->complex == n->complex)
 +                      n->complex = r->complex+1;
 +              else
 +              if(r->complex > n->complex)
 +                      n->complex = r->complex;
 +      }
 +      if(n->complex == 0)
 +              n->complex++;
 +
 +//    if(com64(n))
 +//            return;
 +
 +      switch(n->op) {
 +
 +      case OFUNC:
 +              n->complex = FNX;
 +              break;
 +
 +      case OEQ:
 +      case ONE:
 +      case OLE:
 +      case OLT:
 +      case OGE:
 +      case OGT:
 +      case OHI:
 +      case OHS:
 +      case OLO:
 +      case OLS:
 +              /*
 +               * immediate operators, make const on right
 +               */
 +              if(l->op == OCONST) {
 +                      n->left = r;
 +                      n->right = l;
 +                      n->op = invrel[relindex(n->op)];
 +              }
 +              break;
 +
 +      case OADD:
 +      case OXOR:
 +      case OAND:
 +      case OOR:
 +              /*
 +               * immediate operators, make const on right
 +               */
 +              if(l->op == OCONST) {
 +                      n->left = r;
 +                      n->right = l;
 +              }
 +              break;
 +      }
 +}
 +
index 83058e7ab9b7b82dd1aab206a6935908983d2b37,0000000000000000000000000000000000000000..a63db60b27949aab50f731a22c8e879dbc0b3ce6
mode 100644,000000..100644
--- /dev/null
@@@ -1,404 -1,0 +1,407 @@@
-       int w;
 +// cmd/9c/swt.c from Vita Nuova.
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include "gc.h"
 +
 +void
 +swit1(C1 *q, int nc, int32 def, Node *n)
 +{
 +      Node tn, nod;
 +
 +      regalloc(&nod, n, Z);
 +      /* always signed */
 +      if(typev[n->type->etype])
 +              nod.type = types[TVLONG];
 +      else
 +              nod.type = types[TLONG];
 +      cgen(n, &nod);
 +      regalloc(&tn, &regnode, Z);
 +      swit2(q, nc, def, &nod, &tn);
 +      regfree(&tn);
 +      regfree(&nod);
 +}
 +
 +void
 +swit2(C1 *q, int nc, int32 def, Node *n, Node *tn)
 +{
 +      C1 *r;
 +      int i;
 +      Prog *sp;
 +
 +      if(nc < 5) {
 +              for(i=0; i<nc; i++) {
 +                      if(sval(q->val)) {
 +                              gopcode(OEQ, n, Z, nodconst(q->val));
 +                      } else {
 +                              gopcode(OSUB, nodconst(q->val), n, tn);
 +                              gopcode(OEQ, tn, Z, nodconst(0));
 +                      }
 +                      patch(p, q->label);
 +                      q++;
 +              }
 +              gbranch(OGOTO);
 +              patch(p, def);
 +              return;
 +      }
 +      i = nc / 2;
 +      r = q+i;
 +      if(sval(r->val)) {
 +              gopcode(OGT, n, Z, nodconst(r->val));
 +              sp = p;
 +      } else {
 +              gopcode(OSUB, nodconst(r->val), n, tn);
 +              gopcode(OGT, tn, Z, nodconst(0));
 +              sp = p;
 +      }
 +      gbranch(OGOTO);
 +      p->as = ABEQ;
 +      patch(p, r->label);
 +      swit2(q, i, def, n, tn);
 +
 +      patch(sp, pc);
 +      swit2(r+1, nc-i-1, def, n, tn);
 +}
 +
 +void
 +bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
 +{
 +      int sh;
 +      int32 v;
 +      Node *l;
 +
 +      /*
 +       * n1 gets adjusted/masked value
 +       * n2 gets address of cell
 +       * n3 gets contents of cell
 +       */
 +      l = b->left;
 +      if(n2 != Z) {
 +              regalloc(n1, l, nn);
 +              reglcgen(n2, l, Z);
 +              regalloc(n3, l, Z);
 +              gopcode(OAS, n2, Z, n3);
 +              gopcode(OAS, n3, Z, n1);
 +      } else {
 +              regalloc(n1, l, nn);
 +              cgen(l, n1);
 +      }
 +      if(b->type->shift == 0 && typeu[b->type->etype]) {
 +              v = ~0 + (1L << b->type->nbits);
 +              gopcode(OAND, nodconst(v), Z, n1);
 +      } else {
 +              sh = 32 - b->type->shift - b->type->nbits;
 +              if(sh > 0)
 +                      gopcode(OASHL, nodconst(sh), Z, n1);
 +              sh += b->type->shift;
 +              if(sh > 0)
 +                      if(typeu[b->type->etype])
 +                              gopcode(OLSHR, nodconst(sh), Z, n1);
 +                      else
 +                              gopcode(OASHR, nodconst(sh), Z, n1);
 +      }
 +}
 +
 +void
 +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
 +{
 +      int32 v;
 +      Node nod, *l;
 +      int sh;
 +
 +      /*
 +       * n1 has adjusted/masked value
 +       * n2 has address of cell
 +       * n3 has contents of cell
 +       */
 +      l = b->left;
 +      regalloc(&nod, l, Z);
 +      v = ~0 + (1L << b->type->nbits);
 +      gopcode(OAND, nodconst(v), Z, n1);
 +      gopcode(OAS, n1, Z, &nod);
 +      if(nn != Z)
 +              gopcode(OAS, n1, Z, nn);
 +      sh = b->type->shift;
 +      if(sh > 0)
 +              gopcode(OASHL, nodconst(sh), Z, &nod);
 +      v <<= sh;
 +      gopcode(OAND, nodconst(~v), Z, n3);
 +      gopcode(OOR, n3, Z, &nod);
 +      gopcode(OAS, &nod, Z, n2);
 +
 +      regfree(&nod);
 +      regfree(n1);
 +      regfree(n2);
 +      regfree(n3);
 +}
 +
 +int32
 +outstring(char *s, int32 n)
 +{
 +      int32 r;
 +
 +      if(suppress)
 +              return nstring;
 +      r = nstring;
 +      while(n) {
 +              string[mnstring] = *s++;
 +              mnstring++;
 +              nstring++;
 +              if(mnstring >= NSNAME) {
 +                      gpseudo(ADATA, symstring, nodconst(0L));
 +                      p->from.offset += nstring - NSNAME;
 +                      p->reg = NSNAME;
 +                      p->to.type = D_SCONST;
 +                      memmove(p->to.u.sval, string, NSNAME);
 +                      mnstring = 0;
 +              }
 +              n--;
 +      }
 +      return r;
 +}
 +
 +int
 +mulcon(Node *n, Node *nn)
 +{
 +      Node *l, *r, nod1, nod2;
 +      Multab *m;
 +      int32 v;
 +      int o;
 +      char code[sizeof(m->code)+2], *p;
 +
 +      if(typefd[n->type->etype])
 +              return 0;
 +      l = n->left;
 +      r = n->right;
 +      if(l->op == OCONST) {
 +              l = r;
 +              r = n->left;
 +      }
 +      if(r->op != OCONST)
 +              return 0;
 +      v = convvtox(r->vconst, n->type->etype);
 +      if(v != r->vconst) {
 +              if(debug['M'])
 +                      print("%L multiply conv: %lld\n", n->lineno, r->vconst);
 +              return 0;
 +      }
 +      m = mulcon0(n, v);
 +      if(!m) {
 +              if(debug['M'])
 +                      print("%L multiply table: %lld\n", n->lineno, r->vconst);
 +              return 0;
 +      }
 +
 +      memmove(code, m->code, sizeof(m->code));
 +      code[sizeof(m->code)] = 0;
 +
 +      p = code;
 +      if(p[1] == 'i')
 +              p += 2;
 +      regalloc(&nod1, n, nn);
 +      cgen(l, &nod1);
 +      if(v < 0)
 +              gopcode(ONEG, &nod1, Z, &nod1);
 +      regalloc(&nod2, n, Z);
 +
 +loop:
 +      switch(*p) {
 +      case 0:
 +              regfree(&nod2);
 +              gopcode(OAS, &nod1, Z, nn);
 +              regfree(&nod1);
 +              return 1;
 +      case '+':
 +              o = OADD;
 +              goto addsub;
 +      case '-':
 +              o = OSUB;
 +      addsub: /* number is r,n,l */
 +              v = p[1] - '0';
 +              r = &nod1;
 +              if(v&4)
 +                      r = &nod2;
 +              n = &nod1;
 +              if(v&2)
 +                      n = &nod2;
 +              l = &nod1;
 +              if(v&1)
 +                      l = &nod2;
 +              gopcode(o, l, n, r);
 +              break;
 +      default: /* op is shiftcount, number is r,l */
 +              v = p[1] - '0';
 +              r = &nod1;
 +              if(v&2)
 +                      r = &nod2;
 +              l = &nod1;
 +              if(v&1)
 +                      l = &nod2;
 +              v = *p - 'a';
 +              if(v < 0 || v >= 32) {
 +                      diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
 +                      break;
 +              }
 +              gopcode(OASHL, nodconst(v), l, r);
 +              break;
 +      }
 +      p += 2;
 +      goto loop;
 +}
 +
 +void
 +sextern(Sym *s, Node *a, int32 o, int32 w)
 +{
 +      int32 e, lw;
 +
 +      for(e=0; e<w; e+=NSNAME) {
 +              lw = NSNAME;
 +              if(w-e < lw)
 +                      lw = w-e;
 +              gpseudo(ADATA, s, nodconst(0));
 +              p->from.offset += o+e;
 +              p->reg = lw;
 +              p->to.type = D_SCONST;
 +              memmove(p->to.u.sval, a->cstring+e, lw);
 +      }
 +}
 +
 +void
 +gextern(Sym *s, Node *a, int32 o, int32 w)
 +{
 +      gpseudo(ADATA, s, a);
 +      p->from.offset += o;
 +      p->reg = w;
 +      if(p->to.type == D_OREG)
 +              p->to.type = D_CONST;
 +}
 +
 +void
 +outcode(void)
 +{
 +      Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
 +      if(pragcgobuf.to > pragcgobuf.start) {
 +              Bprint(&outbuf, "\n");
 +              Bprint(&outbuf, "$$  // exports\n\n");
 +              Bprint(&outbuf, "$$  // local types\n\n");
 +              Bprint(&outbuf, "$$  // cgo\n");
 +              Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf));
 +              Bprint(&outbuf, "\n$$\n\n");
 +      }
 +      Bprint(&outbuf, "!\n");
 +
 +      writeobj(ctxt, &outbuf);
 +      lastp = nil;
 +}
 +
 +int32
 +align(int32 i, Type *t, int op, int32 *maxalign)
 +{
 +      int32 o;
 +      Type *v;
-                       w = packflg;
++      int w, packw;
 +
 +      o = i;
 +      w = 1;
++      packw = 0;
 +      switch(op) {
 +      default:
 +              diag(Z, "unknown align opcode %d", op);
 +              break;
 +
 +      case Asu2:      /* padding at end of a struct */
 +              w = *maxalign;
 +              if(w < 1)
 +                      w = 1;
 +              if(packflg)
-                       w = packflg;
++                      packw = packflg;
 +              break;
 +
 +      case Ael1:      /* initial allign of struct element */
 +              for(v=t; v->etype==TARRAY; v=v->link)
 +                      ;
 +              if(v->etype == TSTRUCT || v->etype == TUNION)
 +                      w = v->align;
 +              else
 +                      w = ewidth[v->etype];
 +              if(w < 1 || w > SZ_VLONG)
 +                      fatal(Z, "align");
 +              if(packflg)
++                      packw = packflg;
 +              break;
 +
 +      case Ael2:      /* width of a struct element */
 +              o += t->width;
 +              break;
 +
 +      case Aarg0:     /* initial passbyptr argument in arg list */
 +              if(typesu[t->etype]) {
 +                      o = align(o, types[TIND], Aarg1, nil);
 +                      o = align(o, types[TIND], Aarg2, nil);
 +              }
 +              break;
 +
 +      case Aarg1:     /* initial align of parameter */
 +              w = ewidth[t->etype];
 +              if(w <= 0 || w >= SZ_VLONG) {
 +                      w = SZ_VLONG;
 +                      break;
 +              }
 +              w = 1;
 +              break;
 +
 +      case Aarg2:     /* width of a parameter */
 +              o += t->width;
 +              w = t->width;
 +              if(w > SZ_VLONG)
 +                      w = SZ_VLONG;
 +              break;
 +
 +      case Aaut3:     /* total align of automatic */
 +              o = align(o, t, Ael1, nil);
 +              o = align(o, t, Ael2, nil);
 +              break;
 +      }
++      if(packw != 0 && xround(o, w) != xround(o, packw))
++              diag(Z, "#pragma pack changes offset of %T", t);
 +      o = xround(o, w);
 +      if(maxalign && *maxalign < w)
 +              *maxalign = w;
 +      if(debug['A'])
 +              print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
 +      return o;
 +}
 +
 +int32
 +maxround(int32 max, int32 v)
 +{
 +      v = xround(v, SZ_VLONG);
 +      if(v > max)
 +              return v;
 +      return max;
 +}
index 84aeb4d8a94d823a8ba279369bf21b2ee0374f95,0000000000000000000000000000000000000000..e46aba84e778c62f558b71251282eda7b8da4ab8
mode 100644,000000..100644
--- /dev/null
@@@ -1,1509 -1,0 +1,1537 @@@
- regret(Node *n, Node *nn)
 +// cmd/9c/txt.c from Vita Nuova.
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include "gc.h"
 +
 +static        int     resvreg[nelem(reg)];
 +
 +#define       isv(et) ((et) == TVLONG || (et) == TUVLONG || (et) == TIND)
 +
 +int thechar = '9';
 +char *thestring = "power64";
 +
 +LinkArch      *thelinkarch;
 +
 +void
 +linkarchinit(void)
 +{
 +      thestring = getgoarch();
 +      if(strcmp(thestring, "power64le") == 0)
 +              thelinkarch = &linkpower64le;
 +      else
 +              thelinkarch = &linkpower64;
 +}
 +
 +
 +void
 +ginit(void)
 +{
 +      Type *t;
 +
 +      dodefine("_64BITREG");
 +      dodefine("_64BIT");
 +      exregoffset = REGEXT;
 +      exfregoffset = FREGEXT;
 +      listinit();
 +      nstring = 0;
 +      mnstring = 0;
 +      nrathole = 0;
 +      pc = 0;
 +      breakpc = -1;
 +      continpc = -1;
 +      cases = C;
 +      lastp = P;
 +      tfield = types[TLONG];
 +
 +      typeword = typechlvp;
 +      typecmplx = typesu;
 +      /* TO DO */
 +      memmove(typechlpv, typechlp, sizeof(typechlpv));
 +      typechlpv[TVLONG] = 1;
 +      typechlpv[TUVLONG] = 1;
 +
 +      zprog.link = P;
 +      zprog.as = AGOK;
 +      zprog.reg = NREG;
 +      zprog.from.type = D_NONE;
 +      zprog.from.name = D_NONE;
 +      zprog.from.reg = NREG;
 +      zprog.from3 = zprog.from;
 +      zprog.to = zprog.from;
 +
 +      regnode.op = OREGISTER;
 +      regnode.class = CEXREG;
 +      regnode.reg = 0;
 +      regnode.complex = 0;
 +      regnode.addable = 11;
 +      regnode.type = types[TLONG];
 +
 +      qregnode = regnode;
 +      qregnode.type = types[TVLONG];
 +
 +      constnode.op = OCONST;
 +      constnode.class = CXXX;
 +      constnode.complex = 0;
 +      constnode.addable = 20;
 +      constnode.type = types[TLONG];
 +
 +      vconstnode = constnode;
 +      vconstnode.type = types[TVLONG];
 +
 +      fconstnode.op = OCONST;
 +      fconstnode.class = CXXX;
 +      fconstnode.complex = 0;
 +      fconstnode.addable = 20;
 +      fconstnode.type = types[TDOUBLE];
 +
 +      nodsafe = new(ONAME, Z, Z);
 +      nodsafe->sym = slookup(".safe");
 +      nodsafe->type = types[TINT];
 +      nodsafe->etype = types[TINT]->etype;
 +      nodsafe->class = CAUTO;
 +      complex(nodsafe);
 +
 +      t = typ(TARRAY, types[TCHAR]);
 +      symrathole = slookup(".rathole");
 +      symrathole->class = CGLOBL;
 +      symrathole->type = t;
 +
 +      nodrat = new(ONAME, Z, Z);
 +      nodrat->sym = symrathole;
 +      nodrat->type = types[TIND];
 +      nodrat->etype = TVOID;
 +      nodrat->class = CGLOBL;
 +      complex(nodrat);
 +      nodrat->type = t;
 +
 +      nodret = new(ONAME, Z, Z);
 +      nodret->sym = slookup(".ret");
 +      nodret->type = types[TIND];
 +      nodret->etype = TIND;
 +      nodret->class = CPARAM;
 +      nodret = new(OIND, nodret, Z);
 +      complex(nodret);
 +
 +      com64init();
 +
 +      memset(reg, 0, sizeof(reg));
 +      reg[REGZERO] = 1;       /* don't use */
 +      reg[REGTMP] = 1;
 +      reg[FREGCVI+NREG] = 1;
 +      reg[FREGZERO+NREG] = 1;
 +      reg[FREGHALF+NREG] = 1;
 +      reg[FREGONE+NREG] = 1;
 +      reg[FREGTWO+NREG] = 1;
 +      memmove(resvreg, reg, sizeof(reg));
 +}
 +
 +void
 +gclean(void)
 +{
 +      int i;
 +      Sym *s;
 +
 +      for(i=0; i<NREG; i++)
 +              if(reg[i] && !resvreg[i])
 +                      diag(Z, "reg %d left allocated", i);
 +      for(i=NREG; i<NREG+NREG; i++)
 +              if(reg[i] && !resvreg[i])
 +                      diag(Z, "freg %d left allocated", i-NREG);
 +      while(mnstring)
 +              outstring("", 1L);
 +      symstring->type->width = nstring;
 +      symrathole->type->width = nrathole;
 +      for(i=0; i<NHASH; i++)
 +      for(s = hash[i]; s != S; s = s->link) {
 +              if(s->type == T)
 +                      continue;
 +              if(s->type->width == 0)
 +                      continue;
 +              if(s->class != CGLOBL && s->class != CSTATIC)
 +                      continue;
 +              if(s->type == types[TENUM])
 +                      continue;
 +              gpseudo(AGLOBL, s, nodconst(s->type->width));
 +      }
 +      nextpc();
 +      p->as = AEND;
 +      outcode();
 +}
 +
 +void
 +nextpc(void)
 +{
 +      Plist *pl;
 +
 +      p = alloc(sizeof(*p));
 +      *p = zprog;
 +      p->lineno = nearln;
 +      p->pc = pc;
 +      pc++;
 +      if(lastp == P) {
 +              pl = linknewplist(ctxt);
 +              pl->firstpc = p;
 +      } else
 +              lastp->link = p;
 +      lastp = p;
 +}
 +
 +void
 +gargs(Node *n, Node *tn1, Node *tn2)
 +{
 +      int32 regs;
 +      Node fnxargs[20], *fnxp;
 +
 +      regs = cursafe;
 +
 +      fnxp = fnxargs;
 +      garg1(n, tn1, tn2, 0, &fnxp);   /* compile fns to temps */
 +
 +      curarg = 0;
 +      fnxp = fnxargs;
 +      garg1(n, tn1, tn2, 1, &fnxp);   /* compile normal args and temps */
 +
 +      cursafe = regs;
 +}
 +
 +void
 +garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
 +{
 +      Node nod;
 +
 +      if(n == Z)
 +              return;
 +      if(n->op == OLIST) {
 +              garg1(n->left, tn1, tn2, f, fnxp);
 +              garg1(n->right, tn1, tn2, f, fnxp);
 +              return;
 +      }
 +      if(f == 0) {
 +              if(n->complex >= FNX) {
 +                      regsalloc(*fnxp, n);
 +                      nod = znode;
 +                      nod.op = OAS;
 +                      nod.left = *fnxp;
 +                      nod.right = n;
 +                      nod.type = n->type;
 +                      cgen(&nod, Z);
 +                      (*fnxp)++;
 +              }
 +              return;
 +      }
 +      if(typesu[n->type->etype]) {
 +              regaalloc(tn2, n);
 +              if(n->complex >= FNX) {
 +                      sugen(*fnxp, tn2, n->type->width);
 +                      (*fnxp)++;
 +              } else
 +                      sugen(n, tn2, n->type->width);
 +              return;
 +      }
 +      if(REGARG>=0 && curarg == 0 && typechlpv[n->type->etype]) {
 +              regaalloc1(tn1, n);
 +              if(n->complex >= FNX) {
 +                      cgen(*fnxp, tn1);
 +                      (*fnxp)++;
 +              } else
 +                      cgen(n, tn1);
 +              return;
 +      }
 +      if(vconst(n) == 0) {
 +              regaalloc(tn2, n);
 +              gopcode(OAS, n, Z, tn2);
 +              return;
 +      }
 +      regalloc(tn1, n, Z);
 +      if(n->complex >= FNX) {
 +              cgen(*fnxp, tn1);
 +              (*fnxp)++;
 +      } else
 +              cgen(n, tn1);
 +      regaalloc(tn2, n);
 +      gopcode(OAS, tn1, Z, tn2);
 +      regfree(tn1);
 +}
 +
 +Node*
 +nod32const(vlong v)
 +{
 +      constnode.vconst = v & MASK(32);
 +      return &constnode;
 +}
 +
 +Node*
 +nodgconst(vlong v, Type *t)
 +{
 +      if(!typev[t->etype])
 +              return nodconst((int32)v);
 +      vconstnode.vconst = v;
 +      return &vconstnode;
 +}
 +
 +Node*
 +nodconst(int32 v)
 +{
 +      constnode.vconst = v;
 +      return &constnode;
 +}
 +
 +Node*
 +nodfconst(double d)
 +{
 +      fconstnode.fconst = d;
 +      return &fconstnode;
 +}
 +
 +void
 +nodreg(Node *n, Node *nn, int reg)
 +{
 +      *n = qregnode;
 +      n->reg = reg;
 +      n->type = nn->type;
 +      n->lineno = nn->lineno;
 +}
 +
 +void
-       r = REGRET;
-       if(typefd[nn->type->etype])
-               r = FREGRET+NREG;
-       nodreg(n, nn, r);
-       reg[r]++;
++regret(Node *n, Node *nn, Type *t, int mode)
 +{
 +      int r;
++      
++      if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
++              r = REGRET;
++              if(typefd[nn->type->etype])
++                      r = FREGRET+NREG;
++              nodreg(n, nn, r);
++              reg[r]++;
++              return;
++      }
++      
++      if(mode == 1) {
++              // fetch returned value after call.
++              // already called gargs, so curarg is set.
++              curarg = (curarg+7) & ~7;
++              regaalloc(n, nn);
++              return;
++      }
 +
++      if(mode == 2) {
++              // store value to be returned.
++              // must compute arg offset.
++              if(t->etype != TFUNC)
++                      fatal(Z, "bad regret func %T", t);
++              *n = *nn;
++              n->op = ONAME;
++              n->class = CPARAM;
++              n->sym = slookup(".ret");
++              n->complex = nodret->complex;
++              n->addable = 20;
++              n->xoffset = argsize(0);
++              return;
++      }
++      
++      fatal(Z, "bad regret"); 
 +}
 +
 +void
 +regalloc(Node *n, Node *tn, Node *o)
 +{
 +      int i, j;
 +      static int lasti;
 +
 +      switch(tn->type->etype) {
 +      case TCHAR:
 +      case TUCHAR:
 +      case TSHORT:
 +      case TUSHORT:
 +      case TINT:
 +      case TUINT:
 +      case TLONG:
 +      case TULONG:
 +      case TVLONG:
 +      case TUVLONG:
 +      case TIND:
 +              if(o != Z && o->op == OREGISTER) {
 +                      i = o->reg;
 +                      if(i > 0 && i < NREG)
 +                              goto out;
 +              }
 +              j = lasti + REGRET+1;
 +              for(i=REGRET+1; i<NREG; i++) {
 +                      if(j >= NREG)
 +                              j = REGRET+1;
 +                      if(reg[j] == 0) {
 +                              i = j;
 +                              goto out;
 +                      }
 +                      j++;
 +              }
 +              diag(tn, "out of fixed registers");
 +              goto err;
 +
 +      case TFLOAT:
 +      case TDOUBLE:
 +              if(o != Z && o->op == OREGISTER) {
 +                      i = o->reg;
 +                      if(i >= NREG && i < NREG+NREG)
 +                              goto out;
 +              }
 +              j = lasti + NREG;
 +              for(i=NREG; i<NREG+NREG; i++) {
 +                      if(j >= NREG+NREG)
 +                              j = NREG;
 +                      if(reg[j] == 0) {
 +                              i = j;
 +                              goto out;
 +                      }
 +                      j++;
 +              }
 +              diag(tn, "out of float registers");
 +              goto err;
 +      }
 +      diag(tn, "unknown type in regalloc: %T", tn->type);
 +err:
 +      i = 0;
 +out:
 +      if(i)
 +              reg[i]++;
 +      lasti++;
 +      if(lasti >= 5)
 +              lasti = 0;
 +      nodreg(n, tn, i);
 +}
 +
 +void
 +regialloc(Node *n, Node *tn, Node *o)
 +{
 +      Node nod;
 +
 +      nod = *tn;
 +      nod.type = types[TIND];
 +      regalloc(n, &nod, o);
 +}
 +
 +void
 +regfree(Node *n)
 +{
 +      int i;
 +
 +      i = 0;
 +      if(n->op != OREGISTER && n->op != OINDREG)
 +              goto err;
 +      i = n->reg;
 +      if(i < 0 || i >= sizeof(reg))
 +              goto err;
 +      if(reg[i] <= 0)
 +              goto err;
 +      reg[i]--;
 +      return;
 +err:
 +      diag(n, "error in regfree: %d", i);
 +}
 +
 +void
 +regsalloc(Node *n, Node *nn)
 +{
 +      cursafe = align(cursafe, nn->type, Aaut3, nil);
 +      maxargsafe = maxround(maxargsafe, cursafe+curarg);
 +      *n = *nodsafe;
 +      n->xoffset = -(stkoff + cursafe);
 +      n->type = nn->type;
 +      n->etype = nn->type->etype;
 +      n->lineno = nn->lineno;
 +}
 +
 +void
 +regaalloc1(Node *n, Node *nn)
 +{
 +      if(REGARG < 0)
 +              return;
 +      nodreg(n, nn, REGARG);
 +      reg[REGARG]++;
 +      curarg = align(curarg, nn->type, Aarg1, nil);
 +      curarg = align(curarg, nn->type, Aarg2, nil);
 +      maxargsafe = maxround(maxargsafe, cursafe+curarg);
 +}
 +
 +void
 +regaalloc(Node *n, Node *nn)
 +{
 +      curarg = align(curarg, nn->type, Aarg1, nil);
 +      *n = *nn;
 +      n->op = OINDREG;
 +      n->reg = REGSP;
 +      n->xoffset = curarg + SZ_VLONG;
 +      n->complex = 0;
 +      n->addable = 20;
 +      curarg = align(curarg, nn->type, Aarg2, nil);
 +      maxargsafe = maxround(maxargsafe, cursafe+curarg);
 +}
 +
 +void
 +regind(Node *n, Node *nn)
 +{
 +
 +      if(n->op != OREGISTER) {
 +              diag(n, "regind not OREGISTER");
 +              return;
 +      }
 +      n->op = OINDREG;
 +      n->type = nn->type;
 +}
 +
 +void
 +raddr(Node *n, Prog *p)
 +{
 +      Addr a;
 +
 +      naddr(n, &a);
 +      if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
 +              a.type = D_REG;
 +              a.reg = REGZERO;
 +      }
 +      if(a.type != D_REG && a.type != D_FREG) {
 +              if(n)
 +                      diag(n, "bad in raddr: %O", n->op);
 +              else
 +                      diag(n, "bad in raddr: <null>");
 +              p->reg = NREG;
 +      } else
 +              p->reg = a.reg;
 +}
 +
 +void
 +naddr(Node *n, Addr *a)
 +{
 +      int32 v;
 +
 +      a->type = D_NONE;
 +      if(n == Z)
 +              return;
 +      switch(n->op) {
 +      default:
 +      bad:
 +              prtree(n, "naddr");
 +              diag(n, "%L: !bad in naddr: %O", n->lineno, n->op);
 +              break;
 +
 +      case OREGISTER:
 +              a->type = D_REG;
 +              a->sym = nil;
 +              a->reg = n->reg;
 +              if(a->reg >= NREG) {
 +                      a->type = D_FREG;
 +                      a->reg -= NREG;
 +              }
 +              break;
 +
 +      case OIND:
 +              naddr(n->left, a);
 +              if(a->type == D_REG) {
 +                      a->type = D_OREG;
 +                      break;
 +              }
 +              if(a->type == D_CONST) {
 +                      a->type = D_OREG;
 +                      break;
 +              }
 +              goto bad;
 +
 +      case OINDREG:
 +              a->type = D_OREG;
 +              a->sym = nil;
 +              a->offset = n->xoffset;
 +              a->reg = n->reg;
 +              break;
 +
 +      case ONAME:
 +              a->etype = n->etype;
 +              a->type = D_OREG;
 +              a->name = D_STATIC;
 +              a->sym = linksym(n->sym);
 +              a->offset = n->xoffset;
 +              if(n->class == CSTATIC)
 +                      break;
 +              if(n->class == CEXTERN || n->class == CGLOBL) {
 +                      a->name = D_EXTERN;
 +                      break;
 +              }
 +              if(n->class == CAUTO) {
 +                      a->name = D_AUTO;
 +                      break;
 +              }
 +              if(n->class == CPARAM) {
 +                      a->name = D_PARAM;
 +                      break;
 +              }
 +              goto bad;
 +
 +      case OCONST:
 +              a->sym = nil;
 +              a->reg = NREG;
 +              if(typefd[n->type->etype]) {
 +                      a->type = D_FCONST;
 +                      a->u.dval = n->fconst;
 +              } else {
 +                      a->type = D_CONST;
 +                      a->offset = n->vconst;
 +              }
 +              break;
 +
 +      case OADDR:
 +              naddr(n->left, a);
 +              if(a->type == D_OREG) {
 +                      a->type = D_CONST;
 +                      break;
 +              }
 +              goto bad;
 +
 +      case OADD:
 +              if(n->left->op == OCONST) {
 +                      naddr(n->left, a);
 +                      v = a->offset;
 +                      naddr(n->right, a);
 +              } else {
 +                      naddr(n->right, a);
 +                      v = a->offset;
 +                      naddr(n->left, a);
 +              }
 +              a->offset += v;
 +              break;
 +
 +      }
 +}
 +
 +void
 +fop(int as, int f1, int f2, Node *t)
 +{
 +      Node nod1, nod2, nod3;
 +
 +      nodreg(&nod1, t, NREG+f1);
 +      nodreg(&nod2, t, NREG+f2);
 +      regalloc(&nod3, t, t);
 +      gopcode(as, &nod1, &nod2, &nod3);
 +      gmove(&nod3, t);
 +      regfree(&nod3);
 +}
 +
 +void
 +gmove(Node *f, Node *t)
 +{
 +      int ft, tt, a;
 +      Node nod, fxc0, fxc1, fxc2, fxrat;
 +      Prog *p1;
 +      double d;
 +
 +      ft = f->type->etype;
 +      tt = t->type->etype;
 +
 +      if(ft == TDOUBLE && f->op == OCONST) {
 +              d = f->fconst;
 +              if(d == 0.0) {
 +                      a = FREGZERO;
 +                      goto ffreg;
 +              }
 +              if(d == 0.5) {
 +                      a = FREGHALF;
 +                      goto ffreg;
 +              }
 +              if(d == 1.0) {
 +                      a = FREGONE;
 +                      goto ffreg;
 +              }
 +              if(d == 2.0) {
 +                      a = FREGTWO;
 +                      goto ffreg;
 +              }
 +              if(d == -.5) {
 +                      fop(OSUB, FREGHALF, FREGZERO, t);
 +                      return;
 +              }
 +              if(d == -1.0) {
 +                      fop(OSUB, FREGONE, FREGZERO, t);
 +                      return;
 +              }
 +              if(d == -2.0) {
 +                      fop(OSUB, FREGTWO, FREGZERO, t);
 +                      return;
 +              }
 +              if(d == 1.5) {
 +                      fop(OADD, FREGONE, FREGHALF, t);
 +                      return;
 +              }
 +              if(d == 2.5) {
 +                      fop(OADD, FREGTWO, FREGHALF, t);
 +                      return;
 +              }
 +              if(d == 3.0) {
 +                      fop(OADD, FREGTWO, FREGONE, t);
 +                      return;
 +              }
 +      }
 +      if(ft == TFLOAT && f->op == OCONST) {
 +              d = f->fconst;
 +              if(d == 0) {
 +                      a = FREGZERO;
 +              ffreg:
 +                      nodreg(&nod, f, NREG+a);
 +                      gmove(&nod, t);
 +                      return;
 +              }
 +      }
 +      /*
 +       * a load --
 +       * put it into a register then
 +       * worry what to do with it.
 +       */
 +      if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
 +              switch(ft) {
 +              default:
 +                      if(ewidth[ft] == 4){
 +                              if(typeu[ft])
 +                                      a = AMOVWZ;
 +                              else
 +                                      a = AMOVW;
 +                      }else
 +                              a = AMOVD;
 +                      break;
 +              case TINT:
 +                      a = AMOVW;
 +                      break;
 +              case TUINT:
 +                      a = AMOVWZ;
 +                      break;
 +              case TFLOAT:
 +                      a = AFMOVS;
 +                      break;
 +              case TDOUBLE:
 +                      a = AFMOVD;
 +                      break;
 +              case TCHAR:
 +                      a = AMOVB;
 +                      break;
 +              case TUCHAR:
 +                      a = AMOVBZ;
 +                      break;
 +              case TSHORT:
 +                      a = AMOVH;
 +                      break;
 +              case TUSHORT:
 +                      a = AMOVHZ;
 +                      break;
 +              }
 +              regalloc(&nod, f, t);
 +              gins(a, f, &nod);
 +              gmove(&nod, t);
 +              regfree(&nod);
 +              return;
 +      }
 +
 +      /*
 +       * a store --
 +       * put it into a register then
 +       * store it.
 +       */
 +      if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
 +              switch(tt) {
 +              default:
 +                      if(ewidth[tt] == 4)
 +                              a = AMOVW;
 +                      else
 +                              a = AMOVD;
 +                      break;
 +              case TINT:
 +                      a = AMOVW;
 +                      break;
 +              case TUINT:
 +                      a = AMOVWZ;
 +                      break;
 +              case TUCHAR:
 +                      a = AMOVBZ;
 +                      break;
 +              case TCHAR:
 +                      a = AMOVB;
 +                      break;
 +              case TUSHORT:
 +                      a = AMOVHZ;
 +                      break;
 +              case TSHORT:
 +                      a = AMOVH;
 +                      break;
 +              case TFLOAT:
 +                      a = AFMOVS;
 +                      break;
 +              case TDOUBLE:
 +                      a = AFMOVD;
 +                      break;
 +              }
 +              if(!typefd[ft] && vconst(f) == 0) {
 +                      gins(a, f, t);
 +                      return;
 +              }
 +              if(ft == tt)
 +                      regalloc(&nod, t, f);
 +              else
 +                      regalloc(&nod, t, Z);
 +              gmove(f, &nod);
 +              gins(a, &nod, t);
 +              regfree(&nod);
 +              return;
 +      }
 +
 +      /*
 +       * type x type cross table
 +       */
 +      a = AGOK;
 +      switch(ft) {
 +      case TDOUBLE:
 +      case TFLOAT:
 +              switch(tt) {
 +              case TDOUBLE:
 +                      a = AFMOVD;
 +                      if(ft == TFLOAT)
 +                              a = AFMOVS;     /* AFMOVSD */
 +                      break;
 +              case TFLOAT:
 +                      a = AFRSP;
 +                      if(ft == TFLOAT)
 +                              a = AFMOVS;
 +                      break;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TIND:
 +              case TSHORT:
 +              case TUSHORT:
 +              case TCHAR:
 +              case TUCHAR:
 +                      /* BUG: not right for unsigned int32 */
 +                      regalloc(&nod, f, Z);   /* should be type float */
 +                      regsalloc(&fxrat, f);
 +                      gins(AFCTIWZ, f, &nod);
 +                      gins(AFMOVD, &nod, &fxrat);
 +                      regfree(&nod);
 +                      fxrat.type = nodrat->type;
 +                      fxrat.etype = nodrat->etype;
 +                      fxrat.xoffset += 4;
 +                      gins(AMOVW, &fxrat, t); /* TO DO */
 +                      gmove(t, t);
 +                      return;
 +              case TVLONG:
 +              case TUVLONG:
 +                      /* BUG: not right for unsigned int32 */
 +                      regalloc(&nod, f, Z);   /* should be type float */
 +                      regsalloc(&fxrat, f);
 +                      gins(AFCTIDZ, f, &nod);
 +                      gins(AFMOVD, &nod, &fxrat);
 +                      regfree(&nod);
 +                      fxrat.type = nodrat->type;
 +                      fxrat.etype = nodrat->etype;
 +                      gins(AMOVD, &fxrat, t);
 +                      gmove(t, t);
 +                      return;
 +              }
 +              break;
 +      case TINT:
 +      case TUINT:
 +      case TLONG:
 +      case TULONG:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +                      goto fxtofl;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TSHORT:
 +              case TUSHORT:
 +              case TCHAR:
 +              case TUCHAR:
 +                      if(typeu[tt])
 +                              a = AMOVWZ;
 +                      else
 +                              a = AMOVW;
 +                      break;
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +                      a = AMOVD;
 +                      break;
 +              }
 +              break;
 +      case TVLONG:
 +      case TUVLONG:
 +      case TIND:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +                      goto fxtofl;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +              case TSHORT:
 +              case TUSHORT:
 +              case TCHAR:
 +              case TUCHAR:
 +                      a = AMOVD;      /* TO DO: conversion done? */
 +                      break;
 +              }
 +              break;
 +      case TSHORT:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +                      goto fxtofl;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +                      a = AMOVH;
 +                      break;
 +              case TSHORT:
 +              case TUSHORT:
 +              case TCHAR:
 +              case TUCHAR:
 +                      a = AMOVD;
 +                      break;
 +              }
 +              break;
 +      case TUSHORT:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +                      goto fxtofl;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +                      a = AMOVHZ;
 +                      break;
 +              case TSHORT:
 +              case TUSHORT:
 +              case TCHAR:
 +              case TUCHAR:
 +                      a = AMOVD;
 +                      break;
 +              }
 +              break;
 +      case TCHAR:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +                      goto fxtofl;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +              case TSHORT:
 +              case TUSHORT:
 +                      a = AMOVB;
 +                      break;
 +              case TCHAR:
 +              case TUCHAR:
 +                      a = AMOVD;
 +                      break;
 +              }
 +              break;
 +      case TUCHAR:
 +              switch(tt) {
 +              case TDOUBLE:
 +              case TFLOAT:
 +              fxtofl:
 +                      /*
 +                       * rat[0] = 0x43300000; rat[1] = f^0x80000000;
 +                       * t = *(double*)rat - FREGCVI;
 +                       * is-unsigned(t) => if(t<0) t += 2^32;
 +                       * could be streamlined for int-to-float
 +                       */
 +                      regalloc(&fxc0, f, Z);
 +                      regalloc(&fxc2, f, Z);
 +                      regsalloc(&fxrat, t);   /* should be type float */
 +                      gins(AMOVW, nodconst(0x43300000L), &fxc0);
 +                      gins(AMOVW, f, &fxc2);
 +                      gins(AXOR, nodconst(0x80000000L), &fxc2);
 +                      if(ctxt->arch->endian == BigEndian) {
 +                              gins(AMOVW, &fxc0, &fxrat);
 +                              fxc1 = fxrat;
 +                              fxc1.type = nodrat->type;
 +                              fxc1.etype = nodrat->etype;
 +                              fxc1.xoffset += SZ_LONG;
 +                              gins(AMOVW, &fxc2, &fxc1);
 +                      } else {
 +                              gins(AMOVW, &fxc2, &fxrat);
 +                              fxc1 = fxrat;
 +                              fxc1.type = nodrat->type;
 +                              fxc1.etype = nodrat->etype;
 +                              fxc1.xoffset += SZ_LONG;
 +                              gins(AMOVW, &fxc0, &fxc1);
 +                      }
 +                      regfree(&fxc2);
 +                      regfree(&fxc0);
 +                      regalloc(&nod, t, t);   /* should be type float */
 +                      gins(AFMOVD, &fxrat, &nod);
 +                      nodreg(&fxc1, t, NREG+FREGCVI);
 +                      gins(AFSUB, &fxc1, &nod);
 +                      a = AFMOVD;
 +                      if(tt == TFLOAT)
 +                              a = AFRSP;
 +                      gins(a, &nod, t);
 +                      regfree(&nod);
 +                      if(ft == TULONG) {
 +                              regalloc(&nod, t, Z);
 +                              if(tt == TFLOAT) {
 +                                      gins(AFCMPU, t, Z);
 +                                      p->to.type = D_FREG;
 +                                      p->to.reg = FREGZERO;
 +                                      gins(ABGE, Z, Z);
 +                                      p1 = p;
 +                                      gins(AFMOVS, nodfconst(4294967296.), &nod);
 +                                      gins(AFADDS, &nod, t);
 +                              } else {
 +                                      gins(AFCMPU, t, Z);
 +                                      p->to.type = D_FREG;
 +                                      p->to.reg = FREGZERO;
 +                                      gins(ABGE, Z, Z);
 +                                      p1 = p;
 +                                      gins(AFMOVD, nodfconst(4294967296.), &nod);
 +                                      gins(AFADD, &nod, t);
 +                              }
 +                              patch(p1, pc);
 +                              regfree(&nod);
 +                      }
 +                      return;
 +              case TINT:
 +              case TUINT:
 +              case TLONG:
 +              case TULONG:
 +              case TVLONG:
 +              case TUVLONG:
 +              case TIND:
 +              case TSHORT:
 +              case TUSHORT:
 +                      a = AMOVBZ;
 +                      break;
 +              case TCHAR:
 +              case TUCHAR:
 +                      a = AMOVD;
 +                      break;
 +              }
 +              break;
 +      }
 +      if(a == AGOK)
 +              diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
 +      if(a == AMOVD || (a == AMOVW || a == AMOVWZ) && ewidth[ft] == ewidth[tt] || a == AFMOVS || a == AFMOVD)
 +      if(samaddr(f, t))
 +              return;
 +      gins(a, f, t);
 +}
 +
 +void
 +gins(int a, Node *f, Node *t)
 +{
 +
 +      nextpc();
 +      p->as = a;
 +      if(f != Z)
 +              naddr(f, &p->from);
 +      if(t != Z)
 +              naddr(t, &p->to);
 +      if(debug['g'])
 +              print("%P\n", p);
 +}
 +
 +void
 +gopcode(int o, Node *f1, Node *f2, Node *t)
 +{
 +      int a, et;
 +      Addr ta;
 +      int uns;
 +
 +      uns = 0;
 +      et = TLONG;
 +      if(f1 != Z && f1->type != T) {
 +              if(f1->op == OCONST && t != Z && t->type != T)
 +                      et = t->type->etype;
 +              else
 +                      et = f1->type->etype;
 +      }
 +      a = AGOK;
 +      switch(o) {
 +      case OAS:
 +              gmove(f1, t);
 +              return;
 +
 +      case OASADD:
 +      case OADD:
 +              a = AADD;
 +              if(et == TFLOAT)
 +                      a = AFADDS;
 +              else
 +              if(et == TDOUBLE)
 +                      a = AFADD;
 +              break;
 +
 +      case OASSUB:
 +      case OSUB:
 +              a = ASUB;
 +              if(et == TFLOAT)
 +                      a = AFSUBS;
 +              else
 +              if(et == TDOUBLE)
 +                      a = AFSUB;
 +              break;
 +
 +      case OASOR:
 +      case OOR:
 +              a = AOR;
 +              break;
 +
 +      case OASAND:
 +      case OAND:
 +              a = AAND;
 +              if(f1->op == OCONST)
 +                      a = AANDCC;
 +              break;
 +
 +      case OASXOR:
 +      case OXOR:
 +              a = AXOR;
 +              break;
 +
 +      case OASLSHR:
 +      case OLSHR:
 +              a = ASRW;
 +              if(isv(et))
 +                      a = ASRD;
 +              break;
 +
 +      case OASASHR:
 +      case OASHR:
 +              a = ASRAW;
 +              if(isv(et))
 +                      a = ASRAD;
 +              break;
 +
 +      case OASASHL:
 +      case OASHL:
 +              a = ASLW;
 +              if(isv(et))
 +                      a = ASLD;
 +              break;
 +
 +      case OFUNC:
 +              a = ABL;
 +              break;
 +
 +      case OASLMUL:
 +      case OLMUL:
 +      case OASMUL:
 +      case OMUL:
 +              if(et == TFLOAT) {
 +                      a = AFMULS;
 +                      break;
 +              } else
 +              if(et == TDOUBLE) {
 +                      a = AFMUL;
 +                      break;
 +              }
 +              a = AMULLW;
 +              if(isv(et))
 +                      a = AMULLD;
 +              break;
 +
 +      case OASDIV:
 +      case ODIV:
 +              if(et == TFLOAT) {
 +                      a = AFDIVS;
 +                      break;
 +              } else
 +              if(et == TDOUBLE) {
 +                      a = AFDIV;
 +                      break;
 +              } else
 +              a = ADIVW;
 +              if(isv(et))
 +                      a = ADIVD;
 +              break;
 +
 +      case OASMOD:
 +      case OMOD:
 +              a = AREM;
 +              if(isv(et))
 +                      a = AREMD;
 +              break;
 +
 +      case OASLMOD:
 +      case OLMOD:
 +              a = AREMU;
 +              if(isv(et))
 +                      a = AREMDU;
 +              break;
 +
 +      case OASLDIV:
 +      case OLDIV:
 +              a = ADIVWU;
 +              if(isv(et))
 +                      a = ADIVDU;
 +              break;
 +
 +      case OCOM:
 +              a = ANOR;
 +              break;
 +
 +      case ONEG:
 +              a = ANEG;
 +              if(et == TFLOAT || et == TDOUBLE)
 +                      a = AFNEG;
 +              break;
 +
 +      case OEQ:
 +              a = ABEQ;
 +              goto cmp;
 +
 +      case ONE:
 +              a = ABNE;
 +              goto cmp;
 +
 +      case OLT:
 +              a = ABLT;
 +              goto cmp;
 +
 +      case OLE:
 +              a = ABLE;
 +              goto cmp;
 +
 +      case OGE:
 +              a = ABGE;
 +              goto cmp;
 +
 +      case OGT:
 +              a = ABGT;
 +              goto cmp;
 +
 +      case OLO:
 +              a = ABLT;
 +              goto cmpu;
 +
 +      case OLS:
 +              a = ABLE;
 +              goto cmpu;
 +
 +      case OHS:
 +              a = ABGE;
 +              goto cmpu;
 +
 +      case OHI:
 +              a = ABGT;
 +              goto cmpu;
 +
 +      cmpu:
 +              uns = 1;
 +      cmp:
 +              nextpc();
 +              switch(et){
 +              case TINT:
 +              case TLONG:
 +                      p->as = ACMPW;
 +                      break;
 +              case TUINT:
 +              case TULONG:
 +                      p->as = ACMPWU;
 +                      break;
 +              case TFLOAT:
 +              case TDOUBLE:
 +                      p->as = AFCMPU;
 +                      break;
 +              default:
 +                      p->as = uns? ACMPU: ACMP;
 +                      break;
 +              }
 +              if(f1 != Z)
 +                      naddr(f1, &p->from);
 +              if(t != Z)
 +                      naddr(t, &p->to);
 +              if(f1 == Z || t == Z || f2 != Z)
 +                      diag(Z, "bad cmp in gopcode %O", o);
 +              if(debug['g'])
 +                      print("%P\n", p);
 +              f1 = Z;
 +              f2 = Z;
 +              t = Z;
 +              break;
 +      }
 +      if(a == AGOK)
 +              diag(Z, "bad in gopcode %O", o);
 +      nextpc();
 +      p->as = a;
 +      if(f1 != Z)
 +              naddr(f1, &p->from);
 +      if(f2 != Z) {
 +              naddr(f2, &ta);
 +              p->reg = ta.reg;
 +              if(ta.type == D_CONST && ta.offset == 0) {
 +                      if(R0ISZERO)
 +                              p->reg = REGZERO;
 +                      else
 +                              diag(Z, "REGZERO in gopcode %O", o);
 +              }
 +      }
 +      if(t != Z)
 +              naddr(t, &p->to);
 +      if(debug['g'])
 +              print("%P\n", p);
 +}
 +
 +int
 +samaddr(Node *f, Node *t)
 +{
 +      return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
 +}
 +
 +void
 +gbranch(int o)
 +{
 +      int a;
 +
 +      a = AGOK;
 +      switch(o) {
 +      case ORETURN:
 +              a = ARETURN;
 +              break;
 +      case OGOTO:
 +              a = ABR;
 +              break;
 +      }
 +      nextpc();
 +      if(a == AGOK) {
 +              diag(Z, "bad in gbranch %O",  o);
 +              nextpc();
 +      }
 +      p->as = a;
 +}
 +
 +void
 +patch(Prog *op, int32 pc)
 +{
 +
 +      op->to.offset = pc;
 +      op->to.type = D_BRANCH;
 +}
 +
 +void
 +gpseudo(int a, Sym *s, Node *n)
 +{
 +
 +      nextpc();
 +      p->as = a;
 +      p->from.type = D_OREG;
 +      p->from.sym = linksym(s);
 +
 +      switch(a) {
 +      case ATEXT:
 +              p->reg = textflag;
 +              textflag = 0;
 +              break;
 +      case AGLOBL:
 +              p->reg = s->dataflag;
 +              break;
 +      }
 +
 +      p->from.name = D_EXTERN;
 +      if(s->class == CSTATIC)
 +              p->from.name = D_STATIC;
 +      naddr(n, &p->to);
 +      if(a == ADATA || a == AGLOBL)
 +              pc--;
 +}
 +
 +int
 +sval(int32 v)
 +{
 +
 +      if(v >= -(1<<15) && v < (1<<15))
 +              return 1;
 +      return 0;
 +}
 +
 +void
 +gpcdata(int index, int value)
 +{
 +      Node n1;
 +
 +      n1 = *nodconst(index);
 +      gins(APCDATA, &n1, nodconst(value));
 +}
 +
 +void
 +gprefetch(Node *n)
 +{
 +      // TODO(minux)
 +      USED(n);
 +      /*
 +      Node n1;
 +
 +      regalloc(&n1, n, Z);
 +      gmove(n, &n1);
 +      n1.op = OINDREG;
 +      gins(ADCBT, &n1, Z);
 +      regfree(&n1);
 +      */
 +}
 +
 +
 +int
 +sconst(Node *n)
 +{
 +      vlong vv;
 +
 +      if(n->op == OCONST) {
 +              if(!typefd[n->type->etype]) {
 +                      vv = n->vconst;
 +                      if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15))
 +                              return 1;
 +              }
 +      }
 +      return 0;
 +}
 +
 +int
 +uconst(Node *n)
 +{
 +      vlong vv;
 +
 +      if(n->op == OCONST) {
 +              if(!typefd[n->type->etype]) {
 +                      vv = n->vconst;
 +                      if(vv >= 0 && vv < (((vlong)1)<<16))
 +                              return 1;
 +              }
 +      }
 +      return 0;
 +}
 +
 +int
 +immconst(Node *n)
 +{
 +      vlong v;
 +
 +      if(n->op != OCONST || typefd[n->type->etype])
 +              return 0;
 +      v = n->vconst;
 +      if((v & 0xFFFF) == 0)
 +              v >>= 16;
 +      if(v >= 0 && v < ((vlong)1<<16))
 +              return 1;
 +      if(v >= -((vlong)1<<15) && v <= ((vlong)1<<15))
 +              return 1;
 +      return 0;
 +}
 +
 +int32
 +exreg(Type *t)
 +{
 +      int32 o;
 +
 +      if(typechlpv[t->etype]) {
 +              if(exregoffset <= 3)
 +                      return 0;
 +              o = exregoffset;
 +              exregoffset--;
 +              return o;
 +      }
 +      if(typefd[t->etype]) {
 +              if(exfregoffset <= 16)
 +                      return 0;
 +              o = exfregoffset + NREG;
 +              exfregoffset--;
 +              return o;
 +      }
 +      return 0;
 +}
 +
 +schar ewidth[NTYPE] =
 +{
 +      -1,             /* [TXXX] */
 +      SZ_CHAR,        /* [TCHAR] */
 +      SZ_CHAR,        /* [TUCHAR] */
 +      SZ_SHORT,       /* [TSHORT] */
 +      SZ_SHORT,       /* [TUSHORT] */
 +      SZ_INT,         /* [TINT] */
 +      SZ_INT,         /* [TUINT] */
 +      SZ_LONG,        /* [TLONG] */
 +      SZ_LONG,        /* [TULONG] */
 +      SZ_VLONG,       /* [TVLONG] */
 +      SZ_VLONG,       /* [TUVLONG] */
 +      SZ_FLOAT,       /* [TFLOAT] */
 +      SZ_DOUBLE,      /* [TDOUBLE] */
 +      SZ_IND,         /* [TIND] */
 +      0,              /* [TFUNC] */
 +      -1,             /* [TARRAY] */
 +      0,              /* [TVOID] */
 +      -1,             /* [TSTRUCT] */
 +      -1,             /* [TUNION] */
 +      SZ_INT,         /* [TENUM] */
 +};
 +int32 ncast[NTYPE] =
 +{
 +      0,                              /* [TXXX] */
 +      BCHAR|BUCHAR,                   /* [TCHAR] */
 +      BCHAR|BUCHAR,                   /* [TUCHAR] */
 +      BSHORT|BUSHORT,                 /* [TSHORT] */
 +      BSHORT|BUSHORT,                 /* [TUSHORT] */
 +      BINT|BUINT|BLONG|BULONG,        /* [TINT] */
 +      BINT|BUINT|BLONG|BULONG,        /* [TUINT] */
 +      BINT|BUINT|BLONG|BULONG,        /* [TLONG] */
 +      BINT|BUINT|BLONG|BULONG,        /* [TULONG] */
 +      BVLONG|BUVLONG|BIND,                    /* [TVLONG] */
 +      BVLONG|BUVLONG|BIND,                    /* [TUVLONG] */
 +      BFLOAT,                         /* [TFLOAT] */
 +      BDOUBLE,                        /* [TDOUBLE] */
 +      BVLONG|BUVLONG|BIND,            /* [TIND] */
 +      0,                              /* [TFUNC] */
 +      0,                              /* [TARRAY] */
 +      0,                              /* [TVOID] */
 +      BSTRUCT,                        /* [TSTRUCT] */
 +      BUNION,                         /* [TUNION] */
 +      0,                              /* [TENUM] */
 +};
index 86a56975ade141c2460afa624df7b7564e1d0fcc,0000000000000000000000000000000000000000..e3893600167a67502f96ef8662e648d8e161be0f
mode 100644,000000..100644
--- /dev/null
@@@ -1,1764 -1,0 +1,1763 @@@
-       case OADDPTR:
 +// 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;
 +      int a, f;
 +      Prog *p1, *p2, *p3;
 +      Addr addr;
 +
 +//print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable);
 +      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");
 +
 +      while(n->op == OCONVNOP)
 +              n = n->left;
 +
 +      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);
 +              goto ret;
 +      case OEFACE:
 +              if (res->op != ONAME || !res->addable) {
 +                      tempname(&n1, n->type);
 +                      cgen_eface(n, &n1);
 +                      cgen(&n1, res);
 +              } else
 +                      cgen_eface(n, res);
 +              goto ret;
 +      }
 +
 +      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;
 +      }
 +
 +      if(!res->addable) {
 +              if(n->ullman > res->ullman) {
 +                      regalloc(&n1, n->type, res);
 +                      cgen(n, &n1);
 +                      if(n1.ullman > res->ullman) {
 +                              dump("n1", &n1);
 +                              dump("res", res);
 +                              fatal("loop in cgen");
 +                      }
 +                      cgen(&n1, res);
 +                      regfree(&n1);
 +                      goto ret;
 +              }
 +
 +              if(res->ullman >= UINF)
 +                      goto gen;
 +
 +              if(complexop(n, res)) {
 +                      complexgen(n, res);
 +                      goto ret;
 +              }
 +
 +              f = 1;  // gen thru register
 +              switch(n->op) {
 +              case OLITERAL:
 +                      if(smallintconst(n))
 +                              f = 0;
 +                      break;
 +              case OREGISTER:
 +                      f = 0;
 +                      break;
 +              }
 +
 +              if(!iscomplex[n->type->etype]) {
 +                      a = optoas(OAS, res->type);
 +                      if(sudoaddable(a, res, &addr)) {
 +                              if(f) {
 +                                      regalloc(&n2, res->type, N);
 +                                      cgen(n, &n2);
 +                                      p1 = gins(a, &n2, N);
 +                                      regfree(&n2);
 +                              } else
 +                                      p1 = gins(a, n, N);
 +                              p1->to = addr;
 +                              if(debug['g'])
 +                                      print("%P [ignore previous line]\n", p1);
 +                              sudoclean();
 +                              goto ret;
 +                      }
 +              }
 +
 +      gen:
 +              igen(res, &n1, N);
 +              cgen(n, &n1);
 +              regfree(&n1);
 +              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(complexop(n, res)) {
 +              complexgen(n, res);
 +              goto ret;
 +      }
 +
 +      // if both are addressable, move
 +      if(n->addable) {
 +              if(n->op == OREGISTER || res->op == OREGISTER) {
 +                      gmove(n, res);
 +              } else {
 +                      regalloc(&n1, n->type, N);
 +                      gmove(n, &n1);
 +                      cgen(&n1, res);
 +                      regfree(&n1);
 +              }
 +              goto ret;
 +      }
 +
 +      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;
 +      }
 +
 +      if(!iscomplex[n->type->etype]) {
 +              a = optoas(OAS, n->type);
 +              if(sudoaddable(a, n, &addr)) {
 +                      if(res->op == OREGISTER) {
 +                              p1 = gins(a, N, res);
 +                              p1->from = addr;
 +                      } else {
 +                              regalloc(&n2, n->type, N);
 +                              p1 = gins(a, N, &n2);
 +                              p1->from = addr;
 +                              gins(a, &n2, res);
 +                              regfree(&n2);
 +                      }
 +                      sudoclean();
 +                      goto ret;
 +              }
 +      }
 +
 +      // TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize
 +      // OGE, OLE, and ONE ourselves.
 +      // 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;
 +
 +      // 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(ABR, T, 0);
 +              p2 = pc;
 +              gmove(nodbool(1), res);
 +              p3 = gbranch(ABR, 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);
 +              gmove(&n1, res);
 +              regfree(&n1);
 +              goto ret;
 +
 +      case OMINUS:
 +              if(isfloat[nl->type->etype]) {
 +                      nr = nodintconst(-1);
 +                      convlit(&nr, n->type);
 +                      a = optoas(OMUL, nl->type);
 +                      goto sbop;
 +              }
 +              a = optoas(n->op, nl->type);
 +              goto uop;
 +
 +      // 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 OCONV:
 +              if(n->type->width > nl->type->width) {
 +                      // If loading from memory, do conversion during load,
 +                      // so as to avoid use of 8-bit register in, say, int(*byteptr).
 +                      switch(nl->op) {
 +                      case ODOT:
 +                      case ODOTPTR:
 +                      case OINDEX:
 +                      case OIND:
 +                      case ONAME:
 +                              igen(nl, &n1, res);
 +                              regalloc(&n2, n->type, res);
 +                              gmove(&n1, &n2);
 +                              gmove(&n2, res);
 +                              regfree(&n2);
 +                              regfree(&n1);
 +                              goto ret;
 +                      }
 +              }
 +
 +              regalloc(&n1, nl->type, res);
 +              regalloc(&n2, n->type, &n1);
 +              cgen(nl, &n1);
 +
 +              // if we do the conversion n1 -> n2 here
 +              // reusing the register, then gmove won't
 +              // have to allocate its own register.
 +              gmove(&n1, &n2);
 +              gmove(&n2, res);
 +              regfree(&n2);
 +              regfree(&n1);
 +              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(AMOVD, 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 and chan have len in the first int-sized word.
 +                      // a zero pointer means zero length
 +                      regalloc(&n1, types[tptr], res);
 +                      cgen(nl, &n1);
 +
 +                      nodconst(&n2, types[tptr], 0);
 +                      gins(optoas(OCMP, types[tptr]), &n1, &n2);
 +                      p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
 +
 +                      n2 = n1;
 +                      n2.op = OINDREG;
 +                      n2.type = types[simtype[TINT]];
 +                      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.
 +                      // a zero pointer means zero length
 +                      igen(nl, &n1, res);
 +                      n1.type = types[simtype[TUINT]];
 +                      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 int-sized word.
 +                      // a zero pointer means zero length
 +                      regalloc(&n1, types[tptr], res);
 +                      cgen(nl, &n1);
 +
 +                      nodconst(&n2, types[tptr], 0);
 +                      gins(optoas(OCMP, types[tptr]), &n1, &n2);
 +                      p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
 +
 +                      n2 = n1;
 +                      n2.op = OINDREG;
 +                      n2.xoffset = widthint;
 +                      n2.type = types[simtype[TINT]];
 +                      gmove(&n2, &n1);
 +
 +                      patch(p1, pc);
 +
 +                      gmove(&n1, res);
 +                      regfree(&n1);
 +                      break;
 +              }
 +              if(isslice(nl->type)) {
 +                      igen(nl, &n1, res);
 +                      n1.type = types[simtype[TUINT]];
 +                      n1.xoffset += Array_cap;
 +                      gmove(&n1, res);
 +                      regfree(&n1);
 +                      break;
 +              }
 +              fatal("cgen: OCAP: unknown type %lT", nl->type);
 +              break;
 +
 +      case OADDR:
 +              if(n->bounded) // let race detector avoid nil checks
 +                      disable_checknil++;
 +              agen(nl, res);
 +              if(n->bounded)
 +                      disable_checknil--;
 +              break;
 +
 +      case OCALLMETH:
 +              cgen_callmeth(n, 0);
 +              cgen_callret(n, res);
 +              break;
 +
 +      case OCALLINTER:
 +              cgen_callinter(n, res, 0);
 +              cgen_callret(n, res);
 +              break;
 +
 +      case OCALLFUNC:
 +              cgen_call(n, 0);
 +              cgen_callret(n, res);
 +              break;
 +
 +      case OMOD:
 +      case ODIV:
 +              if(isfloat[n->type->etype]) {
 +                      a = optoas(n->op, nl->type);
 +                      goto abop;
 +              }
 +
 +              if(nl->ullman >= nr->ullman) {
 +                      regalloc(&n1, nl->type, res);
 +                      cgen(nl, &n1);
 +                      cgen_div(n->op, &n1, nr, res);
 +                      regfree(&n1);
 +              } else {
 +                      if(!smallintconst(nr)) {
 +                              regalloc(&n2, nr->type, res);
 +                              cgen(nr, &n2);
 +                      } else {
 +                              n2 = *nr;
 +                      }
 +                      cgen_div(n->op, nl, &n2, res);
 +                      if(n2.op != OLITERAL)
 +                              regfree(&n2);
 +              }
 +              break;
 +
 +      case OLSH:
 +      case ORSH:
 +      case OLROT:
 +              cgen_shift(n->op, n->bounded, nl, nr, res);
 +              break;
 +      }
 +      goto ret;
 +
 +sbop: // symmetric binary
 +      /*
 +       * put simplest on right - we'll generate into left
 +       * and then adjust it using the computation of right.
 +       * constants and variables have the same ullman
 +       * count, so look for constants specially.
 +       *
 +       * an integer constant we can use as an immediate
 +       * is simpler than a variable - we can use the immediate
 +       * in the adjustment instruction directly - so it goes
 +       * on the right.
 +       *
 +       * other constants, like big integers or floating point
 +       * constants, require a mov into a register, so those
 +       * might as well go on the left, so we can reuse that
 +       * register for the computation.
 +       */
 +      if(nl->ullman < nr->ullman ||
 +         (nl->ullman == nr->ullman &&
 +          (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) {
 +              r = nl;
 +              nl = nr;
 +              nr = r;
 +      }
 +
 +abop: // asymmetric binary
 +      if(nl->ullman >= nr->ullman) {
 +              regalloc(&n1, nl->type, res);
 +              cgen(nl, &n1);
 +      /*
 +       * This generates smaller code - it avoids a MOV - but it's
 +       * easily 10% slower due to not being able to
 +       * optimize/manipulate the move.
 +       * To see, run: go test -bench . crypto/md5
 +       * with and without.
 +       *
 +              if(sudoaddable(a, nr, &addr)) {
 +                      p1 = gins(a, N, &n1);
 +                      p1->from = addr;
 +                      gmove(&n1, res);
 +                      sudoclean();
 +                      regfree(&n1);
 +                      goto ret;
 +              }
 +       *
 +       */
 +              // TODO(minux): enable using constants directly in certain instructions.
 +              //if(smallintconst(nr))
 +              //      n2 = *nr;
 +              //else {
 +                      regalloc(&n2, nr->type, N);
 +                      cgen(nr, &n2);
 +              //}
 +      } else {
 +              //if(smallintconst(nr))
 +              //      n2 = *nr;
 +              //else {
 +                      regalloc(&n2, nr->type, res);
 +                      cgen(nr, &n2);
 +              //}
 +              regalloc(&n1, nl->type, N);
 +              cgen(nl, &n1);
 +      }
 +      gins(a, &n2, &n1);
 +      // Normalize result for types smaller than word.
 +      if(n->type->width < widthreg) {
 +              switch(n->op) {
 +              case OADD:
 +              case OSUB:
 +              case OMUL:
 +              case OLSH:
 +                      gins(optoas(OAS, n->type), &n1, &n1);
 +                      break;
 +              }
 +      }
 +      gmove(&n1, res);
 +      regfree(&n1);
 +      if(n2.op != OLITERAL)
 +              regfree(&n2);
 +      goto ret;
 +
 +uop:  // unary
 +      regalloc(&n1, nl->type, res);
 +      cgen(nl, &n1);
 +      gins(a, N, &n1);
 +      gmove(&n1, res);
 +      regfree(&n1);
 +      goto ret;
 +
 +ret:
 +      ;
 +}
 +
 +/*
 + * allocate a register (reusing res if possible) and generate
 + *  a = 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, n->type, 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;
 +      }
 +}
 +
 +/*
 + * allocate a register (reusing res if possible) and generate
 + * a = &n
 + * The caller must call 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;
 +
 +      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[TINT64]);
 +                      if(!isconst(nl, CTSTR))
 +                              agenr(nl, &n3, res);
 +                      if(!isconst(nr, CTINT)) {
 +                              cgen(nr, &tmp);
 +                              regalloc(&n1, tmp.type, N);
 +                              gmove(&tmp, &n1);
 +                      }
 +              } else if(nl->addable) {
 +                      if(!isconst(nr, CTINT)) {
 +                              tempname(&tmp, types[TINT64]);
 +                              cgen(nr, &tmp);
 +                              regalloc(&n1, tmp.type, N);
 +                              gmove(&tmp, &n1);
 +                      }
 +                      if(!isconst(nl, CTSTR)) {
 +                              agenr(nl, &n3, res);
 +                      }
 +              } else {
 +                      tempname(&tmp, types[TINT64]);
 +                      cgen(nr, &tmp);
 +                      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);
 +                                      ginscon2(optoas(OCMP, types[TUINT64]), &n4, v);
 +                                      regfree(&n4);
 +                                      p1 = gbranch(optoas(OGT, types[TUINT64]), T, +1);
 +                                      ginscall(panicindex, 0);
 +                                      patch(p1, pc);
 +                              }
 +
 +                              n1 = n3;
 +                              n1.op = OINDREG;
 +                              n1.type = types[tptr];
 +                              n1.xoffset = Array_array;
 +                              gmove(&n1, &n3);
 +                      }
 +
 +                      if (v*w != 0) {
 +                              ginscon(optoas(OADD, types[tptr]), v*w, &n3);
 +                      }
 +                      *a = n3;
 +                      break;
 +              }
 +
 +              regalloc(&n2, types[TINT64], &n1);                      // i
 +              gmove(&n1, &n2);
 +              regfree(&n1);
 +
 +              if(!debug['B'] && !n->bounded) {
 +                      // check bounds
 +                      if(isconst(nl, CTSTR)) {
 +                              nodconst(&n4, types[TUINT64], 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[TUINT64], N);
 +                              gmove(&n1, &n4);
 +                      } else {
 +                              if(nl->type->bound < (1<<15)-1)
 +                                      nodconst(&n4, types[TUINT64], nl->type->bound);
 +                              else {
 +                                      regalloc(&n4, types[TUINT64], N);
 +                                      p1 = gins(AMOVD, N, &n4);
 +                                      p1->from.type = D_CONST;
 +                                      p1->from.offset = nl->type->bound;
 +                              }
 +                      }
 +                      gins(optoas(OCMP, types[TUINT64]), &n2, &n4);
 +                      if(n4.op == OREGISTER)
 +                              regfree(&n4);
 +                      p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
 +                      if(p2)
 +                              patch(p2, pc);
 +                      ginscall(panicindex, 0);
 +                      patch(p1, pc);
 +              }
 +              
 +              if(isconst(nl, CTSTR)) {
 +                      regalloc(&n3, types[tptr], res);
 +                      p1 = gins(AMOVD, N, &n3);
 +                      datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
 +                      p1->from.type = D_CONST;
 +              } 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 already scaled */
 +                      gins(optoas(OADD, types[tptr]), &n2, &n3);
 +              } /* else if(w == 2 || w == 4 || w == 8) {
 +                      // TODO(minux): scale using shift
 +              } */ else {
 +                      regalloc(&n4, types[TUINT64], N);
 +                      nodconst(&n1, types[TUINT64], w);
 +                      gmove(&n1, &n4);
 +                      gins(optoas(OMUL, types[TUINT64]), &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;
 +      }
 +}
 +
 +static void
 +ginsadd(int as, vlong off, Node *dst)
 +{
 +      Node n1;
 +
 +      regalloc(&n1, types[tptr], dst);
 +      gmove(dst, &n1);
 +      ginscon(as, off, &n1);
 +      gmove(&n1, dst);
 +      regfree(&n1);
 +}
 +
 +/*
 + * generate:
 + *    res = &n;
 + * The generated code checks that the result is not nil.
 + */
 +void
 +agen(Node *n, Node *res)
 +{
 +      Node *nl, *nr;
 +      Node n1, n2, n3;
 +
 +      if(debug['g']) {
 +              dump("\nagen-res", res);
 +              dump("agen-r", n);
 +      }
 +      if(n == N || n->type == T)
 +              return;
 +
 +      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);
 +              memset(&n3, 0, sizeof n3);
 +              n3.op = OADDR;
 +              n3.left = &n1;
 +              gins(AMOVD, &n3, &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(AMOVD, &n1, &n2);
 +              gmove(&n2, res);
 +              regfree(&n2);
 +              goto ret;
 +      }
 +
 +      nl = n->left;
 +      nr = n->right;
 +      USED(nr);
 +
 +      switch(n->op) {
 +      default:
 +              fatal("agen: unknown op %+hN", n);
 +              break;
 +
 +      case OCALLMETH:
 +              // TODO(minux): 5g has this: Release res so that it is available for cgen_call.
 +              // Pick it up again after the call for OCALLMETH and OCALLFUNC.
 +              cgen_callmeth(n, 0);
 +              cgen_aret(n, res);
 +              break;
 +
 +      case OCALLINTER:
 +              cgen_callinter(n, res, 0);
 +              cgen_aret(n, res);
 +              break;
 +
 +      case OCALLFUNC:
 +              cgen_call(n, 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) {
 +                      ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
 +              }
 +              break;
 +
 +      case OIND:
 +              cgen(nl, res);
 +              cgen_checknil(res);
 +              break;
 +
 +      case ODOT:
 +              agen(nl, res);
 +              if(n->xoffset != 0) {
 +                      ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
 +              }
 +              break;
 +
 +      case ODOTPTR:
 +              cgen(nl, res);
 +              cgen_checknil(res);
 +              if(n->xoffset != 0) {
 +                      ginsadd(optoas(OADD, types[tptr]), n->xoffset, res);
 +              }
 +              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)
 +{
 +      Type *fp;
 +      Iter flist;
 +      Node n1;
 +
 +      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 != D_R0+REGSP)
 +                      reg[n->val.u.reg]++;
 +              *a = *n;
 +              return;
 +
 +      case ODOT:
 +              igen(n->left, a, res);
 +              a->xoffset += n->xoffset;
 +              a->type = n->type;
 +              fixlargeoffset(a);
 +              return;
 +
 +      case ODOTPTR:
 +              cgenr(n->left, a, res);
 +              cgen_checknil(a);
 +              a->op = OINDREG;
 +              a->xoffset += n->xoffset;
 +              a->type = n->type;
 +              fixlargeoffset(a);
 +              return;
 +
 +      case OCALLFUNC:
 +      case OCALLMETH:
 +      case OCALLINTER:
 +              switch(n->op) {
 +              case OCALLFUNC:
 +                      cgen_call(n, 0);
 +                      break;
 +              case OCALLMETH:
 +                      cgen_callmeth(n, 0);
 +                      break;
 +              case OCALLINTER:
 +                      cgen_callinter(n, N, 0);
 +                      break;
 +              }
 +              fp = structfirst(&flist, getoutarg(n->left->type));
 +              memset(a, 0, sizeof *a);
 +              a->op = OINDREG;
 +              a->val.u.reg = D_R0+REGSP;
 +              a->addable = 1;
 +              a->xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
 +              a->type = n->type;
 +              return;
 +
 +      case OINDEX:
 +              // Index of fixed-size array by constant can
 +              // put the offset in the addressing.
 +              // Could do the same for slice except that we need
 +              // to use the real index for the bounds checking.
 +              if(isfixedarray(n->left->type) ||
 +                 (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
 +              if(isconst(n->right, CTINT)) {
 +                      // Compute &a.
 +                      if(!isptr[n->left->type->etype])
 +                              igen(n->left, a, res);
 +                      else {
 +                              igen(n->left, &n1, res);
 +                              cgen_checknil(&n1);
 +                              regalloc(a, types[tptr], res);
 +                              gmove(&n1, a);
 +                              regfree(&n1);
 +                              a->op = OINDREG;
 +                      }
 +
 +                      // Compute &a[i] as &a + i*width.
 +                      a->type = n->type;
 +                      a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
 +                      fixlargeoffset(a);
 +                      return;
 +              }
 +              break;
 +      }
 +
 +      agenr(n, a, res);
 +      a->op = OINDREG;
 +      a->type = n->type;
 +}
 +
 +/*
 + * generate:
 + *    if(n == true) goto to;
 + */
 +void
 +bgen(Node *n, int true, int likely, Prog *to)
 +{
 +      int et, a;
 +      Node *nl, *nr, *l, *r;
 +      Node n1, n2, 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;
 +
 +      while(n->op == OCONVNOP) {
 +              n = n->left;
 +              if(n->ninit != nil)
 +                      genlist(n->ninit);
 +      }
 +
 +      switch(n->op) {
 +      default:
 +              regalloc(&n1, n->type, N);
 +              cgen(n, &n1);
 +              nodconst(&n2, n->type, 0);
 +              gins(optoas(OCMP, n->type), &n1, &n2);
 +              a = ABNE;
 +              if(!true)
 +                      a = ABEQ;
 +              patch(gbranch(a, n->type, likely), to);
 +              regfree(&n1);
 +              goto ret;
 +
 +      case OLITERAL:
 +              // need to ask if it is bool?
 +              if(!true == !n->val.u.bval)
 +                      patch(gbranch(ABR, T, likely), to);
 +              goto ret;
 +
 +      case OANDAND:
 +              if(!true)
 +                      goto caseor;
 +
 +      caseand:
 +              p1 = gbranch(ABR, T, 0);
 +              p2 = gbranch(ABR, T, 0);
 +              patch(p1, pc);
 +              bgen(n->left, !true, -likely, p2);
 +              bgen(n->right, !true, -likely, p2);
 +              p1 = gbranch(ABR, T, 0);
 +              patch(p1, to);
 +              patch(p2, pc);
 +              goto ret;
 +
 +      case OOROR:
 +              if(!true)
 +                      goto caseand;
 +
 +      caseor:
 +              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;
 +              break;
 +      }
 +
 +      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[nr->type->etype]) {
 +                              // brcom is not valid on floats when NaN is involved.
 +                              p1 = gbranch(ABR, T, 0);
 +                              p2 = gbranch(ABR, T, 0);
 +                              patch(p1, pc);
 +                              ll = n->ninit;   // avoid re-genning ninit
 +                              n->ninit = nil;
 +                              bgen(n, 1, -likely, p2);
 +                              n->ninit = ll;
 +                              patch(gbranch(ABR, T, 0), to);
 +                              patch(p2, pc);
 +                              goto ret;
 +                      }
 +                      a = brcom(a);
 +                      true = !true;
 +              }
 +
 +              // make simplest on right
 +              if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
 +                      a = brrev(a);
 +                      r = nl;
 +                      nl = nr;
 +                      nr = r;
 +              }
 +
 +              if(isslice(nl->type)) {
 +                      // front end should only leave cmp to literal nil
 +                      if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
 +                              yyerror("illegal slice comparison");
 +                              break;
 +                      }
 +                      a = optoas(a, types[tptr]);
 +                      igen(nl, &n1, N);
 +                      n1.xoffset += Array_array;
 +                      n1.type = types[tptr];
 +                      nodconst(&tmp, types[tptr], 0);
 +                      regalloc(&n2, types[tptr], &n1);
 +                      gmove(&n1, &n2);
 +                      gins(optoas(OCMP, types[tptr]), &n2, &tmp);
 +                      regfree(&n2);
 +                      patch(gbranch(a, types[tptr], likely), to);
 +                      regfree(&n1);
 +                      break;
 +              }
 +
 +              if(isinter(nl->type)) {
 +                      // front end should only leave cmp to literal nil
 +                      if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
 +                              yyerror("illegal interface comparison");
 +                              break;
 +                      }
 +                      a = optoas(a, types[tptr]);
 +                      igen(nl, &n1, N);
 +                      n1.type = types[tptr];
 +                      nodconst(&tmp, types[tptr], 0);
 +                      regalloc(&n2, types[tptr], &n1);
 +                      gmove(&n1, &n2);
 +                      gins(optoas(OCMP, types[tptr]), &n2, &tmp);
 +                      regfree(&n2);
 +                      patch(gbranch(a, types[tptr], likely), to);
 +                      regfree(&n1);
 +                      break;
 +              }
 +              if(iscomplex[nl->type->etype]) {
 +                      complexbool(a, nl, nr, true, likely, to);
 +                      break;
 +              }
 +
 +              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);
 +
 +                      goto cmp;
 +              }
 +
 +              regalloc(&n1, nl->type, N);
 +              cgen(nl, &n1);
 +
 +              // TODO(minux): cmpi does accept 16-bit signed immediate as p->to.
 +              // and cmpli accepts 16-bit unsigned immediate.
 +              //if(smallintconst(nr)) {
 +              //      gins(optoas(OCMP, nr->type), &n1, nr);
 +              //      patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
 +              //      regfree(&n1);
 +              //      break;
 +              //}
 +
 +              regalloc(&n2, nr->type, N);
 +              cgen(nr, &n2);
 +      cmp:
 +              l = &n1;
 +              r = &n2;
 +              gins(optoas(OCMP, nr->type), l, r);
 +              if(isfloat[nr->type->etype] && (a == OLE || a == OGE)) {
 +                      // To get NaN right, must rewrite x <= y into separate x < y or x = y.
 +                      switch(a) {
 +                      case OLE:
 +                              a = OLT;
 +                              break;
 +                      case OGE:
 +                              a = OGT;
 +                              break;
 +                      }
 +                      patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
 +                      patch(gbranch(optoas(OEQ, nr->type), nr->type, likely), to);                    
 +              } else {
 +                      patch(gbranch(optoas(a, nr->type), 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.
 + */
 +int64
 +stkof(Node *n)
 +{
 +      Type *t;
 +      Iter flist;
 +      int64 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 + widthptr;     // +widthptr: correct for saved LR
 +              break;
 +      }
 +
 +      // botch - probably failing to recognize address
 +      // arithmetic on the above. eg INDEX and DOT
 +      return -1000;
 +}
 +
 +/*
 + * block copy:
 + *    memmove(&ns, &n, w);
 + */
 +void
 +sgen(Node *n, Node *ns, int64 w)
 +{
 +      Node dst, src, tmp, nend;
 +      int32 c, odst, osrc;
 +      int dir, align, op;
 +      Prog *p, *ploop;
 +      NodeList *l;
 +      Node *res = ns;
 +
 +      if(debug['g']) {
 +              print("\nsgen w=%lld\n", w);
 +              dump("r", n);
 +              dump("res", ns);
 +      }
 +
 +      if(n->ullman >= UINF && ns->ullman >= UINF)
 +              fatal("sgen UINF");
 +
 +      if(w < 0)
 +              fatal("sgen copy %lld", w);
 +      
 +      // If copying .args, that's all the results, so record definition sites
 +      // for them for the liveness analysis.
 +      if(ns->op == ONAME && strcmp(ns->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, ns))
 +      //      return;
 +      
 +      if(w == 0) {
 +              // evaluate side effects only.
 +              regalloc(&dst, types[tptr], N);
 +              agen(res, &dst);
 +              agen(n, &dst);
 +              regfree(&dst);
 +              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 = AMOVBU;
 +              break;
 +      case 2:
 +              op = AMOVHU;
 +              break;
 +      case 4:
 +              op = AMOVWZU; // there is no lwau, only lwaux
 +              break;
 +      case 8:
 +              op = AMOVDU;
 +              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(n->ullman >= res->ullman) {
 +              agenr(n, &dst, res);    // temporarily use dst
 +              regalloc(&src, types[tptr], N);
 +              gins(AMOVD, &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[tptr], N);
 +
 +      // set up end marker
 +      memset(&nend, 0, sizeof nend);
 +
 +      // move src and dest to the end of block if necessary
 +      if(dir < 0) {
 +              if(c >= 4) {
 +                      regalloc(&nend, types[tptr], N);
 +                      p = gins(AMOVD, &src, &nend);
 +              }
 +
 +              p = gins(AADD, N, &src);
 +              p->from.type = D_CONST;
 +              p->from.offset = w;
 +
 +              p = gins(AADD, N, &dst);
 +              p->from.type = D_CONST;
 +              p->from.offset = w;
 +      } else {
 +              p = gins(AADD, N, &src);
 +              p->from.type = D_CONST;
 +              p->from.offset = -dir;
 +
 +              p = gins(AADD, N, &dst);
 +              p->from.type = D_CONST;
 +              p->from.offset = -dir;
 +
 +              if(c >= 4) {
 +                      regalloc(&nend, types[tptr], N);
 +                      p = gins(AMOVD, &src, &nend);
 +                      p->from.type = D_CONST;
 +                      p->from.offset = w;
 +              }
 +      }
 +
 +
 +      // move
 +      // TODO: enable duffcopy for larger copies.
 +      if(c >= 4) {
 +              p = gins(op, &src, &tmp);
 +              p->from.type = D_OREG;
 +              p->from.offset = dir;
 +              ploop = p;
 +
 +              p = gins(op, &tmp, &dst);
 +              p->to.type = D_OREG;
 +              p->to.offset = dir;
 +
 +              p = gins(ACMP, &src, &nend);
 +
 +              patch(gbranch(ABNE, T, 0), ploop);
 +              regfree(&nend);
 +      } else {
 +              while(c-- > 0) {
 +                      p = gins(op, &src, &tmp);
 +                      p->from.type = D_OREG;
 +                      p->from.offset = dir;
 +      
 +                      p = gins(op, &tmp, &dst);
 +                      p->to.type = D_OREG;
 +                      p->to.offset = dir;
 +              }
 +      }
 +
 +      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 can't.
 + */
 +int
 +componentgen(Node *nr, Node *nl)
 +{
 +      Node nodl, nodr;
 +      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;
 +              }
 +      }
 +      
 +      // 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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +              } else
 +                      nodconst(&nodr, nodl.type, 0);
 +              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;
 +}
diff --cc src/cmd/9g/gg.h
index 6aa00117f8fdb83065147d12bf05773d97b6fc64,0000000000000000000000000000000000000000..2eb516b403b6532030cd8bc25ec4c13cecdfeb68
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,118 @@@
- void  clearslim(Node*);
 +// Copyright 2014 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.
 +
 +#ifndef       EXTERN
 +#define       EXTERN  extern
 +#endif
 +
 +#include "../gc/go.h"
 +#include "../9l/9.out.h"
 +
 +// TODO(minux): Remove when no longer used.
 +#define noimpl sysfatal("%s not implemented (%s:%d).", __func__, __FILE__, __LINE__)
 +
 +#define TEXTFLAG reg
 +
 +EXTERN        int32   dynloc;
 +EXTERN        uchar   reg[NREG+NFREG];
 +EXTERN        int32   pcloc;          // instruction counter
 +EXTERN        Strlit  emptystring;
 +EXTERN        Prog    zprog;
 +EXTERN        Node*   newproc;
 +EXTERN        Node*   deferproc;
 +EXTERN        Node*   deferreturn;
 +EXTERN        Node*   panicindex;
 +EXTERN        Node*   panicslice;
 +EXTERN        Node*   panicdiv;
 +EXTERN        Node*   throwreturn;
 +extern        vlong   unmappedzero;
 +
 +/*
 + * ggen.c
 + */
 +void  compile(Node*);
 +void  gen(Node*);
 +Node* lookdot(Node*, Node*, int);
 +void  cgen_as(Node*, Node*);
 +void  cgen_callmeth(Node*, int);
 +void  cgen_callinter(Node*, Node*, int);
 +void  cgen_proc(Node*, int);
 +void  cgen_callret(Node*, Node*);
 +void  cgen_div(int, Node*, Node*, Node*);
 +void  cgen_hmul(Node*, Node*, Node*);
 +void  cgen_shift(int, int, Node*, Node*, Node*);
 +void  cgen_dcl(Node*);
 +int   needconvert(Type*, Type*);
 +void  genconv(Type*, Type*);
 +void  allocparams(void);
 +void  checklabels(void);
 +void  ginscall(Node*, int);
 +int   gen_as_init(Node*);
 +
 +/*
 + * cgen.c
 + */
 +void  agen(Node*, Node*);
 +void  agenr(Node*, Node*, Node*);
 +void  cgenr(Node*, Node*, Node*);
 +void  igen(Node*, Node*, Node*);
 +vlong fieldoffset(Type*, Node*);
 +void  sgen(Node*, Node*, int64);
 +void  gmove(Node*, Node*);
 +Prog* gins(int, Node*, Node*);
 +void  naddr(Node*, Addr*, int);
 +void  cgen_aret(Node*, Node*);
 +int   componentgen(Node*, Node*);
 +
 +/*
 + * gsubr.c
 + */
 +void  clearp(Prog*);
 +Prog* gbranch(int, Type*, int);
 +Prog* prog(int);
 +void  gconv(int, int);
 +int   conv2pt(Type*);
 +vlong convvtox(vlong, int);
 +void  fnparam(Type*, int, int);
 +Prog* gop(int, Node*, Node*, Node*);
 +int   optoas(int, Type*);
 +void  ginit(void);
 +void  gclean(void);
 +void  regalloc(Node*, Type*, Node*);
 +void  regfree(Node*);
 +Node* nodarg(Type*, int);
 +void  nodreg(Node*, Type*, int);
 +void  nodindreg(Node*, Type*, int);
 +void  ginscon(int, vlong, Node*);
 +void  ginscon2(int, Node*, vlong);
 +void  buildtxt(void);
 +Plist*        newplist(void);
 +int   isfat(Type*);
 +void  sudoclean(void);
 +int   sudoaddable(int, Node*, Addr*);
 +void  afunclit(Addr*, Node*);
 +void  nodfconst(Node*, Type*, Mpflt*);
 +void  gtrack(Sym*);
 +void  gargsize(vlong);
 +void  fixlargeoffset(Node *n);
 +
 +/*
 + * cplx.c
 + */
 +int   complexop(Node*, Node*);
 +void  complexmove(Node*, Node*);
 +void  complexgen(Node*, Node*);
 +
 +/*
 + * gobj.c
 + */
 +void  datastring(char*, int, Addr*);
 +void  datagostring(Strlit*, Addr*);
 +
 +/*
 + * list.c
 + */
 +void  listinit(void);
 +
 +void  zaddr(Biobuf*, Addr*, int, int);
index dfdff058793376523664af27d07f452522926c87,0000000000000000000000000000000000000000..b194cfd9eef0fe3656e405169154cd9a25ffc566
mode 100644,000000..100644
--- /dev/null
@@@ -1,1720 -1,0 +1,1715 @@@
-               return 1;
 +// Derived from Inferno utils/6c/txt.c
 +// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +#include <u.h>
 +#include <libc.h>
 +#include "gg.h"
 +#include "../../pkg/runtime/funcdata.h"
 +
 +// TODO(rsc): Can make this bigger if we move
 +// the text segment up higher in 6l for all GOOS.
 +// At the same time, can raise StackBig in ../../pkg/runtime/stack.h.
 +vlong unmappedzero = 4096;
 +
 +void
 +clearp(Prog *p)
 +{
 +      *p = zprog;
 +      p->as = AEND;
 +      p->pc = pcloc;
 +      pcloc++;
 +}
 +
 +static int ddumped;
 +static Prog *dfirst;
 +static Prog *dpc;
 +
 +/*
 + * generate and return proc with p->as = as,
 + * linked into program. pc is next instruction.
 + */
 +Prog*
 +prog(int as)
 +{
 +      Prog *p;
 +
 +      if(as == ADATA || as == AGLOBL) {
 +              if(ddumped)
 +                      fatal("already dumped data");
 +              if(dpc == nil) {
 +                      dpc = mal(sizeof(*dpc));
 +                      dfirst = dpc;
 +              }
 +              p = dpc;
 +              dpc = mal(sizeof(*dpc));
 +              p->link = dpc;
 +              p->reg = 0; // used for flags
 +      } else {
 +              p = pc;
 +              pc = mal(sizeof(*pc));
 +              clearp(pc);
 +              p->link = pc;
 +      }
 +
 +      if(lineno == 0) {
 +              if(debug['K'])
 +                      warn("prog: line 0");
 +      }
 +
 +      p->as = as;
 +      p->lineno = lineno;
 +      return p;
 +}
 +
 +void
 +dumpdata(void)
 +{
 +      ddumped = 1;
 +      if(dfirst == nil)
 +              return;
 +      newplist();
 +      *pc = *dfirst;
 +      pc = dpc;
 +      clearp(pc);
 +}
 +
 +/*
 + * generate a branch.
 + * t is ignored.
 + * likely values are for branch prediction:
 + *    -1 unlikely
 + *    0 no opinion
 + *    +1 likely
 + */
 +Prog*
 +gbranch(int as, Type *t, int likely)
 +{
 +      Prog *p;
 +      
 +      USED(t);
 +
 +      p = prog(as);
 +      p->to.type = D_BRANCH;
 +      p->to.u.branch = P;
 +      // TODO(minux): Enable this code.
 +      // Note: liblink used Bcc CR0, label form, so we need another way
 +      // to set likely/unlikely flag. Also note the y bit is not exactly
 +      // likely/unlikely bit.
 +      if(0 && as != ABR && likely != 0) {
 +              p->from.type = D_CONST;
 +              p->from.offset = likely > 0;
 +      }
 +      return p;
 +}
 +
 +/*
 + * patch previous branch to jump to to.
 + */
 +void
 +patch(Prog *p, Prog *to)
 +{
 +      if(p->to.type != D_BRANCH)
 +              fatal("patch: not a branch");
 +      p->to.u.branch = to;
 +      p->to.offset = to->pc;
 +}
 +
 +Prog*
 +unpatch(Prog *p)
 +{
 +      Prog *q;
 +
 +      if(p->to.type != D_BRANCH)
 +              fatal("unpatch: not a branch");
 +      q = p->to.u.branch;
 +      p->to.u.branch = P;
 +      p->to.offset = 0;
 +      return q;
 +}
 +
 +/*
 + * start a new Prog list.
 + */
 +Plist*
 +newplist(void)
 +{
 +      Plist *pl;
 +
 +      pl = linknewplist(ctxt);
 +
 +      pc = mal(sizeof(*pc));
 +      clearp(pc);
 +      pl->firstpc = pc;
 +
 +      return pl;
 +}
 +
 +void
 +gused(Node *n)
 +{
 +      gins(ANOP, n, N);       // used
 +}
 +
 +Prog*
 +gjmp(Prog *to)
 +{
 +      Prog *p;
 +
 +      p = gbranch(ABR, T, 0);
 +      if(to != P)
 +              patch(p, to);
 +      return p;
 +}
 +
 +void
 +ggloblnod(Node *nam)
 +{
 +      Prog *p;
 +
 +      p = gins(AGLOBL, nam, N);
 +      p->lineno = nam->lineno;
 +      p->from.sym->gotype = linksym(ngotype(nam));
 +      p->to.sym = nil;
 +      p->to.type = D_CONST;
 +      p->to.offset = nam->type->width;
 +      if(nam->readonly)
 +              p->reg = RODATA;
 +      if(nam->type != T && !haspointers(nam->type))
 +              p->reg |= NOPTR;
 +}
 +
 +void
 +gtrack(Sym *s)
 +{
 +      Prog *p;
 +      
 +      p = gins(AUSEFIELD, N, N);
 +      p->from.type = D_OREG;
 +      p->from.name = D_EXTERN;
 +      p->from.sym = linksym(s);
 +}
 +
 +void
 +gargsize(vlong size)
 +{
 +      Node n1, n2;
 +      
 +      nodconst(&n1, types[TINT32], PCDATA_ArgSize);
 +      nodconst(&n2, types[TINT32], size);
 +      gins(APCDATA, &n1, &n2);
 +}
 +
 +void
 +ggloblsym(Sym *s, int32 width, int8 flags)
 +{
 +      Prog *p;
 +
 +      p = gins(AGLOBL, N, N);
 +      p->from.type = D_OREG;
 +      p->from.name = D_EXTERN;
 +      p->from.sym = linksym(s);
 +      p->to.type = D_CONST;
 +      p->to.name = D_NONE;
 +      p->to.offset = width;
 +      p->reg = flags;
 +}
 +
 +int
 +isfat(Type *t)
 +{
 +      if(t != T)
 +      switch(t->etype) {
 +      case TSTRUCT:
 +      case TARRAY:
 +      case TSTRING:
 +      case TINTER:    // maybe remove later
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +/*
 + * naddr of func generates code for address of func.
 + * if using opcode that can take address implicitly,
 + * call afunclit to fix up the argument.
 + */
 +void
 +afunclit(Addr *a, Node *n)
 +{
 +      if(a->type == D_CONST && a->name == D_EXTERN) {
 +              a->type = D_OREG;
 +              a->sym = linksym(n->sym);
 +      }
 +}
 +
 +static        int     resvd[] =
 +{
 +      REGZERO,
 +      REGSP,  // reserved for SP, XXX: not reserved in 9c.
 +      30,     // for g
 +      REGTMP, // REGTMP
 +      FREGCVI+NREG,
 +      FREGZERO+NREG,
 +      FREGHALF+NREG,
 +      FREGONE+NREG,
 +      FREGTWO+NREG,
 +};
 +
 +void
 +ginit(void)
 +{
 +      int i;
 +
 +      for(i=0; i<nelem(reg); i++)
 +              reg[i] = 1;
 +      for(i=0; i<NREG; i++)
 +              reg[i] = 0;
 +      for(i=NREG; i<NREG+NREG; i++)
 +              reg[i] = 0;
 +
 +      for(i=0; i<nelem(resvd); i++)
 +              reg[resvd[i]]++;
 +}
 +
 +static        uintptr regpc[nelem(reg)];
 +
 +void
 +gclean(void)
 +{
 +      int i;
 +
 +      for(i=0; i<nelem(resvd); i++)
 +              reg[resvd[i]]--;
 +
 +      for(i=0; i<nelem(reg); i++)
 +              if(reg[i])
 +                      yyerror("reg %R left allocated, %p\n", i, regpc[i]);
 +}
 +
 +int32
 +anyregalloc(void)
 +{
 +      int i, j;
 +
 +      for(i=0; i<nelem(reg); i++) {
 +              if(reg[i] == 0)
 +                      goto ok;
 +              for(j=0; j<nelem(resvd); j++)
 +                      if(resvd[j] == i)
 +                              goto ok;
 +              return 1;
 +      ok:;
 +      }
 +      return 0;
 +}
 +
 +/*
 + * allocate register of type t, leave in n.
 + * if o != N, o is desired fixed register.
 + * caller must regfree(n).
 + */
 +void
 +regalloc(Node *n, Type *t, Node *o)
 +{
 +      int i, et;
 +      int fixfree, fltfree;
 +
 +      if(t == T)
 +              fatal("regalloc: t nil");
 +      et = simtype[t->etype];
 +
 +      if(debug['r']) {
 +              fixfree = 0;
 +              fltfree = 0;
 +              for(i = D_R0; i < D_F0+NREG; i++)
 +                      if(reg[i] == 0) {
 +                              if(i < D_F0)
 +                                      fixfree++;
 +                              else
 +                                      fltfree++;
 +                      }
 +              print("regalloc fix %d flt %d free\n", fixfree, fltfree);
 +      }
 +
 +      switch(et) {
 +      case TINT8:
 +      case TUINT8:
 +      case TINT16:
 +      case TUINT16:
 +      case TINT32:
 +      case TUINT32:
 +      case TINT64:
 +      case TUINT64:
 +      case TPTR32:
 +      case TPTR64:
 +      case TBOOL:
 +              if(o != N && o->op == OREGISTER) {
 +                      i = o->val.u.reg;
 +                      if(i >= D_R0+REGMIN && i <= D_R0+REGMAX)
 +                              goto out;
 +              }
 +              for(i=D_R0+REGMIN; i<=D_R0+REGMAX; i++)
 +                      if(reg[i] == 0) {
 +                              regpc[i] = (uintptr)getcallerpc(&n);
 +                              goto out;
 +                      }
 +              flusherrors();
 +              for(i=D_R0; i<D_R0+NREG; i++)
 +                      print("R%d %p\n", i, regpc[i]);
 +              fatal("out of fixed registers");
 +
 +      case TFLOAT32:
 +      case TFLOAT64:
 +              if(o != N && o->op == OREGISTER) {
 +                      i = o->val.u.reg;
 +                      if(i >= D_F0+FREGMIN && i <= D_F0+FREGMAX)
 +                              goto out;
 +              }
 +              for(i=D_F0+FREGMIN; i<=D_F0+FREGMAX; i++)
 +                      if(reg[i] == 0) {
 +                              regpc[i] = (uintptr)getcallerpc(&n);
 +                              goto out;
 +                      }
 +              flusherrors();
 +              for(i=D_F0; i<D_F0+NREG; i++)
 +                      print("F%d %p\n", i, regpc[i]);
 +              fatal("out of floating registers");
 +
 +      case TCOMPLEX64:
 +      case TCOMPLEX128:
 +              tempname(n, t);
 +              return;
 +      }
 +      fatal("regalloc: unknown type %T", t);
 +      return;
 +
 +out:
 +      reg[i]++;
 +      nodreg(n, t, i);
 +}
 +
 +void
 +regfree(Node *n)
 +{
 +      int i;
 +
 +      if(n->op == ONAME)
 +              return;
 +      if(n->op != OREGISTER && n->op != OINDREG)
 +              fatal("regfree: not a register");
 +      i = n->val.u.reg;
 +      if(i == D_R0 + REGSP)
 +              return;
 +      if(i < 0 || i >= nelem(reg))
 +              fatal("regfree: reg out of range");
 +      if(reg[i] <= 0)
 +              fatal("regfree: reg not allocated");
 +      reg[i]--;
 +      if(reg[i] == 0)
 +              regpc[i] = 0;
 +}
 +
 +/*
 + * initialize n to be register r of type t.
 + */
 +void
 +nodreg(Node *n, Type *t, int r)
 +{
 +      if(t == T)
 +              fatal("nodreg: t nil");
 +
 +      memset(n, 0, sizeof(*n));
 +      n->op = OREGISTER;
 +      n->addable = 1;
 +      ullmancalc(n);
 +      n->val.u.reg = r;
 +      n->type = t;
 +}
 +
 +/*
 + * initialize n to be indirect of register r; n is type t.
 + */
 +void
 +nodindreg(Node *n, Type *t, int r)
 +{
 +      nodreg(n, t, r);
 +      n->op = OINDREG;
 +}
 +
 +Node*
 +nodarg(Type *t, int fp)
 +{
 +      Node *n;
 +      NodeList *l;
 +      Type *first;
 +      Iter savet;
 +
 +      // entire argument struct, not just one arg
 +      if(t->etype == TSTRUCT && t->funarg) {
 +              n = nod(ONAME, N, N);
 +              n->sym = lookup(".args");
 +              n->type = t;
 +              first = structfirst(&savet, &t);
 +              if(first == nil)
 +                      fatal("nodarg: bad struct");
 +              if(first->width == BADWIDTH)
 +                      fatal("nodarg: offset not computed for %T", t);
 +              n->xoffset = first->width;
 +              n->addable = 1;
 +              goto fp;
 +      }
 +
 +      if(t->etype != TFIELD)
 +              fatal("nodarg: not field %T", t);
 +      
 +      if(fp == 1) {
 +              for(l=curfn->dcl; l; l=l->next) {
 +                      n = l->n;
 +                      if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
 +                              return n;
 +              }
 +      }
 +
 +      n = nod(ONAME, N, N);
 +      n->type = t->type;
 +      n->sym = t->sym;
 +      
 +      if(t->width == BADWIDTH)
 +              fatal("nodarg: offset not computed for %T", t);
 +      n->xoffset = t->width;
 +      n->addable = 1;
 +      n->orig = t->nname;
 +
 +fp:
 +      // Rewrite argument named _ to __,
 +      // or else the assignment to _ will be
 +      // discarded during code generation.
 +      if(isblank(n))
 +              n->sym = lookup("__");
 +
 +      switch(fp) {
 +      default:
 +              fatal("nodarg %T %d", t, fp);
 +
 +      case 0:         // output arg for calling another function
 +              n->op = OINDREG;
 +              n->val.u.reg = D_R0+REGSP;
 +              n->xoffset += 8;
 +              break;
 +
 +      case 1:         // input arg to current function
 +              n->class = PPARAM;
 +              break;
 +
 +      case 2:         // offset output arg
 +fatal("shouldn't be used");
 +              n->op = OINDREG;
 +              n->val.u.reg = D_R0 + REGSP;
 +              n->xoffset += types[tptr]->width;
 +              break;
 +      }
 +      n->typecheck = 1;
 +      return n;
 +}
 +
 +/*
 + * generate
 + *    as $c, n
 + */
 +void
 +ginscon(int as, vlong c, Node *n2)
 +{
 +      Node n1, ntmp;
 +
 +      nodconst(&n1, types[TINT64], c);
 +
 +      if(as != AMOVD && (c < -BIG || c > BIG)) {
 +              // cannot have more than 16-bit of immediate in ADD, etc.
 +              // instead, MOV into register first.
 +              regalloc(&ntmp, types[TINT64], N);
 +              gins(AMOVD, &n1, &ntmp);
 +              gins(as, &ntmp, n2);
 +              regfree(&ntmp);
 +              return;
 +      }
 +      gins(as, &n1, n2);
 +}
 +
 +/*
 + * generate
 + *    as n, $c (CMP/CMPU)
 + */
 +void
 +ginscon2(int as, Node *n2, vlong c)
 +{
 +      Node n1, ntmp;
 +
 +      nodconst(&n1, types[TINT64], c);
 +
 +      switch(as) {
 +      default:
 +              fatal("ginscon2");
 +      case ACMP:
 +              if(-BIG <= c && c <= BIG) {
 +                      gins(as, n2, &n1);
 +                      return;
 +              }
 +              break;
 +      case ACMPU:
 +              if(0 <= c && c <= 2*BIG) {
 +                      gins(as, n2, &n1);
 +                      return;
 +              }
 +              break;
 +      }
 +      // MOV n1 into register first
 +      regalloc(&ntmp, types[TINT64], N);
 +      gins(AMOVD, &n1, &ntmp);
 +      gins(as, n2, &ntmp);
 +      regfree(&ntmp);
 +}
 +
 +#define       CASE(a,b)       (((a)<<16)|((b)<<0))
 +/*c2go int CASE(int, int); */
 +
 +/*
 + * Is this node a memory operand?
 + */
 +int
 +ismem(Node *n)
 +{
 +      switch(n->op) {
 +      case OITAB:
 +      case OSPTR:
 +      case OLEN:
 +      case OCAP:
 +      case OINDREG:
 +      case ONAME:
 +      case OPARAM:
 +      case OCLOSUREVAR:
-               //if(flag_largemodel)
-                       return 1;
-               break;
 +      case OADDR:
-       case CASE(OADDPTR, TPTR32):
++              return 1;
 +      }
 +      return 0;
 +}
 +
 +/*
 + * set up nodes representing 2^63
 + */
 +Node bigi;
 +Node bigf;
 +
 +void
 +bignodes(void)
 +{
 +      static int did;
 +
 +      if(did)
 +              return;
 +      did = 1;
 +
 +      nodconst(&bigi, types[TUINT64], 1);
 +      mpshiftfix(bigi.val.u.xval, 63);
 +
 +      bigf = bigi;
 +      bigf.type = types[TFLOAT64];
 +      bigf.val.ctype = CTFLT;
 +      bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
 +      mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
 +}
 +
 +/*
 + * generate move:
 + *    t = f
 + * hard part is conversions.
 + */
 +void
 +gmove(Node *f, Node *t)
 +{
 +      int a, ft, tt;
 +      Type *cvt;
 +      Node r1, r2, r3, con;
 +      Prog *p1, *p2;
 +
 +      if(debug['M'])
 +              print("gmove %lN -> %lN\n", f, t);
 +
 +      ft = simsimtype(f->type);
 +      tt = simsimtype(t->type);
 +      cvt = t->type;
 +
 +      if(iscomplex[ft] || iscomplex[tt]) {
 +              complexmove(f, t);
 +              return;
 +      }
 +
 +      // cannot have two memory operands
 +      if(ismem(f) && ismem(t))
 +              goto hard;
 +
 +      // convert constant to desired type
 +      if(f->op == OLITERAL) {
 +              switch(tt) {
 +              default:
 +                      convconst(&con, t->type, &f->val);
 +                      break;
 +
 +              case TINT32:
 +              case TINT16:
 +              case TINT8:
 +                      convconst(&con, types[TINT64], &f->val);
 +                      regalloc(&r1, con.type, t);
 +                      gins(AMOVD, &con, &r1);
 +                      gmove(&r1, t);
 +                      regfree(&r1);
 +                      return;
 +
 +              case TUINT32:
 +              case TUINT16:
 +              case TUINT8:
 +                      convconst(&con, types[TUINT64], &f->val);
 +                      regalloc(&r1, con.type, t);
 +                      gins(AMOVD, &con, &r1);
 +                      gmove(&r1, t);
 +                      regfree(&r1);
 +                      return;
 +              }
 +
 +              f = &con;
 +              ft = tt;        // so big switch will choose a simple mov
 +
 +              // constants can't move directly to memory.
 +              if(ismem(t)) {
 +                      goto hard;
 +                      // float constants come from memory.
 +                      //if(isfloat[tt])
 +                      //      goto hard;
 +
 +                      // 64-bit immediates are also from memory.
 +                      //if(isint[tt])
 +                      //      goto hard;
 +                      //// 64-bit immediates are really 32-bit sign-extended
 +                      //// unless moving into a register.
 +                      //if(isint[tt]) {
 +                      //      if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
 +                      //              goto hard;
 +                      //      if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
 +                      //              goto hard;
 +                      //}
 +              }
 +      }
 +
 +      // value -> value copy, only one memory operand.
 +      // figure out the instruction to use.
 +      // break out of switch for one-instruction gins.
 +      // goto rdst for "destination must be register".
 +      // goto hard for "convert to cvt type first".
 +      // otherwise handle and return.
 +
 +      switch(CASE(ft, tt)) {
 +      default:
 +              fatal("gmove %lT -> %lT", f->type, t->type);
 +
 +      /*
 +       * integer copy and truncate
 +       */
 +      case CASE(TINT8, TINT8):        // same size
 +      case CASE(TUINT8, TINT8):
 +      case CASE(TINT16, TINT8):       // truncate
 +      case CASE(TUINT16, TINT8):
 +      case CASE(TINT32, TINT8):
 +      case CASE(TUINT32, TINT8):
 +      case CASE(TINT64, TINT8):
 +      case CASE(TUINT64, TINT8):
 +              a = AMOVB;
 +              break;
 +
 +      case CASE(TINT8, TUINT8):       // same size
 +      case CASE(TUINT8, TUINT8):
 +      case CASE(TINT16, TUINT8):      // truncate
 +      case CASE(TUINT16, TUINT8):
 +      case CASE(TINT32, TUINT8):
 +      case CASE(TUINT32, TUINT8):
 +      case CASE(TINT64, TUINT8):
 +      case CASE(TUINT64, TUINT8):
 +              a = AMOVBZ;
 +              break;
 +
 +      case CASE(TINT16, TINT16):      // same size
 +      case CASE(TUINT16, TINT16):
 +      case CASE(TINT32, TINT16):      // truncate
 +      case CASE(TUINT32, TINT16):
 +      case CASE(TINT64, TINT16):
 +      case CASE(TUINT64, TINT16):
 +              a = AMOVH;
 +              break;
 +
 +      case CASE(TINT16, TUINT16):     // same size
 +      case CASE(TUINT16, TUINT16):
 +      case CASE(TINT32, TUINT16):     // truncate
 +      case CASE(TUINT32, TUINT16):
 +      case CASE(TINT64, TUINT16):
 +      case CASE(TUINT64, TUINT16):
 +              a = AMOVHZ;
 +              break;
 +
 +      case CASE(TINT32, TINT32):      // same size
 +      case CASE(TUINT32, TINT32):
 +      case CASE(TINT64, TINT32):      // truncate
 +      case CASE(TUINT64, TINT32):
 +              a = AMOVW;
 +              break;
 +
 +      case CASE(TINT32, TUINT32):     // same size
 +      case CASE(TUINT32, TUINT32):
 +      case CASE(TINT64, TUINT32):
 +      case CASE(TUINT64, TUINT32):
 +              a = AMOVWZ;
 +              break;
 +
 +      case CASE(TINT64, TINT64):      // same size
 +      case CASE(TINT64, TUINT64):
 +      case CASE(TUINT64, TINT64):
 +      case CASE(TUINT64, TUINT64):
 +              a = AMOVD;
 +              break;
 +
 +      /*
 +       * integer up-conversions
 +       */
 +      case CASE(TINT8, TINT16):       // sign extend int8
 +      case CASE(TINT8, TUINT16):
 +      case CASE(TINT8, TINT32):
 +      case CASE(TINT8, TUINT32):
 +      case CASE(TINT8, TINT64):
 +      case CASE(TINT8, TUINT64):
 +              a = AMOVB;
 +              goto rdst;
 +
 +      case CASE(TUINT8, TINT16):      // zero extend uint8
 +      case CASE(TUINT8, TUINT16):
 +      case CASE(TUINT8, TINT32):
 +      case CASE(TUINT8, TUINT32):
 +      case CASE(TUINT8, TINT64):
 +      case CASE(TUINT8, TUINT64):
 +              a = AMOVBZ;
 +              goto rdst;
 +
 +      case CASE(TINT16, TINT32):      // sign extend int16
 +      case CASE(TINT16, TUINT32):
 +      case CASE(TINT16, TINT64):
 +      case CASE(TINT16, TUINT64):
 +              a = AMOVH;
 +              goto rdst;
 +
 +      case CASE(TUINT16, TINT32):     // zero extend uint16
 +      case CASE(TUINT16, TUINT32):
 +      case CASE(TUINT16, TINT64):
 +      case CASE(TUINT16, TUINT64):
 +              a = AMOVHZ;
 +              goto rdst;
 +
 +      case CASE(TINT32, TINT64):      // sign extend int32
 +      case CASE(TINT32, TUINT64):
 +              a = AMOVW;
 +              goto rdst;
 +
 +      case CASE(TUINT32, TINT64):     // zero extend uint32
 +      case CASE(TUINT32, TUINT64):
 +              a = AMOVWZ;
 +              goto rdst;
 +
 +      /*
 +      * float to integer
 +      */
 +      case CASE(TFLOAT32, TINT32):
 +      case CASE(TFLOAT64, TINT32):
 +      case CASE(TFLOAT32, TINT64):
 +      case CASE(TFLOAT64, TINT64):
 +      case CASE(TFLOAT32, TINT16):
 +      case CASE(TFLOAT32, TINT8):
 +      case CASE(TFLOAT32, TUINT16):
 +      case CASE(TFLOAT32, TUINT8):
 +      case CASE(TFLOAT64, TINT16):
 +      case CASE(TFLOAT64, TINT8):
 +      case CASE(TFLOAT64, TUINT16):
 +      case CASE(TFLOAT64, TUINT8):
 +      case CASE(TFLOAT32, TUINT32):
 +      case CASE(TFLOAT64, TUINT32):
 +      case CASE(TFLOAT32, TUINT64):
 +      case CASE(TFLOAT64, TUINT64):
 +              //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
 +              //return;
 +              // algorithm is:
 +              //      if small enough, use native float64 -> int64 conversion.
 +              //      otherwise, subtract 2^63, convert, and add it back.
 +              bignodes();
 +              regalloc(&r1, types[ft], f);
 +              gmove(f, &r1);
 +              if(tt == TUINT64) {
 +                      regalloc(&r2, types[TFLOAT64], N);
 +                      gmove(&bigf, &r2);
 +                      gins(AFCMPU, &r1, &r2);
 +                      p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1);
 +                      gins(AFSUB, &r2, &r1);
 +                      patch(p1, pc);
 +                      regfree(&r2);
 +              }
 +              regalloc(&r2, types[TFLOAT64], N);
 +              regalloc(&r3, types[TINT64], t);
 +              gins(AFCTIDZ, &r1, &r2);
 +              p1 = gins(AFMOVD, &r2, N);
 +              p1->to.type = D_OREG;
 +              p1->to.reg = REGSP;
 +              p1->to.offset = -8;
 +              p1 = gins(AMOVD, N, &r3);
 +              p1->from.type = D_OREG;
 +              p1->from.reg = REGSP;
 +              p1->from.offset = -8;
 +              regfree(&r2);
 +              regfree(&r1);
 +              if(tt == TUINT64) {
 +                      p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1); // use CR0 here again
 +                      nodreg(&r1, types[TINT64], D_R0+REGTMP);
 +                      gins(AMOVD, &bigi, &r1);
 +                      gins(AADD, &r1, &r3);
 +                      patch(p1, pc);
 +              }
 +              gmove(&r3, t);
 +              regfree(&r3);
 +              return;
 +
 +      /*
 +       * integer to float
 +       */
 +      case CASE(TINT32, TFLOAT32):
 +      case CASE(TINT32, TFLOAT64):
 +      case CASE(TINT64, TFLOAT32):
 +      case CASE(TINT64, TFLOAT64):
 +      case CASE(TINT16, TFLOAT32):
 +      case CASE(TINT16, TFLOAT64):
 +      case CASE(TINT8, TFLOAT32):
 +      case CASE(TINT8, TFLOAT64):
 +      case CASE(TUINT16, TFLOAT32):
 +      case CASE(TUINT16, TFLOAT64):
 +      case CASE(TUINT8, TFLOAT32):
 +      case CASE(TUINT8, TFLOAT64):
 +      case CASE(TUINT32, TFLOAT32):
 +      case CASE(TUINT32, TFLOAT64):
 +      case CASE(TUINT64, TFLOAT32):
 +      case CASE(TUINT64, TFLOAT64):
 +              //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
 +              //return;
 +              // algorithm is:
 +              //      if small enough, use native int64 -> uint64 conversion.
 +              //      otherwise, halve (rounding to odd?), convert, and double.
 +              bignodes();
 +              regalloc(&r1, types[TINT64], N);
 +              gmove(f, &r1);
 +              if(ft == TUINT64) {
 +                      nodreg(&r2, types[TUINT64], D_R0+REGTMP);
 +                      gmove(&bigi, &r2);
 +                      gins(ACMPU, &r1, &r2);
 +                      p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
 +                      p2 = gins(ASRD, N, &r1);
 +                      p2->from.type = D_CONST;
 +                      p2->from.offset = 1;
 +                      patch(p1, pc);
 +              }
 +              regalloc(&r2, types[TFLOAT64], t);
 +              p1 = gins(AMOVD, &r1, N);
 +              p1->to.type = D_OREG;
 +              p1->to.reg = REGSP;
 +              p1->to.offset = -8;
 +              p1 = gins(AFMOVD, N, &r2);
 +              p1->from.type = D_OREG;
 +              p1->from.reg = REGSP;
 +              p1->from.offset = -8;
 +              gins(AFCFID, &r2, &r2);
 +              regfree(&r1);
 +              if(ft == TUINT64) {
 +                      p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); // use CR0 here again
 +                      nodreg(&r1, types[TFLOAT64], D_F0+FREGTWO);
 +                      gins(AFMUL, &r1, &r2);
 +                      patch(p1, pc);
 +              }
 +              gmove(&r2, t);
 +              regfree(&r2);
 +              return;
 +
 +      /*
 +       * float to float
 +       */
 +      case CASE(TFLOAT32, TFLOAT32):
 +              a = AFMOVS;
 +              break;
 +
 +      case CASE(TFLOAT64, TFLOAT64):
 +              a = AFMOVD;
 +              break;
 +
 +      case CASE(TFLOAT32, TFLOAT64):
 +              a = AFMOVS;
 +              goto rdst;
 +
 +      case CASE(TFLOAT64, TFLOAT32):
 +              a = AFRSP;
 +              goto rdst;
 +      }
 +
 +      gins(a, f, t);
 +      return;
 +
 +rdst:
 +      // requires register destination
 +      regalloc(&r1, t->type, t);
 +      gins(a, f, &r1);
 +      gmove(&r1, t);
 +      regfree(&r1);
 +      return;
 +
 +hard:
 +      // requires register intermediate
 +      regalloc(&r1, cvt, t);
 +      gmove(f, &r1);
 +      gmove(&r1, t);
 +      regfree(&r1);
 +      return;
 +}
 +
 +/*
 + * generate one instruction:
 + *    as f, t
 + */
 +Prog*
 +gins(int as, Node *f, Node *t)
 +{
 +      //int32 w;
 +      Prog *p;
 +      Addr af, at;
 +
 +      memset(&af, 0, sizeof af);
 +      memset(&at, 0, sizeof at);
 +      if(f != N)
 +              naddr(f, &af, 1);
 +      if(t != N)
 +              naddr(t, &at, 1);
 +      p = prog(as);
 +      if(f != N)
 +              p->from = af;
 +      if(t != N)
 +              p->to = at;
 +      if(as == ATEXT)
 +              p->reg = 0;
 +      if(debug['g'])
 +              print("%P\n", p);
 +
 +      // TODO(minux): enable these.
 +      // right now it fails on MOVD $type."".TypeAssertionError(SB) [width=1], R7 [width=8]
 +      /*
 +      w = 0;
 +      switch(as) {
 +      case AMOVB:
 +      case AMOVBU:
 +      case AMOVBZ:
 +      case AMOVBZU:
 +              w = 1;
 +              break;
 +      case AMOVH:
 +      case AMOVHU:
 +      case AMOVHZ:
 +      case AMOVHZU:
 +              w = 2;
 +              break;
 +      case AMOVW:
 +      case AMOVWU:
 +      case AMOVWZ:
 +      case AMOVWZU:
 +              w = 4;
 +              break;
 +      case AMOVD:
 +      case AMOVDU:
 +              w = 8;
 +              break;
 +      }
 +      if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
 +              dump("f", f);
 +              dump("t", t);
 +              fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
 +      }
 +      */
 +
 +      return p;
 +}
 +
 +void
 +fixlargeoffset(Node *n)
 +{
 +      Node a;
 +
 +      if(n == N)
 +              return;
 +      if(n->op != OINDREG)
 +              return;
 +      if(n->val.u.reg == D_R0+REGSP) // stack offset cannot be large
 +              return;
 +      if(n->xoffset != (int32)n->xoffset) {
 +              // TODO(minux): offset too large, move into R31 and add to R31 instead.
 +              // this is used only in test/fixedbugs/issue6036.go.
 +              print("offset too large: %N\n", n);
 +              noimpl;
 +              a = *n;
 +              a.op = OREGISTER;
 +              a.type = types[tptr];
 +              a.xoffset = 0;
 +              cgen_checknil(&a);
 +              ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
 +              n->xoffset = 0;
 +      }
 +}
 +
 +/*
 + * generate code to compute n;
 + * make a refer to result.
 + */
 +void
 +naddr(Node *n, Addr *a, int canemitcode)
 +{
 +      Sym *s;
 +
 +      a->type = D_NONE;
 +      a->name = D_NONE;
 +      a->reg = NREG;
 +      a->gotype = nil;
 +      a->node = N;
 +      a->etype = 0;
 +      a->width = 0;
 +      if(n == N)
 +              return;
 +
 +      if(n->type != T && n->type->etype != TIDEAL) {
 +              dowidth(n->type);
 +              a->width = n->type->width;
 +      }
 +
 +      switch(n->op) {
 +      default:
 +              fatal("naddr: bad %O %D", n->op, a);
 +              break;
 +
 +      case ONAME:
 +              a->etype = 0;
 +              a->width = 0;
 +              a->reg = NREG;
 +              if(n->type != T) {
 +                      a->etype = simtype[n->type->etype];
 +                      a->width = n->type->width;
 +              }
 +              a->offset = n->xoffset;
 +              s = n->sym;
 +              a->node = n->orig;
 +              //if(a->node >= (Node*)&n)
 +              //      fatal("stack node");
 +              if(s == S)
 +                      s = lookup(".noname");
 +              if(n->method) {
 +                      if(n->type != T)
 +                      if(n->type->sym != S)
 +                      if(n->type->sym->pkg != nil)
 +                              s = pkglookup(s->name, n->type->sym->pkg);
 +              }
 +
 +              a->type = D_OREG;
 +              switch(n->class) {
 +              default:
 +                      fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
 +              case PEXTERN:
 +                      a->name = D_EXTERN;
 +                      break;
 +              case PAUTO:
 +                      a->name = D_AUTO;
 +                      break;
 +              case PPARAM:
 +              case PPARAMOUT:
 +                      a->name = D_PARAM;
 +                      break;
 +              case PFUNC:
 +                      a->name = D_EXTERN;
 +                      a->type = D_CONST;
 +                      a->width = widthptr;
 +                      s = funcsym(s);
 +                      break;
 +              }
 +              a->sym = linksym(s);
 +              break;
 +
 +      case OLITERAL:
 +              switch(n->val.ctype) {
 +              default:
 +                      fatal("naddr: const %lT", n->type);
 +                      break;
 +              case CTFLT:
 +                      a->type = D_FCONST;
 +                      a->u.dval = mpgetflt(n->val.u.fval);
 +                      break;
 +              case CTINT:
 +              case CTRUNE:
 +                      a->sym = nil;
 +                      a->type = D_CONST;
 +                      a->offset = mpgetfix(n->val.u.xval);
 +                      break;
 +              case CTSTR:
 +                      datagostring(n->val.u.sval, a);
 +                      break;
 +              case CTBOOL:
 +                      a->sym = nil;
 +                      a->type = D_CONST;
 +                      a->offset = n->val.u.bval;
 +                      break;
 +              case CTNIL:
 +                      a->sym = nil;
 +                      a->type = D_CONST;
 +                      a->offset = 0;
 +                      break;
 +              }
 +              break;
 +
 +      case OREGISTER:
 +              if(n->val.u.reg < D_F0) {
 +                      a->type = D_REG;
 +                      a->reg = n->val.u.reg;
 +              } else {
 +                      a->type = D_FREG;
 +                      a->reg = n->val.u.reg - D_F0;
 +              }
 +              a->sym = nil;
 +              break;
 +
 +      case OINDREG:
 +              a->type = D_OREG;
 +              a->reg = n->val.u.reg;
 +              a->sym = linksym(n->sym);
 +              a->offset = n->xoffset;
 +              if(a->offset != (int32)a->offset)
 +                      yyerror("offset %lld too large for OINDREG", a->offset);
 +              break;
 +
 +      case OPARAM:
 +              // n->left is PHEAP ONAME for stack parameter.
 +              // compute address of actual parameter on stack.
 +              a->etype = simtype[n->left->type->etype];
 +              a->width = n->left->type->width;
 +              a->offset = n->xoffset;
 +              a->sym = linksym(n->left->sym);
 +              a->type = D_OREG;
 +              a->name = D_PARAM;
 +              a->node = n->left->orig;
 +              break;
 +
 +      case OCLOSUREVAR:
 +              if(!curfn->needctxt)
 +                      fatal("closurevar without needctxt");
 +              a->type = D_OREG;
 +              a->reg = REGENV;
 +              a->offset = n->xoffset;
 +              a->sym = nil;
 +              break;
 +
 +      case OCFUNC:
 +              naddr(n->left, a, canemitcode);
 +              a->sym = linksym(n->left->sym);
 +              break;
 +
 +      case OITAB:
 +              // itable of interface value
 +              naddr(n->left, a, canemitcode);
 +              a->etype = simtype[tptr];
 +              if(a->type == D_CONST && a->offset == 0)
 +                      break;  // len(nil)
 +              break;
 +
 +      case OSPTR:
 +              // pointer in a string or slice
 +              naddr(n->left, a, canemitcode);
 +              if(a->type == D_CONST && a->offset == 0)
 +                      break;  // ptr(nil)
 +              a->etype = simtype[tptr];
 +              a->offset += Array_array;
 +              a->width = widthptr;
 +              break;
 +
 +      case OLEN:
 +              // len of string or slice
 +              naddr(n->left, a, canemitcode);
 +              a->etype = simtype[TINT];
 +              if(a->type == D_CONST && a->offset == 0)
 +                      break;  // len(nil)
 +              a->offset += Array_nel;
 +              break;
 +
 +      case OCAP:
 +              // cap of string or slice
 +              naddr(n->left, a, canemitcode);
 +              a->etype = simtype[TINT];
 +              if(a->type == D_CONST && a->offset == 0)
 +                      break;  // cap(nil)
 +              a->offset += Array_cap;
 +              break;
 +
 +      case OADDR:
 +              naddr(n->left, a, canemitcode);
 +              a->etype = tptr;
 +              switch(a->type) {
 +              case D_OREG:
 +                      a->type = D_CONST;
 +                      break;
 +
 +              case D_REG:
 +              case D_CONST:
 +                      break;
 +
 +              default:
 +                      fatal("naddr: OADDR %d\n", a->type);
 +              }
 +      }
 +}
 +
 +/*
 + * return Axxx for Oxxx on type t.
 + */
 +int
 +optoas(int op, Type *t)
 +{
 +      int a;
 +
 +      if(t == T)
 +              fatal("optoas: t is nil");
 +
 +      a = AGOK;
 +      switch(CASE(op, simtype[t->etype])) {
 +      default:
 +              fatal("optoas: no entry for op=%O type=%T", op, t);
 +              break;
 +
 +      case CASE(OEQ, TBOOL):
 +      case CASE(OEQ, TINT8):
 +      case CASE(OEQ, TUINT8):
 +      case CASE(OEQ, TINT16):
 +      case CASE(OEQ, TUINT16):
 +      case CASE(OEQ, TINT32):
 +      case CASE(OEQ, TUINT32):
 +      case CASE(OEQ, TINT64):
 +      case CASE(OEQ, TUINT64):
 +      case CASE(OEQ, TPTR32):
 +      case CASE(OEQ, TPTR64):
 +      case CASE(OEQ, TFLOAT32):
 +      case CASE(OEQ, TFLOAT64):
 +              a = ABEQ;
 +              break;
 +
 +      case CASE(ONE, TBOOL):
 +      case CASE(ONE, TINT8):
 +      case CASE(ONE, TUINT8):
 +      case CASE(ONE, TINT16):
 +      case CASE(ONE, TUINT16):
 +      case CASE(ONE, TINT32):
 +      case CASE(ONE, TUINT32):
 +      case CASE(ONE, TINT64):
 +      case CASE(ONE, TUINT64):
 +      case CASE(ONE, TPTR32):
 +      case CASE(ONE, TPTR64):
 +      case CASE(ONE, TFLOAT32):
 +      case CASE(ONE, TFLOAT64):
 +              a = ABNE;
 +              break;
 +
 +      case CASE(OLT, TINT8):  // ACMP
 +      case CASE(OLT, TINT16):
 +      case CASE(OLT, TINT32):
 +      case CASE(OLT, TINT64):
 +      case CASE(OLT, TUINT8): // ACMPU
 +      case CASE(OLT, TUINT16):
 +      case CASE(OLT, TUINT32):
 +      case CASE(OLT, TUINT64):
 +      case CASE(OLT, TFLOAT32): // AFCMPU
 +      case CASE(OLT, TFLOAT64):
 +              a = ABLT;
 +              break;
 +
 +      case CASE(OLE, TINT8):  // ACMP
 +      case CASE(OLE, TINT16):
 +      case CASE(OLE, TINT32):
 +      case CASE(OLE, TINT64):
 +      case CASE(OLE, TUINT8): // ACMPU
 +      case CASE(OLE, TUINT16):
 +      case CASE(OLE, TUINT32):
 +      case CASE(OLE, TUINT64):
 +      case CASE(OLE, TFLOAT32): // AFCMPU
 +      case CASE(OLE, TFLOAT64):
 +              a = ABLE;
 +              break;
 +
 +      case CASE(OGT, TINT8):
 +      case CASE(OGT, TINT16):
 +      case CASE(OGT, TINT32):
 +      case CASE(OGT, TINT64):
 +      case CASE(OGT, TUINT8):
 +      case CASE(OGT, TUINT16):
 +      case CASE(OGT, TUINT32):
 +      case CASE(OGT, TUINT64):
 +      case CASE(OGT, TFLOAT32):
 +      case CASE(OGT, TFLOAT64):
 +              a = ABGT;
 +              break;
 +
 +      case CASE(OGE, TINT8):
 +      case CASE(OGE, TINT16):
 +      case CASE(OGE, TINT32):
 +      case CASE(OGE, TINT64):
 +      case CASE(OGE, TUINT8):
 +      case CASE(OGE, TUINT16):
 +      case CASE(OGE, TUINT32):
 +      case CASE(OGE, TUINT64):
 +      case CASE(OGE, TFLOAT32):
 +      case CASE(OGE, TFLOAT64):
 +              a = ABGE;
 +              break;
 +
 +      case CASE(OCMP, TBOOL):
 +      case CASE(OCMP, TINT8):
 +      case CASE(OCMP, TINT16):
 +      case CASE(OCMP, TINT32):
 +      case CASE(OCMP, TPTR32):
 +      case CASE(OCMP, TINT64):
 +              a = ACMP;
 +              break;
 +
 +      case CASE(OCMP, TUINT8):
 +      case CASE(OCMP, TUINT16):
 +      case CASE(OCMP, TUINT32):
 +      case CASE(OCMP, TUINT64):
 +      case CASE(OCMP, TPTR64):
 +              a = ACMPU;
 +              break;
 +
 +      case CASE(OCMP, TFLOAT32):
 +      case CASE(OCMP, TFLOAT64):
 +              a = AFCMPU;
 +              break;
 +
 +      case CASE(OAS, TBOOL):
 +      case CASE(OAS, TINT8):
 +              a = AMOVB;
 +              break;
 +
 +      case CASE(OAS, TUINT8):
 +              a = AMOVBZ;
 +              break;
 +
 +      case CASE(OAS, TINT16):
 +              a = AMOVH;
 +              break;
 +
 +      case CASE(OAS, TUINT16):
 +              a = AMOVHZ;
 +              break;
 +
 +      case CASE(OAS, TINT32):
 +              a = AMOVW;
 +              break;
 +
 +      case CASE(OAS, TUINT32):
 +      case CASE(OAS, TPTR32):
 +              a = AMOVWZ;
 +              break;
 +
 +      case CASE(OAS, TINT64):
 +      case CASE(OAS, TUINT64):
 +      case CASE(OAS, TPTR64):
 +              a = AMOVD;
 +              break;
 +
 +      case CASE(OAS, TFLOAT32):
 +              a = AFMOVS;
 +              break;
 +
 +      case CASE(OAS, TFLOAT64):
 +              a = AFMOVD;
 +              break;
 +
 +      case CASE(OADD, TINT8):
 +      case CASE(OADD, TUINT8):
 +      case CASE(OADD, TINT16):
 +      case CASE(OADD, TUINT16):
 +      case CASE(OADD, TINT32):
 +      case CASE(OADD, TUINT32):
 +      case CASE(OADD, TPTR32):
-       case CASE(OADDPTR, TPTR64):
 +      case CASE(OADD, TINT64):
 +      case CASE(OADD, TUINT64):
 +      case CASE(OADD, TPTR64):
 +              a = AADD;
 +              break;
 +
 +      case CASE(OADD, TFLOAT32):
 +              a = AFADDS;
 +              break;
 +
 +      case CASE(OADD, TFLOAT64):
 +              a = AFADD;
 +              break;
 +
 +      case CASE(OSUB, TINT8):
 +      case CASE(OSUB, TUINT8):
 +      case CASE(OSUB, TINT16):
 +      case CASE(OSUB, TUINT16):
 +      case CASE(OSUB, TINT32):
 +      case CASE(OSUB, TUINT32):
 +      case CASE(OSUB, TPTR32):
 +      case CASE(OSUB, TINT64):
 +      case CASE(OSUB, TUINT64):
 +      case CASE(OSUB, TPTR64):
 +              a = ASUB;
 +              break;
 +
 +      case CASE(OSUB, TFLOAT32):
 +              a = AFSUBS;
 +              break;
 +
 +      case CASE(OSUB, TFLOAT64):
 +              a = AFSUB;
 +              break;
 +
 +      case CASE(OMINUS, TINT8):
 +      case CASE(OMINUS, TUINT8):
 +      case CASE(OMINUS, TINT16):
 +      case CASE(OMINUS, TUINT16):
 +      case CASE(OMINUS, TINT32):
 +      case CASE(OMINUS, TUINT32):
 +      case CASE(OMINUS, TPTR32):
 +      case CASE(OMINUS, TINT64):
 +      case CASE(OMINUS, TUINT64):
 +      case CASE(OMINUS, TPTR64):
 +              a = ANEG;
 +              break;
 +
 +      case CASE(OAND, TINT8):
 +      case CASE(OAND, TUINT8):
 +      case CASE(OAND, TINT16):
 +      case CASE(OAND, TUINT16):
 +      case CASE(OAND, TINT32):
 +      case CASE(OAND, TUINT32):
 +      case CASE(OAND, TPTR32):
 +      case CASE(OAND, TINT64):
 +      case CASE(OAND, TUINT64):
 +      case CASE(OAND, TPTR64):
 +              a = AAND;
 +              break;
 +
 +      case CASE(OOR, TINT8):
 +      case CASE(OOR, TUINT8):
 +      case CASE(OOR, TINT16):
 +      case CASE(OOR, TUINT16):
 +      case CASE(OOR, TINT32):
 +      case CASE(OOR, TUINT32):
 +      case CASE(OOR, TPTR32):
 +      case CASE(OOR, TINT64):
 +      case CASE(OOR, TUINT64):
 +      case CASE(OOR, TPTR64):
 +              a = AOR;
 +              break;
 +
 +      case CASE(OXOR, TINT8):
 +      case CASE(OXOR, TUINT8):
 +      case CASE(OXOR, TINT16):
 +      case CASE(OXOR, TUINT16):
 +      case CASE(OXOR, TINT32):
 +      case CASE(OXOR, TUINT32):
 +      case CASE(OXOR, TPTR32):
 +      case CASE(OXOR, TINT64):
 +      case CASE(OXOR, TUINT64):
 +      case CASE(OXOR, TPTR64):
 +              a = AXOR;
 +              break;
 +
 +      // TODO(minux): handle rotates
 +      //case CASE(OLROT, TINT8):
 +      //case CASE(OLROT, TUINT8):
 +      //case CASE(OLROT, TINT16):
 +      //case CASE(OLROT, TUINT16):
 +      //case CASE(OLROT, TINT32):
 +      //case CASE(OLROT, TUINT32):
 +      //case CASE(OLROT, TPTR32):
 +      //case CASE(OLROT, TINT64):
 +      //case CASE(OLROT, TUINT64):
 +      //case CASE(OLROT, TPTR64):
 +      //      a = 0//???; RLDC?
 +      //      break;
 +
 +      case CASE(OLSH, TINT8):
 +      case CASE(OLSH, TUINT8):
 +      case CASE(OLSH, TINT16):
 +      case CASE(OLSH, TUINT16):
 +      case CASE(OLSH, TINT32):
 +      case CASE(OLSH, TUINT32):
 +      case CASE(OLSH, TPTR32):
 +      case CASE(OLSH, TINT64):
 +      case CASE(OLSH, TUINT64):
 +      case CASE(OLSH, TPTR64):
 +              a = ASLD;
 +              break;
 +
 +      case CASE(ORSH, TUINT8):
 +      case CASE(ORSH, TUINT16):
 +      case CASE(ORSH, TUINT32):
 +      case CASE(ORSH, TPTR32):
 +      case CASE(ORSH, TUINT64):
 +      case CASE(ORSH, TPTR64):
 +              a = ASRD;
 +              break;
 +
 +      case CASE(ORSH, TINT8):
 +      case CASE(ORSH, TINT16):
 +      case CASE(ORSH, TINT32):
 +      case CASE(ORSH, TINT64):
 +              a = ASRAD;
 +              break;
 +
 +      // TODO(minux): handle rotates
 +      //case CASE(ORROTC, TINT8):
 +      //case CASE(ORROTC, TUINT8):
 +      //case CASE(ORROTC, TINT16):
 +      //case CASE(ORROTC, TUINT16):
 +      //case CASE(ORROTC, TINT32):
 +      //case CASE(ORROTC, TUINT32):
 +      //case CASE(ORROTC, TINT64):
 +      //case CASE(ORROTC, TUINT64):
 +      //      a = 0//??? RLDC??
 +      //      break;
 +
 +      case CASE(OHMUL, TINT64):
 +              a = AMULHD;
 +              break;
 +      case CASE(OHMUL, TUINT64):
 +      case CASE(OHMUL, TPTR64):
 +              a = AMULHDU;
 +              break;
 +
 +      case CASE(OMUL, TINT8):
 +      case CASE(OMUL, TINT16):
 +      case CASE(OMUL, TINT32):
 +      case CASE(OMUL, TINT64):
 +              a = AMULLD;
 +              break;
 +
 +      case CASE(OMUL, TUINT8):
 +      case CASE(OMUL, TUINT16):
 +      case CASE(OMUL, TUINT32):
 +      case CASE(OMUL, TPTR32):
 +              // don't use word multiply, the high 32-bit are undefined.
 +              // fallthrough
 +      case CASE(OMUL, TUINT64):
 +      case CASE(OMUL, TPTR64):
 +              a = AMULLD; // for 64-bit multiplies, signedness doesn't matter.
 +              break;
 +
 +      case CASE(OMUL, TFLOAT32):
 +              a = AFMULS;
 +              break;
 +
 +      case CASE(OMUL, TFLOAT64):
 +              a = AFMUL;
 +              break;
 +
 +      case CASE(ODIV, TINT8):
 +      case CASE(ODIV, TINT16):
 +      case CASE(ODIV, TINT32):
 +      case CASE(ODIV, TINT64):
 +              a = ADIVD;
 +              break;
 +
 +      case CASE(ODIV, TUINT8):
 +      case CASE(ODIV, TUINT16):
 +      case CASE(ODIV, TUINT32):
 +      case CASE(ODIV, TPTR32):
 +      case CASE(ODIV, TUINT64):
 +      case CASE(ODIV, TPTR64):
 +              a = ADIVDU;
 +              break;
 +
 +      case CASE(ODIV, TFLOAT32):
 +              a = AFDIVS;
 +              break;
 +
 +      case CASE(ODIV, TFLOAT64):
 +              a = AFDIV;
 +              break;
 +
 +      }
 +      return a;
 +}
 +
 +enum
 +{
 +      ODynam          = 1<<0,
 +      OAddable        = 1<<1,
 +};
 +
 +int
 +xgen(Node *n, Node *a, int o)
 +{
 +      // TODO(minux)
 +      USED(n); USED(a); USED(o);
 +      return -1;
 +}
 +
 +void
 +sudoclean(void)
 +{
 +      return;
 +}
 +
 +/*
 + * generate code to compute address of n,
 + * a reference to a (perhaps nested) field inside
 + * an array or struct.
 + * return 0 on failure, 1 on success.
 + * on success, leaves usable address in a.
 + *
 + * caller is responsible for calling sudoclean
 + * after successful sudoaddable,
 + * to release the register used for a.
 + */
 +int
 +sudoaddable(int as, Node *n, Addr *a)
 +{
 +      // TODO(minux)
 +      USED(as); USED(n); USED(a);
 +      return 0;
 +}
index 5aeea1b6b06318002c18775761034ac0e159418d,0000000000000000000000000000000000000000..b8ca777c35cadb6a82943193a72fdf446117eadc
mode 100644,000000..100644
--- /dev/null
@@@ -1,338 -1,0 +1,338 @@@
-                       symo = HEADR+segtext.len+segdata.filelen;
 +// Inferno utils/5l/asm.c
 +// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
 +//
 +//    Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 +//    Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 +//    Portions Copyright © 1997-1999 Vita Nuova Limited
 +//    Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
 +//    Portions Copyright © 2004,2006 Bruce Ellis
 +//    Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 +//    Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
 +//    Portions Copyright © 2009 The Go Authors.  All rights reserved.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a copy
 +// of this software and associated documentation files (the "Software"), to deal
 +// in the Software without restriction, including without limitation the rights
 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +// copies of the Software, and to permit persons to whom the Software is
 +// furnished to do so, subject to the following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included in
 +// all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +// THE SOFTWARE.
 +
 +// Writing object files.
 +
 +#include      "l.h"
 +#include      "../ld/lib.h"
 +#include      "../ld/elf.h"
 +#include      "../ld/dwarf.h"
 +
 +
 +char linuxdynld[] = "/lib64/ld64.so.1";
 +char freebsddynld[] = "XXX";
 +char openbsddynld[] = "XXX";
 +char netbsddynld[] = "XXX";
 +char dragonflydynld[] = "XXX";
 +char solarisdynld[] = "XXX";
 +
 +static int
 +needlib(char *name)
 +{
 +      char *p;
 +      LSym *s;
 +
 +      if(*name == '\0')
 +              return 0;
 +
 +      /* reuse hash code in symbol table */
 +      p = smprint(".dynlib.%s", name);
 +      s = linklookup(ctxt, p, 0);
 +      free(p);
 +      if(s->type == 0) {
 +              s->type = 100;  // avoid SDATA, etc.
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +int   nelfsym = 1;
 +
 +// b is the addresses, a is the I-form branch instruction template, peform
 +// addition so that the instruction jumps to address (offset) b.
 +static int32
 +braddoff(int32 a, int32 b)
 +{
 +      return (((uint32)a) & 0xfc000003U) | (0x03fffffcU & (uint32)((a & 0x3fffffcU) + b));
 +}
 +
 +void
 +adddynrela(LSym *rel, LSym *s, Reloc *r)
 +{
 +      // TODO(minux)
 +      USED(rel); USED(s); USED(r);
 +}
 +
 +void
 +adddynrel(LSym *s, Reloc *r)
 +{
 +      LSym *targ;
 +
 +      // TODO(minux)
 +
 +      targ = r->sym;
 +      ctxt->cursym = s;
 +      diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
 +}
 +
 +int
 +elfreloc1(Reloc *r, vlong sectoff)
 +{
 +      USED(r); USED(sectoff);
 +      // TODO(minux)
 +      return -1;
 +}
 +
 +void
 +elfsetupplt(void)
 +{
 +      // TODO(minux)
 +      return;
 +}
 +
 +int
 +machoreloc1(Reloc *r, vlong sectoff)
 +{
 +      USED(r);
 +      USED(sectoff);
 +
 +      return -1;
 +}
 +
 +
 +int
 +archreloc(Reloc *r, LSym *s, vlong *val)
 +{
 +      uint32 o1, o2;
 +      int32 t;
 +
 +      if(linkmode == LinkExternal) {
 +              // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
 +              // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
 +              // R_CALLPOWER corresponds to R_PPC_REL24.
 +              return -1;
 +      }
 +      switch(r->type) {
 +      case R_CONST:
 +              *val = r->add;
 +              return 0;
 +      case R_GOTOFF:
 +              *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
 +              return 0;
 +      case R_ADDRPOWER:
 +              // r->add is two power64 instructions holding an immediate 32-bit constant.
 +              // We want to add r->sym's address to that constant.
 +              // The encoding of the immediate x<<16 + y,
 +              // where x is the low 16 bits of the first instruction and y is the low 16
 +              // bits of the second. Both x and y are signed (int16, not uint16).
 +              o1 = r->add >> 32;
 +              o2 = r->add;
 +              t = symaddr(r->sym);
 +              if(t < 0) {
 +                      ctxt->diag("relocation for %s is too big (>=2G): %lld", s->name, symaddr(r->sym));
 +              }
 +              t += ((o1 & 0xffff) << 16) + ((int32)o2 << 16 >> 16);
 +              if(t & 0x8000)
 +                      t += 0x10000;
 +              o1 = (o1 & 0xffff0000) | ((t >> 16) & 0xffff);
 +              o2 = (o2 & 0xffff0000) | (t & 0xffff);
 +              // when laid out, the instruction order must always be o1, o2.
 +              if(ctxt->arch->endian == BigEndian)
 +                      *val = ((vlong)o1 << 32) | o2;
 +              else
 +                      *val = ((vlong)o2 << 32) | o1;
 +              return 0;
 +      case R_CALLPOWER:
 +              *val = braddoff((uint32)r->add, (int32)(symaddr(r->sym) - (s->value + r->off)));
 +              return 0;
 +      }
 +      return -1;
 +}
 +
 +void
 +adddynsym(Link *ctxt, LSym *s)
 +{
 +      USED(ctxt); USED(s);
 +      // TODO(minux)
 +      return;
 +}
 +
 +void
 +adddynlib(char *lib)
 +{
 +      LSym *s;
 +      
 +      if(!needlib(lib))
 +              return;
 +      
 +      if(iself) {
 +              s = linklookup(ctxt, ".dynstr", 0);
 +              if(s->size == 0)
 +                      addstring(s, "");
 +              elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
 +      } else {
 +              diag("adddynlib: unsupported binary format");
 +      }
 +}
 +
 +void
 +asmb(void)
 +{
 +      uint32 symo;
 +      Section *sect;
 +      LSym *sym;
 +      int i;
 +
 +      if(debug['v'])
 +              Bprint(&bso, "%5.2f asmb\n", cputime());
 +      Bflush(&bso);
 +
 +      if(iself)
 +              asmbelfsetup();
 +
 +      sect = segtext.sect;
 +      cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 +      codeblk(sect->vaddr, sect->len);
 +      for(sect = sect->next; sect != nil; sect = sect->next) {
 +              cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 +              datblk(sect->vaddr, sect->len);
 +      }
 +
 +      if(segrodata.filelen > 0) {
 +              if(debug['v'])
 +                      Bprint(&bso, "%5.2f rodatblk\n", cputime());
 +              Bflush(&bso);
 +
 +              cseek(segrodata.fileoff);
 +              datblk(segrodata.vaddr, segrodata.filelen);
 +      }
 +
 +      if(debug['v'])
 +              Bprint(&bso, "%5.2f datblk\n", cputime());
 +      Bflush(&bso);
 +
 +      cseek(segdata.fileoff);
 +      datblk(segdata.vaddr, segdata.filelen);
 +
 +      /* output symbol table */
 +      symsize = 0;
 +      lcsize = 0;
 +      symo = 0;
 +      if(!debug['s']) {
 +              // TODO: rationalize
 +              if(debug['v'])
 +                      Bprint(&bso, "%5.2f sym\n", cputime());
 +              Bflush(&bso);
 +              switch(HEADTYPE) {
 +              default:
 +                      if(iself)
 +                              goto ElfSym;
 +              case Hplan9:
-                       symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
++                      symo = segdata.fileoff+segdata.filelen;
 +                      break;
 +              ElfSym:
++                      symo = segdata.fileoff+segdata.filelen;
 +                      symo = rnd(symo, INITRND);
 +                      break;
 +              }
 +              cseek(symo);
 +              switch(HEADTYPE) {
 +              default:
 +                      if(iself) {
 +                              if(debug['v'])
 +                                      Bprint(&bso, "%5.2f elfsym\n", cputime());
 +                              asmelfsym();
 +                              cflush();
 +                              cwrite(elfstrdat, elfstrsize);
 +      
 +                              if(debug['v'])
 +                                      Bprint(&bso, "%5.2f dwarf\n", cputime());
 +                              dwarfemitdebugsections();
 +                              
 +                              if(linkmode == LinkExternal)
 +                                      elfemitreloc();
 +                      }
 +                      break;
 +              case Hplan9:
 +                      asmplan9sym();
 +                      cflush();
 +
 +                      sym = linklookup(ctxt, "pclntab", 0);
 +                      if(sym != nil) {
 +                              lcsize = sym->np;
 +                              for(i=0; i < lcsize; i++)
 +                                      cput(sym->p[i]);
 +
 +                              cflush();
 +                      }
 +                      break;
 +              }
 +      }
 +
 +      ctxt->cursym = nil;
 +      if(debug['v'])
 +              Bprint(&bso, "%5.2f header\n", cputime());
 +      Bflush(&bso);
 +      cseek(0L);
 +      switch(HEADTYPE) {
 +      default:
 +      case Hplan9:    /* plan 9 */
 +              LPUT(0x647);                    /* magic */
 +              LPUT(segtext.filelen);                  /* sizes */
 +              LPUT(segdata.filelen);
 +              LPUT(segdata.len - segdata.filelen);
 +              LPUT(symsize);                  /* nsyms */
 +              LPUT(entryvalue());             /* va of entry */
 +              LPUT(0L);
 +              LPUT(lcsize);
 +              break;
 +      case Hlinux:
 +      case Hfreebsd:
 +      case Hnetbsd:
 +      case Hopenbsd:
 +      case Hnacl:
 +              asmbelf(symo);
 +              break;
 +      }
 +      cflush();
 +      if(debug['c']){
 +              print("textsize=%ulld\n", segtext.filelen);
 +              print("datsize=%ulld\n", segdata.filelen);
 +              print("bsssize=%ulld\n", segdata.len - segdata.filelen);
 +              print("symsize=%d\n", symsize);
 +              print("lcsize=%d\n", lcsize);
 +              print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
 +      }
 +}
 +
 +vlong
 +rnd(vlong v, int32 r)
 +{
 +      vlong c;
 +
 +      if(r <= 0)
 +              return v;
 +      v += r - 1;
 +      c = v % r;
 +      if(c < 0)
 +              c += r;
 +      v -= c;
 +      return v;
 +}
diff --cc src/cmd/cc/cc.y
index 11ee444b7d710e5be14764da583af10e4e04eb3d,11ee444b7d710e5be14764da583af10e4e04eb3d..8d7cb1472ca231fb87b693495e76c25e673e9ff9
@@@ -1043,6 -1043,6 +1043,7 @@@ complex
        }
  |     LSTRUCT sbody
        {
++              diag(Z, "struct must have tag");
                taggen++;
                sprint(symb, "_%d_", taggen);
                $$ = dotag(lookup(), TSTRUCT, autobn);
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 5e1c47a04cb44fee381bd8521471653faacb8f8a,c908e7a8893a658ff6dfacded0c977165fbc0d04..49060b73569bfe45d56be802d6f7b2c2f7a18102
@@@ -529,9 -529,9 +529,12 @@@ func (f *File) applyRelocations(dst []b
        if f.Class == ELFCLASS32 && f.Machine == EM_386 {
                return f.applyRelocations386(dst, rels)
        }
+       if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
+               return f.applyRelocationsARM64(dst, rels)
+       }
 +      if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 {
 +              return f.applyRelocationsPPC64(dst, rels)
 +      }
  
        return errors.New("not implemented")
  }
@@@ -618,51 -618,51 +621,96 @@@ func (f *File) applyRelocations386(dst 
        return nil
  }
  
+ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
+       // 24 is the size of Rela64.
+       if len(rels)%24 != 0 {
+               return errors.New("length of relocation section is not a multiple of 24")
+       }
+       symbols, _, err := f.getSymbols(SHT_SYMTAB)
+       if err != nil {
+               return err
+       }
+       b := bytes.NewReader(rels)
+       var rela Rela64
+       for b.Len() > 0 {
+               binary.Read(b, f.ByteOrder, &rela)
+               symNo := rela.Info >> 32
+               t := R_AARCH64(rela.Info & 0xffff)
+               if symNo == 0 || symNo > uint64(len(symbols)) {
+                       continue
+               }
+               sym := &symbols[symNo-1]
+               if SymType(sym.Info&0xf) != STT_SECTION {
+                       // We don't handle non-section relocations for now.
+                       continue
+               }
+               switch t {
+               case R_AARCH64_ABS64:
+                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+               case R_AARCH64_ABS32:
+                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+               }
+       }
+       return nil
+ }
 +func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
 +      // 24 is the size of Rela64.
 +      if len(rels)%24 != 0 {
 +              return errors.New("length of relocation section is not a multiple of 24")
 +      }
 +
 +      symbols, _, err := f.getSymbols(SHT_SYMTAB)
 +      if err != nil {
 +              return err
 +      }
 +
 +      b := bytes.NewReader(rels)
 +      var rela Rela64
 +
 +      for b.Len() > 0 {
 +              binary.Read(b, f.ByteOrder, &rela)
 +              symNo := rela.Info >> 32
 +              t := R_PPC64(rela.Info & 0xffff)
 +
 +              if symNo == 0 || symNo > uint64(len(symbols)) {
 +                      continue
 +              }
 +              sym := &symbols[symNo-1]
 +              if SymType(sym.Info&0xf) != STT_SECTION {
 +                      // We don't handle non-section relocations for now.
 +                      continue
 +              }
 +
 +              switch t {
 +              case R_PPC64_ADDR64:
 +                      if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
 +                              continue
 +                      }
 +                      f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
 +              case R_PPC64_ADDR32:
 +                      if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
 +                              continue
 +                      }
 +                      f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
 +              }
 +      }
 +
 +      return nil
 +}
 +
  func (f *File) DWARF() (*dwarf.Data, error) {
        // There are many other DWARF sections, but these
        // are the required ones, and the debug/dwarf package
        // If there's a relocation table for .debug_info, we have to process it
        // now otherwise the data in .debug_info is invalid for x86-64 objects.
        rela := f.Section(".rela.debug_info")
-       if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_PPC64) {
 -      if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64) {
++      if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64 || f.Machine == EM_PPC64) {
                data, err := rela.Data()
                if err != nil {
                        return nil, err
index db9a7476c34822d8bab1cf4b3639f438540914f8,5e5ba52f3993a4ee79b84dd5c9e01501c4b8c5d1..d57aaab0ec2630fe7c8420792b2a920bb7e23818
@@@ -260,12 -260,12 +260,18 @@@ var relocationTests = []relocationTest
                        {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
                },
        },
+       {
+               "testdata/go-relocation-test-gcc482-aarch64.obj",
+               []relocationTestEntry{
+                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+               },
+       },
 +      {
 +              "testdata/go-relocation-test-gcc482-ppc64le.obj",
 +              []relocationTestEntry{
 +                      {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
 +              },
 +      },
        {
                "testdata/go-relocation-test-clang-x86.obj",
                []relocationTestEntry{
Simple merge
index 8fd8020f980a8525d24599216c6449ec6ad0fd87,0000000000000000000000000000000000000000..3ba8201b3be048923cdbc53481b40d867fe6ec34
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- #include "../../cmd/ld/textflag.h"
 +// Copyright 2011 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.
 +
 +// +build power64 power64le
 +
++#include "textflag.h"
 +
 +TEXT ·Abs(SB),NOSPLIT,$0-16
 +      MOVD    x+0(FP), R3
 +      MOVD    $((1<<63)-1), R4
 +      AND     R4, R3
 +      MOVD    R3, ret+8(FP)
 +      RETURN
index 502d40cb64c5140330ccab4f0012d20602facedb,0000000000000000000000000000000000000000..c33a9209f1cb9d664ddae00a464b5167f64bbff7
mode 100644,000000..100644
--- /dev/null
@@@ -1,46 -1,0 +1,46 @@@
- #include "../../../cmd/ld/textflag.h"
 +// Copyright 2013 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.
 +
 +// +build power64 power64le
 +
++#include "textflag.h"
 +
 +// This file provides fast assembly versions for the elementary
 +// arithmetic operations on vectors implemented in arith.go.
 +
 +TEXT ·mulWW(SB),NOSPLIT,$0
 +      BR ·mulWW_g(SB)
 +
 +TEXT ·divWW(SB),NOSPLIT,$0
 +      BR ·divWW_g(SB)
 +
 +TEXT ·addVV(SB),NOSPLIT,$0
 +      BR ·addVV_g(SB)
 +
 +TEXT ·subVV(SB),NOSPLIT,$0
 +      BR ·subVV_g(SB)
 +
 +TEXT ·addVW(SB),NOSPLIT,$0
 +      BR ·addVW_g(SB)
 +
 +TEXT ·subVW(SB),NOSPLIT,$0
 +      BR ·subVW_g(SB)
 +
 +TEXT ·shlVU(SB),NOSPLIT,$0
 +      BR ·shlVU_g(SB)
 +
 +TEXT ·shrVU(SB),NOSPLIT,$0
 +      BR ·shrVU_g(SB)
 +
 +TEXT ·mulAddVWW(SB),NOSPLIT,$0
 +      BR ·mulAddVWW_g(SB)
 +
 +TEXT ·addMulVVW(SB),NOSPLIT,$0
 +      BR ·addMulVVW_g(SB)
 +
 +TEXT ·divWVW(SB),NOSPLIT,$0
 +      BR ·divWVW_g(SB)
 +
 +TEXT ·bitLen(SB),NOSPLIT,$0
 +      BR ·bitLen_g(SB)
index c324fcda4e5805095ae5c8aef29de74e753bd9e2,d54c284b5e9d90be76d6cb37e4aa79b74204d49b..1826c37fbd19585952aabe222ac95a6af307253b
@@@ -4,9 -4,9 +4,9 @@@
  
  // Assembly to get into package runtime without using exported symbols.
  
 -// +build amd64 amd64p32 arm 386
 +// +build amd64 amd64p32 arm 386 power64 power64le
  
- #include "../../../cmd/ld/textflag.h"
+ #include "textflag.h"
  
  #ifdef GOARCH_arm
  #define JMP B
Simple merge
index 78839075c428b31dce41b30041e481dfb9929351,0000000000000000000000000000000000000000..e430cdf04c98374e29bed0ffdc3c7e3072bb12e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,29 @@@
- #include "../../cmd/ld/textflag.h"
 +// Copyright 2012 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.
 +
 +// +build power64 power64le
 +
- // Stubs to give reflect package access to runtime services
- // TODO: should probably be done another way.
- TEXT ·makemap(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_makemap(SB)
- TEXT ·mapaccess(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapaccess(SB)
- TEXT ·mapassign(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapassign(SB)
- TEXT ·mapdelete(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapdelete(SB)
- TEXT ·mapiterinit(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapiterinit(SB)
- TEXT ·mapiterkey(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapiterkey(SB)
- TEXT ·mapiternext(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_mapiternext(SB)
- TEXT ·maplen(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_maplen(SB)
- TEXT ·ismapkey(SB),NOSPLIT,$0-0
-       BR      runtime·reflect_ismapkey(SB)
++#include "textflag.h"
 +
 +// makeFuncStub is the code half of the function returned by MakeFunc.
 +// See the comment on the declaration of makeFuncStub in makefunc.go
 +// for more details.
 +// No argsize here, gc generates argsize info at call site.
 +TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
 +      MOVD    R11, 8(R1)
 +      MOVD    $argframe+0(FP), R3
 +      MOVD    R3, 16(R1)
 +      BL      ·callReflect(SB)
 +      RETURN
 +
 +// methodValueCall is the code half of the function returned by makeMethodValue.
 +// See the comment on the declaration of methodValueCall in makefunc.go
 +// for more details.
 +// No argsize here, gc generates argsize info at call site.
 +TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
 +      MOVD    R11, 8(R1)
 +      MOVD    $argframe+0(FP), R3
 +      MOVD    R3, 16(R1)
 +      BL      ·callMethod(SB)
 +      RETURN
Simple merge
Simple merge
index 41db45ca14164493008f29da7dbcb51d3073b13b,0000000000000000000000000000000000000000..64f145672c54d80d834a2d82400edb7f78258905
mode 100644,000000..100644
--- /dev/null
@@@ -1,211 -1,0 +1,211 @@@
- typedef struct Sigaltstack Sigaltstack;
 +// Created by cgo -cdefs - DO NOT EDIT
 +// cgo -cdefs defs_linux.go defs3_linux.go
 +
 +
 +enum {
 +      EINTR   = 0x4,
 +      EAGAIN  = 0xb,
 +      ENOMEM  = 0xc,
 +
 +      PROT_NONE       = 0x0,
 +      PROT_READ       = 0x1,
 +      PROT_WRITE      = 0x2,
 +      PROT_EXEC       = 0x4,
 +
 +      MAP_ANON        = 0x20,
 +      MAP_PRIVATE     = 0x2,
 +      MAP_FIXED       = 0x10,
 +
 +      MADV_DONTNEED   = 0x4,
 +
 +      SA_RESTART      = 0x10000000,
 +      SA_ONSTACK      = 0x8000000,
 +      SA_SIGINFO      = 0x4,
 +
 +      SIGHUP          = 0x1,
 +      SIGINT          = 0x2,
 +      SIGQUIT         = 0x3,
 +      SIGILL          = 0x4,
 +      SIGTRAP         = 0x5,
 +      SIGABRT         = 0x6,
 +      SIGBUS          = 0x7,
 +      SIGFPE          = 0x8,
 +      SIGKILL         = 0x9,
 +      SIGUSR1         = 0xa,
 +      SIGSEGV         = 0xb,
 +      SIGUSR2         = 0xc,
 +      SIGPIPE         = 0xd,
 +      SIGALRM         = 0xe,
 +      SIGSTKFLT       = 0x10,
 +      SIGCHLD         = 0x11,
 +      SIGCONT         = 0x12,
 +      SIGSTOP         = 0x13,
 +      SIGTSTP         = 0x14,
 +      SIGTTIN         = 0x15,
 +      SIGTTOU         = 0x16,
 +      SIGURG          = 0x17,
 +      SIGXCPU         = 0x18,
 +      SIGXFSZ         = 0x19,
 +      SIGVTALRM       = 0x1a,
 +      SIGPROF         = 0x1b,
 +      SIGWINCH        = 0x1c,
 +      SIGIO           = 0x1d,
 +      SIGPWR          = 0x1e,
 +      SIGSYS          = 0x1f,
 +
 +      FPE_INTDIV      = 0x1,
 +      FPE_INTOVF      = 0x2,
 +      FPE_FLTDIV      = 0x3,
 +      FPE_FLTOVF      = 0x4,
 +      FPE_FLTUND      = 0x5,
 +      FPE_FLTRES      = 0x6,
 +      FPE_FLTINV      = 0x7,
 +      FPE_FLTSUB      = 0x8,
 +
 +      BUS_ADRALN      = 0x1,
 +      BUS_ADRERR      = 0x2,
 +      BUS_OBJERR      = 0x3,
 +
 +      SEGV_MAPERR     = 0x1,
 +      SEGV_ACCERR     = 0x2,
 +
 +      ITIMER_REAL     = 0x0,
 +      ITIMER_VIRTUAL  = 0x1,
 +      ITIMER_PROF     = 0x2,
 +
 +      EPOLLIN         = 0x1,
 +      EPOLLOUT        = 0x4,
 +      EPOLLERR        = 0x8,
 +      EPOLLHUP        = 0x10,
 +      EPOLLRDHUP      = 0x2000,
 +      EPOLLET         = -0x80000000,
 +      EPOLL_CLOEXEC   = 0x80000,
 +      EPOLL_CTL_ADD   = 0x1,
 +      EPOLL_CTL_DEL   = 0x2,
 +      EPOLL_CTL_MOD   = 0x3,
 +};
 +
 +typedef struct Sigset Sigset;
 +typedef struct Timespec Timespec;
 +typedef struct Timeval Timeval;
 +typedef struct Sigaction Sigaction;
 +typedef struct Siginfo Siginfo;
 +typedef struct Itimerval Itimerval;
 +typedef struct EpollEvent EpollEvent;
 +typedef uint64 Usigset;
 +
 +#pragma pack on
 +
 +//struct Sigset {
 +//    uint64  sig[1];
 +//};
 +//typedef uint64 Sigset;
 +
 +struct Timespec {
 +      int64   tv_sec;
 +      int64   tv_nsec;
 +};
 +struct Timeval {
 +      int64   tv_sec;
 +      int64   tv_usec;
 +};
 +struct Sigaction {
 +      void    *sa_handler;
 +      uint64  sa_flags;
 +      void    *sa_restorer;
 +      Usigset sa_mask;
 +};
 +struct Siginfo {
 +      int32   si_signo;
 +      int32   si_errno;
 +      int32   si_code;
 +      byte    Pad_cgo_0[4];
 +      byte    _sifields[112];
 +};
 +struct Itimerval {
 +      Timeval it_interval;
 +      Timeval it_value;
 +};
 +struct EpollEvent {
 +      uint32  events;
 +      byte    Pad_cgo_0[4];
 +      uint64  data;
 +};
 +
 +
 +#pragma pack off
 +// Created by cgo -cdefs - DO NOT EDIT
 +// cgo -cdefs defs_linux.go defs3_linux.go
 +
 +
 +enum {
 +      O_RDONLY        = 0x0,
 +      O_CLOEXEC       = 0x80000,
 +      SA_RESTORER     = 0,
 +};
 +
 +//typedef struct Usigset Usigset;
 +typedef struct Ptregs Ptregs;
 +typedef struct Vreg Vreg;
- struct Sigaltstack {
++typedef struct SigaltstackT SigaltstackT;
 +typedef struct Sigcontext Sigcontext;
 +typedef struct Ucontext Ucontext;
 +
 +#pragma pack on
 +
 +//struct Usigset {
 +//    uint64  sig[1];
 +//};
 +//typedef Sigset Usigset;
 +
 +struct Ptregs {
 +      uint64  gpr[32];
 +      uint64  nip;
 +      uint64  msr;
 +      uint64  orig_gpr3;
 +      uint64  ctr;
 +      uint64  link;
 +      uint64  xer;
 +      uint64  ccr;
 +      uint64  softe;
 +      uint64  trap;
 +      uint64  dar;
 +      uint64  dsisr;
 +      uint64  result;
 +};
 +typedef       uint64  Gregset[48];
 +typedef       float64 FPregset[33];
 +struct Vreg {
 +      uint32  u[4];
 +};
 +
-       Sigaltstack     uc_stack;
++struct SigaltstackT {
 +      byte    *ss_sp;
 +      int32   ss_flags;
 +      byte    Pad_cgo_0[4];
 +      uint64  ss_size;
 +};
 +
 +struct Sigcontext {
 +      uint64  _unused[4];
 +      int32   signal;
 +      int32   _pad0;
 +      uint64  handler;
 +      uint64  oldmask;
 +      Ptregs  *regs;
 +      uint64  gp_regs[48];
 +      float64 fp_regs[33];
 +      Vreg    *v_regs;
 +      int64   vmx_reserve[101];
 +};
 +struct Ucontext {
 +      uint64  uc_flags;
 +      Ucontext        *uc_link;
++      SigaltstackT    uc_stack;
 +      Usigset uc_sigmask;
 +      Usigset __unused[15];
 +      Sigcontext      uc_mcontext;
 +};
 +
 +
 +#pragma pack off
index 5e5b7ec3756af4286d6f84a564d4b409e14f7937,88f6703f97df8f21d3a12c9b4c8fafa6c1cf007d..7d432983b1186cbc9baab5f9d5a4c965d8934200
@@@ -117,17 -147,12 +147,18 @@@ func infoBigStruct() []byte 
                }
        case "amd64p32":
                return []byte{
-                       BitsPointer, BitsScalar, BitsScalar, BitsScalar,
-                       BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
-                       BitsScalar, BitsScalar, BitsScalar, BitsScalar,
-                       BitsScalar, BitsScalar, BitsMultiWord, BitsString,
+                       BitsPointer,                                                // q *int
+                       BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+                       BitsPointer, BitsDead, BitsDead, // r []byte
+                       BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+                       BitsPointer, BitsDead, // i string
                }
 +      case "power64", "power64le":
 +              return []byte{
 +                      BitsPointer, BitsScalar, BitsScalar, BitsScalar,
 +                      BitsMultiWord, BitsSlice, BitsScalar, BitsScalar,
 +                      BitsScalar, BitsScalar, BitsMultiWord, BitsString,
 +              }
        default:
                panic("unknown arch")
        }
index f29cf0108f2558867890eca8faeb77697bbbcbb9,d07fdb29bcf9f92f09b45a48ed05ffa3dff6bd19..5696470f2979ea065ab93065bff9ea1f6999ae42
@@@ -261,17 -259,9 +259,9 @@@ dumpbv(BitVector *bv, uintptr offset
                        dumpint(offset + i / BitsPerPointer * PtrSize);
                        break;
                case BitsMultiWord:
 -                      switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
 +                      switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
-                       case BitsString:
-                               dumpint(FieldKindString);
-                               dumpint(offset + i / BitsPerPointer * PtrSize);
-                               i += BitsPerPointer;
-                               break;
-                       case BitsSlice:
-                               dumpint(FieldKindSlice);
-                               dumpint(offset + i / BitsPerPointer * PtrSize);
-                               i += 2 * BitsPerPointer;
-                               break;
+                       default:
+                               runtime·throw("unexpected garbage collection bits");
                        case BitsIface:
                                dumpint(FieldKindIface);
                                dumpint(offset + i / BitsPerPointer * PtrSize);
@@@ -795,10 -803,11 +803,11 @@@ dumpbvtypes(BitVector *bv, byte *base
        uintptr i;
  
        for(i = 0; i < bv->n; i += BitsPerPointer) {
 -              if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
 +              if((bv->bytedata[i/8] >> i%8 & 3) != BitsMultiWord)
                        continue;
 -              switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
 +              switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
-               case BitsString:
+               default:
+                       runtime·throw("unexpected garbage collection bits");
                case BitsIface:
                        i += BitsPerPointer;
                        break;
@@@ -840,8 -847,8 +847,8 @@@ makeheapobjbv(byte *p, uintptr size
                if(!mw && bits == BitsDead)
                        break;  // end of heap object
                mw = !mw && bits == BitsMultiWord;
-               tmpbuf[i*BitsPerPointer/8] &= ~(3<<((i*BitsPerPointer)%8));
+               tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((i*BitsPerPointer)%8));
                tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8);
        }
 -      return (BitVector){i*BitsPerPointer, (uint32*)tmpbuf};
 +      return (BitVector){i*BitsPerPointer, (byte*)tmpbuf};
  }
index 1e133168b17cbcd05b0569ea323f6e7e8e1f0013,752ff60f37b3fa2299fa3a83a9cec642409077bd..91224a38f3c7e222b7ca6205a7e3befcd8c48bbe
@@@ -21,7 -21,10 +21,10 @@@ MHeap runtime·mheap
  #pragma dataflag NOPTR
  MStats runtime·memstats;
  
 -void runtime·cmallocgc(uintptr size, Type *typ, uint32 flag, void **ret);
+ Type* runtime·conservative;
 +void runtime·cmallocgc(uintptr size, Type *typ, intgo flag, void **ret);
+ void runtime·gc_notype_ptr(Eface*);
  
  void*
  runtime·mallocgc(uintptr size, Type *typ, uint32 flag)
index df030794b59cb32dd568c846c2bcee1a797d5807,883ca0cef79dbeba2e30dd089bc2850bfedaa484..ea3a467b8f7bf043f6e5b92b58574987674845d7
@@@ -4,22 -4,15 +4,13 @@@
  
  package runtime
  
 -import (
 -      "unsafe"
 -)
 +import "unsafe"
  
  const (
-       flagNoScan      = 1 << 0 // GC doesn't have to scan object
-       flagNoProfiling = 1 << 1 // must not profile
-       flagNoZero      = 1 << 3 // don't zero memory
-       flagNoInvokeGC  = 1 << 4 // don't invoke GC
-       kindArray      = 17
-       kindFunc       = 19
-       kindInterface  = 20
-       kindPtr        = 22
-       kindStruct     = 25
-       kindMask       = 1<<6 - 1
-       kindGCProg     = 1 << 6
-       kindNoPointers = 1 << 7
+       debugMalloc = false
+       flagNoScan = 1 << 0 // GC doesn't have to scan object
+       flagNoZero = 1 << 1 // don't zero memory
  
        maxTinySize   = 16
        tinySizeClass = 2
@@@ -167,16 -204,96 +202,98 @@@ func gomallocgc(size uintptr, typ *_typ
                size = uintptr(s.elemsize)
        }
  
-       // TODO: write markallocated in Go
-       mp.ptrarg[0] = x
-       mp.scalararg[0] = uint(size)
-       mp.scalararg[1] = uint(size0)
-       mp.ptrarg[1] = unsafe.Pointer(typ)
-       mp.scalararg[2] = uint(flags & flagNoScan)
-       onM(&markallocated_m)
+       if flags&flagNoScan != 0 {
+               // All objects are pre-marked as noscan.
+               goto marked
+       }
+       // From here till marked label marking the object as allocated
+       // and storing type info in the GC bitmap.
+       {
+               arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
+               off := (uintptr(x) - arena_start) / ptrSize
+               xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
+               shift := (off % wordsPerBitmapByte) * gcBits
+               if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
+                       println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
+                       gothrow("bad bits in markallocated")
+               }
  
-       mp.mallocing = 0
+               var ti, te uintptr
+               var ptrmask *uint8
+               if size == ptrSize {
+                       // It's one word and it has pointers, it must be a pointer.
+                       *xbits |= (bitsPointer << 2) << shift
+                       goto marked
+               }
+               if typ.kind&kindGCProg != 0 {
+                       nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
+                       masksize := nptr
+                       if masksize%2 != 0 {
+                               masksize *= 2 // repeated
+                       }
+                       masksize = masksize * pointersPerByte / 8 // 4 bits per word
+                       masksize++                                // unroll flag in the beginning
+                       if masksize > maxGCMask && typ.gc[1] != 0 {
+                               // If the mask is too large, unroll the program directly
+                               // into the GC bitmap. It's 7 times slower than copying
+                               // from the pre-unrolled mask, but saves 1/16 of type size
+                               // memory for the mask.
+                               mp := acquirem()
+                               mp.ptrarg[0] = x
+                               mp.ptrarg[1] = unsafe.Pointer(typ)
+                               mp.scalararg[0] = uintptr(size)
+                               mp.scalararg[1] = uintptr(size0)
+                               onM(unrollgcproginplace_m)
+                               releasem(mp)
+                               goto marked
+                       }
+                       ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
 -                      // Check whether the program is already unrolled.
 -                      if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
++                      // Check whether the program is already unrolled
++                      // by checking if the unroll flag byte is set
++                      maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
++                      if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
+                               mp := acquirem()
+                               mp.ptrarg[0] = unsafe.Pointer(typ)
+                               onM(unrollgcprog_m)
+                               releasem(mp)
+                       }
+                       ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
+               } else {
+                       ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask
+               }
+               if size == 2*ptrSize {
+                       *xbits = *ptrmask | bitBoundary
+                       goto marked
+               }
+               te = uintptr(typ.size) / ptrSize
+               // If the type occupies odd number of words, its mask is repeated.
+               if te%2 == 0 {
+                       te /= 2
+               }
+               // Copy pointer bitmask into the bitmap.
+               for i := uintptr(0); i < size0; i += 2 * ptrSize {
+                       v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
+                       ti++
+                       if ti == te {
+                               ti = 0
+                       }
+                       if i == 0 {
+                               v |= bitBoundary
+                       }
+                       if i+ptrSize == size0 {
+                               v &^= uint8(bitPtrMask << 4)
+                       }
  
+                       *xbits = v
+                       xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
+               }
+               if size0%(2*ptrSize) == 0 && size0 < size {
+                       // Mark the word after last object's word as bitsDead.
+                       *xbits = bitsDead << 2
+               }
+       }
+ marked:
        if raceenabled {
                racemalloc(x, size)
        }
Simple merge
Simple merge
index b1a8943115dd5c2ba7333a22ffcba6bb2c2c64f7,d4c414736be332b45293b97d61038b428fe788e5..7ec9640eb6b47e47b7d85b37f5a7fa24d606f8db
@@@ -510,11 -438,11 +444,11 @@@ markroot(ParFor *desc, uint32 i
        // Note: if you add a case here, please also update heapdump.c:dumproots.
        switch(i) {
        case RootData:
-               scanblock(data, edata - data, work.gcdata);
 -              scanblock(runtime·data, runtime·edata - runtime·data, (byte*)runtime·gcdatamask.data);
++              scanblock(runtime·data, runtime·edata - runtime·data, runtime·gcdatamask.bytedata);
                break;
  
        case RootBss:
-               scanblock(bss, ebss - bss, work.gcbss);
 -              scanblock(runtime·bss, runtime·ebss - runtime·bss, (byte*)runtime·gcbssmask.data);
++              scanblock(runtime·bss, runtime·ebss - runtime·bss, runtime·gcbssmask.bytedata);
                break;
  
        case RootFinalizers:
@@@ -733,7 -668,7 +674,7 @@@ scanframe(Stkframe *frame, void *unused
                }
                bv = runtime·stackmapdata(stackmap, pcdata);
                size = (bv.n * PtrSize) / BitsPerPointer;
-               scanblock(frame->varp - size, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
 -              scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, (byte*)bv.data);
++              scanblock((byte*)frame->varp - size, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
        }
  
        // Scan arguments.
        stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
        if(stackmap != nil) {
                bv = runtime·stackmapdata(stackmap, pcdata);
-               scanblock(frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
 -              scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data);
++              scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
        } else {
                if(Debug > 2)
                        runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
@@@ -1842,14 -1640,23 +1646,23 @@@ unrollglobgcprog(byte *prog, uintptr si
                runtime·throw("unrollglobgcprog: program does not end with insEnd");
        if(mask[masksize] != 0xa1)
                runtime·throw("unrollglobgcprog: overflow");
-       return mask;
 -      return (BitVector){masksize*8, (uint32*)mask};
++      return (BitVector){masksize*8, mask};
  }
  
static void
unrollgcproginplace(void *v, uintptr size, uintptr size0, Type *typ)
+ void
runtime·unrollgcproginplace_m(void)
  {
-       uintptr *b, off, shift, pos;
-       byte *arena_start, *prog;
+       uintptr size, size0, pos, off;
+       byte *arena_start, *prog, *bitp, shift;
+       Type *typ;
+       void *v;
+       v = g->m->ptrarg[0];
+       typ = g->m->ptrarg[1];
+       size = g->m->scalararg[0];
+       size0 = g->m->scalararg[1];
+       g->m->ptrarg[0] = nil;
+       g->m->ptrarg[1] = nil;
  
        pos = 0;
        prog = (byte*)typ->gc[1];
  }
  
  // Unrolls GC program in typ->gc[1] into typ->gc[0]
static void
unrollgcprog(Type *typ)
+ void
runtime·unrollgcprog_m(void)
  {
-       static Lock lock;
+       static Mutex lock;
+       Type *typ;
        byte *mask, *prog;
        uintptr pos;
 -      uint32 x;
 +      uintptr x;
  
+       typ = g->m->ptrarg[0];
+       g->m->ptrarg[0] = nil;
        runtime·lock(&lock);
        mask = (byte*)typ->gc[0];
        if(mask[0] == 0) {
@@@ -2119,8 -1830,8 +1838,8 @@@ runtime·getgcmask(byte *p, Type *t, by
                *len = n/PtrSize;
                *mask = runtime·mallocgc(*len, nil, 0);
                for(i = 0; i < n; i += PtrSize) {
-                       off = (p+i-data)/PtrSize;
-                       bits = (work.gcdata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+                       off = (p+i-runtime·data)/PtrSize;
 -                      bits = (((byte*)runtime·gcdatamask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
++                      bits = (runtime·gcdatamask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
                        (*mask)[i/PtrSize] = bits;
                }
                return;
                *len = n/PtrSize;
                *mask = runtime·mallocgc(*len, nil, 0);
                for(i = 0; i < n; i += PtrSize) {
-                       off = (p+i-bss)/PtrSize;
-                       bits = (work.gcbss[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+                       off = (p+i-runtime·bss)/PtrSize;
 -                      bits = (((byte*)runtime·gcbssmask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
++                      bits = (runtime·gcbssmask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
                        (*mask)[i/PtrSize] = bits;
                }
                return;
                *len = n/PtrSize;
                *mask = runtime·mallocgc(*len, nil, 0);
                for(i = 0; i < n; i += PtrSize) {
-                       off = (p+i-frame.varp+size)/PtrSize;
+                       off = (p+i-(byte*)frame.varp+size)/PtrSize;
 -                      bits = (bv.data[off*BitsPerPointer/32] >> ((off*BitsPerPointer)%32))&BitsMask;
 +                      bits = (bv.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
                        (*mask)[i/PtrSize] = bits;
                }
        }
index 99271a532beaf33897cae5fb9073628ba5ddf419,d04b5cab8feda5a780760c5c04c724d09e0f9aa2..cc7acfbe1f9ea7f3a5f1566f000511a022dcde98
@@@ -7,16 -7,9 +7,16 @@@
  enum {
        ScanStackByFrames = 1,
  
 +      // TODO(rsc): Half the code in the garbage collector
 +      // now accesses the bitmap as an array of bytes
 +      // instead of as an array of uintptrs. 
 +      // This is tricky to do correctly in a portable fashion.
 +      // (It breaks on big-endian systems.)
 +      // Should we just make the bitmap a byte array?
 +
        // Four bits per word (see #defines below).
-       wordsPerBitmapWord = sizeof(void*)*8/4,
        gcBits = 4,
+       wordsPerBitmapByte = 8/gcBits,
  
        // GC type info programs.
        // The programs allow to store type info required for GC in a compact form.
Simple merge
Simple merge
index 0000000000000000000000000000000000000000,1e35561d1541af81e92c88958b699db17e3c0a55..75d155b3fc4711ee5686e5102c617f33d3e9eb45
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,216 +1,216 @@@
 -      if GOARCH == "arm" {
+ // Copyright 2014 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.
+ package runtime
+ import "unsafe"
+ var indexError = error(errorString("index out of range"))
+ func panicindex() {
+       panic(indexError)
+ }
+ var sliceError = error(errorString("slice bounds out of range"))
+ func panicslice() {
+       panic(sliceError)
+ }
+ var divideError = error(errorString("integer divide by zero"))
+ func panicdivide() {
+       panic(divideError)
+ }
+ func throwreturn() {
+       gothrow("no return at end of a typed function - compiler is broken")
+ }
+ func throwinit() {
+       gothrow("recursive call during initialization - linker skew")
+ }
+ // Create a new deferred function fn with siz bytes of arguments.
+ // The compiler turns a defer statement into a call to this.
+ //go:nosplit
+ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
+       // the arguments of fn are in a perilous state.  The stack map
+       // for deferproc does not describe them.  So we can't let garbage
+       // collection or stack copying trigger until we've copied them out
+       // to somewhere safe.  deferproc_m does that.  Until deferproc_m,
+       // we can only call nosplit routines.
+       argp := uintptr(unsafe.Pointer(&fn))
+       argp += unsafe.Sizeof(fn)
++      if GOARCH == "arm" || GOARCH == "power64" || GOARCH == "power64le" {
+               argp += ptrSize // skip caller's saved link register
+       }
+       mp := acquirem()
+       mp.scalararg[0] = uintptr(siz)
+       mp.ptrarg[0] = unsafe.Pointer(fn)
+       mp.scalararg[1] = argp
+       mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz))
+       if mp.curg != getg() {
+               // go code on the m stack can't defer
+               gothrow("defer on m")
+       }
+       onM(deferproc_m)
+       releasem(mp)
+       // deferproc returns 0 normally.
+       // a deferred func that stops a panic
+       // makes the deferproc return 1.
+       // the code the compiler generates always
+       // checks the return value and jumps to the
+       // end of the function if deferproc returns != 0.
+       return0()
+       // No code can go here - the C return register has
+       // been set and must not be clobbered.
+ }
+ // Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
+ // Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
+ // This maps exactly to malloc size classes.
+ // defer size class for arg size sz
+ func deferclass(siz uintptr) uintptr {
+       return (siz + 7) >> 4
+ }
+ // total size of memory block for defer with arg size sz
+ func totaldefersize(siz uintptr) uintptr {
+       return (unsafe.Sizeof(_defer{}) - unsafe.Sizeof(_defer{}.args)) + round(siz, ptrSize)
+ }
+ // Ensure that defer arg sizes that map to the same defer size class
+ // also map to the same malloc size class.
+ func testdefersizes() {
+       var m [len(p{}.deferpool)]int32
+       for i := range m {
+               m[i] = -1
+       }
+       for i := uintptr(0); ; i++ {
+               defersc := deferclass(i)
+               if defersc >= uintptr(len(m)) {
+                       break
+               }
+               siz := goroundupsize(totaldefersize(i))
+               if m[defersc] < 0 {
+                       m[defersc] = int32(siz)
+                       continue
+               }
+               if m[defersc] != int32(siz) {
+                       print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
+                       gothrow("bad defer size class")
+               }
+       }
+ }
+ // Allocate a Defer, usually using per-P pool.
+ // Each defer must be released with freedefer.
+ // Note: runs on M stack
+ func newdefer(siz int32) *_defer {
+       var d *_defer
+       sc := deferclass(uintptr(siz))
+       mp := acquirem()
+       if sc < uintptr(len(p{}.deferpool)) {
+               pp := mp.p
+               d = pp.deferpool[sc]
+               if d != nil {
+                       pp.deferpool[sc] = d.link
+               }
+       }
+       if d == nil {
+               // deferpool is empty or just a big defer
+               total := goroundupsize(totaldefersize(uintptr(siz)))
+               d = (*_defer)(gomallocgc(total, conservative, 0))
+       }
+       d.siz = siz
+       d.special = false
+       gp := mp.curg
+       d.link = gp._defer
+       gp._defer = d
+       releasem(mp)
+       return d
+ }
+ // Free the given defer.
+ // The defer cannot be used after this call.
+ func freedefer(d *_defer) {
+       if d.special {
+               return
+       }
+       sc := deferclass(uintptr(d.siz))
+       if sc < uintptr(len(p{}.deferpool)) {
+               mp := acquirem()
+               pp := mp.p
+               d.link = pp.deferpool[sc]
+               pp.deferpool[sc] = d
+               releasem(mp)
+               // No need to wipe out pointers in argp/pc/fn/args,
+               // because we empty the pool before GC.
+       }
+ }
+ // Run a deferred function if there is one.
+ // The compiler inserts a call to this at the end of any
+ // function which calls defer.
+ // If there is a deferred function, this will call runtime·jmpdefer,
+ // which will jump to the deferred function such that it appears
+ // to have been called by the caller of deferreturn at the point
+ // just before deferreturn was called.  The effect is that deferreturn
+ // is called again and again until there are no more deferred functions.
+ // Cannot split the stack because we reuse the caller's frame to
+ // call the deferred function.
+ // The single argument isn't actually used - it just has its address
+ // taken so it can be matched against pending defers.
+ //go:nosplit
+ func deferreturn(arg0 uintptr) {
+       gp := getg()
+       d := gp._defer
+       if d == nil {
+               return
+       }
+       argp := uintptr(unsafe.Pointer(&arg0))
+       if d.argp != argp {
+               return
+       }
+       // Moving arguments around.
+       // Do not allow preemption here, because the garbage collector
+       // won't know the form of the arguments until the jmpdefer can
+       // flip the PC over to fn.
+       mp := acquirem()
+       memmove(unsafe.Pointer(argp), unsafe.Pointer(&d.args), uintptr(d.siz))
+       fn := d.fn
+       gp._defer = d.link
+       freedefer(d)
+       releasem(mp)
+       jmpdefer(fn, argp)
+ }
+ // Goexit terminates the goroutine that calls it.  No other goroutine is affected.
+ // Goexit runs all deferred calls before terminating the goroutine.
+ //
+ // Calling Goexit from the main goroutine terminates that goroutine
+ // without func main returning. Since func main has not returned,
+ // the program continues execution of other goroutines.
+ // If all other goroutines exit, the program crashes.
+ func Goexit() {
+       // Run all deferred functions for the current goroutine.
+       gp := getg()
+       for gp._defer != nil {
+               d := gp._defer
+               gp._defer = d.link
+               reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz))
+               freedefer(d)
+               // Note: we ignore recovers here because Goexit isn't a panic
+       }
+       goexit()
+ }
index 0000000000000000000000000000000000000000,e8774343208e835c325a2e94b6e916b511738b3a..9faae8a4b1bb653bb46a826e30a231c4938d5b1e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,209 +1,209 @@@
 -      print("fatal error: ", gostringnocopy(s), "\n")
+ // Copyright 2012 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.
+ package runtime
+ import "unsafe"
+ // Print all currently active panics.  Used when crashing.
+ func printpanics(p *_panic) {
+       if p.link != nil {
+               printpanics(p.link)
+               print("\t")
+       }
+       print("panic: ")
+       printany(p.arg)
+       if p.recovered {
+               print(" [recovered]")
+       }
+       print("\n")
+ }
+ // The implementation of the predeclared function panic.
+ func gopanic(e interface{}) {
+       gp := getg()
+       if gp.m.curg != gp {
+               gothrow("panic on m stack")
+       }
+       var p _panic
+       var dabort _defer
+       p.arg = e
+       p.link = gp._panic
+       gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
+       fn := abortpanic
+       dabort.fn = *(**funcval)(unsafe.Pointer(&fn))
+       dabort.siz = ptrSize
+       dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here?
+       dabort.argp = _NoArgs
+       dabort.special = true
+       for {
+               d := gp._defer
+               if d == nil {
+                       break
+               }
+               // take defer off list in case of recursive panic
+               gp._defer = d.link
+               argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
+               pc := d.pc
+               // The deferred function may cause another panic,
+               // so reflectcall may not return. Set up a defer
+               // to mark this panic aborted if that happens.
+               dabort.link = gp._defer
+               gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort)))
+               p._defer = d
+               p.argp = getargp(0)
+               reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz))
+               p.argp = 0
+               // reflectcall did not panic. Remove dabort.
+               if gp._defer != &dabort {
+                       gothrow("bad defer entry in panic")
+               }
+               gp._defer = dabort.link
+               // trigger shrinkage to test stack copy.  See stack_test.go:TestStackPanic
+               //GC()
+               freedefer(d)
+               if p.recovered {
+                       gp._panic = p.link
+                       // Aborted panics are marked but remain on the g.panic list.
+                       // Remove them from the list and free the associated defers.
+                       for gp._panic != nil && gp._panic.aborted {
+                               freedefer(gp._panic._defer)
+                               gp._panic = gp._panic.link
+                       }
+                       if gp._panic == nil { // must be done with signal
+                               gp.sig = 0
+                       }
+                       // Pass information about recovering frame to recovery.
+                       gp.sigcode0 = uintptr(argp)
+                       gp.sigcode1 = pc
+                       mcall(recovery_m)
+                       gothrow("recovery failed") // mcall should not return
+               }
+       }
+       // ran out of deferred calls - old-school panic now
+       startpanic()
+       printpanics(gp._panic)
+       dopanic(0)       // should not return
+       *(*int)(nil) = 0 // not reached
+ }
+ // getargp returns the location where the caller
+ // writes outgoing function call arguments.
+ //go:nosplit
+ func getargp(x int) uintptr {
+       // x is an argument mainly so that we can return its address.
+       // However, we need to make the function complex enough
+       // that it won't be inlined. We always pass x = 0, so this code
+       // does nothing other than keep the compiler from thinking
+       // the function is simple enough to inline.
+       if x > 0 {
+               return getcallersp(unsafe.Pointer(&x)) * 0
+       }
+       return uintptr(noescape(unsafe.Pointer(&x)))
+ }
+ func abortpanic(p *_panic) {
+       p.aborted = true
+ }
+ // The implementation of the predeclared function recover.
+ // Cannot split the stack because it needs to reliably
+ // find the stack segment of its caller.
+ //
+ // TODO(rsc): Once we commit to CopyStackAlways,
+ // this doesn't need to be nosplit.
+ //go:nosplit
+ func gorecover(argp uintptr) interface{} {
+       // Must be in a function running as part of a deferred call during the panic.
+       // Must be called from the topmost function of the call
+       // (the function used in the defer statement).
+       // p.argp is the argument pointer of that topmost deferred function call.
+       // Compare against argp reported by caller.
+       // If they match, the caller is the one who can recover.
+       gp := getg()
+       p := gp._panic
+       if p != nil && !p.recovered && argp == p.argp {
+               p.recovered = true
+               return p.arg
+       }
+       return nil
+ }
+ //go:nosplit
+ func startpanic() {
+       onM(startpanic_m)
+ }
+ //go:nosplit
+ func dopanic(unused int) {
+       gp := getg()
+       mp := acquirem()
+       mp.ptrarg[0] = unsafe.Pointer(gp)
+       mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused))
+       mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused))
+       onM(dopanic_m) // should never return
+       *(*int)(nil) = 0
+ }
+ //go:nosplit
+ func throw(s *byte) {
++      print("fatal error: ", gostringnocopy(s), "\n")
+       gp := getg()
+       if gp.m.throwing == 0 {
+               gp.m.throwing = 1
+       }
+       startpanic()
+       dopanic(0)
+       *(*int)(nil) = 0 // not reached
+ }
+ //go:nosplit
+ func gothrow(s string) {
+       gp := getg()
+       if gp.m.throwing == 0 {
+               gp.m.throwing = 1
+       }
+       startpanic()
+       print("fatal error: ", s, "\n")
+       dopanic(0)
+       *(*int)(nil) = 0 // not reached
+ }
+ func panicstring(s *int8) {
+       // m.softfloat is set during software floating point,
+       // which might cause a fault during a memory load.
+       // It increments m.locks to avoid preemption.
+       // If we're panicking, the software floating point frames
+       // will be unwound, so decrement m.locks as they would.
+       gp := getg()
+       if gp.m.softfloat != 0 {
+               gp.m.locks--
+               gp.m.softfloat = 0
+       }
+       if gp.m.mallocing != 0 {
+               print("panic: ", s, "\n")
+               gothrow("panic during malloc")
+       }
+       if gp.m.gcing != 0 {
+               print("panic: ", s, "\n")
+               gothrow("panic during gc")
+       }
+       if gp.m.locks != 0 {
+               print("panic: ", s, "\n")
+               gothrow("panic holding locks")
+       }
+       var err interface{}
+       newErrorCString(unsafe.Pointer(s), &err)
+       gopanic(err)
+ }
index 23513e1a7ba0dd18ecb2cac0d87c963263c85aa9,698be9ffaeb6355d020efb7770b98d97a108da61..d77f20abf96d1c7e78612ae8a146a8eaa917d28b
@@@ -1832,8 -2244,9 +2244,9 @@@ voi
  runtime·newproc(int32 siz, FuncVal* fn, ...)
  {
        byte *argp;
+       void (*mfn)(void);
  
 -      if(thechar == '5')
 +      if(thechar == '5' || thechar == '9')
                argp = (byte*)(&fn+2);  // skip caller's saved LR
        else
                argp = (byte*)(&fn+1);
index 88f24408ba8884de6b309e73c61f80054443c791,18b3f40648806ed34b63c90235a2443859b89fa2..b85a8448402ccdafcab744433e00b1921fb0331d
@@@ -567,23 -601,12 +601,12 @@@ adjustpointers(byte **scanp, BitVector 
                        }
                        break;
                case BitsMultiWord:
 -                      switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
 +                      switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
-                       case BitsString:
-                               // string referents are never on the stack, never need to be adjusted
-                               i++; // skip len
-                               break;
-                       case BitsSlice:
-                               p = scanp[i];
-                               if(minp <= p && p < maxp) {
-                                       if(StackDebug >= 3)
-                                               runtime·printf("adjust slice %p\n", p);
-                                       scanp[i] = p + delta;
-                               }
-                               i += 2; // skip len, cap
-                               break;
+                       default:
+                               runtime·throw("unexpected garbage collection bits");
                        case BitsEface:
                                t = (Type*)scanp[i];
-                               if(t != nil && (t->size > PtrSize || (t->kind & KindNoPointers) == 0)) {
+                               if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
                                        p = scanp[i+1];
                                        if(minp <= p && p < maxp) {
                                                if(StackDebug >= 3)
@@@ -969,7 -1045,8 +1045,8 @@@ runtime·newstack(void
                while(dst < dstend)
                        *dst++ = *src++;
        }
 -      if(thechar == '5') {
+       
 +      if(thechar == '5' || thechar == '9') {
                // caller would have saved its LR below args.
                sp -= sizeof(void*);
                *(void**)sp = nil;
Simple merge
index 0000000000000000000000000000000000000000,babc9276802b2d79b9699f4a97eae5c619bbc909..8cd9afe60801a169d24522b61284b58ec8fc7030
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,150 +1,156 @@@
+ // Copyright 2014 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.
+ // This file exposes various internal runtime functions to other packages in std lib.
+ #include "zasm_GOOS_GOARCH.h"
+ #include "textflag.h"
+ #ifdef GOARCH_arm
+ #define JMP B
+ #endif
++#ifdef GOARCH_power64
++#define JMP BR
++#endif
++#ifdef GOARCH_power64le
++#define JMP BR
++#endif
+ TEXT net·runtimeNano(SB),NOSPLIT,$0-0
+       JMP     runtime·nanotime(SB)
+ TEXT time·runtimeNano(SB),NOSPLIT,$0-0
+       JMP     runtime·nanotime(SB)
+ TEXT time·Sleep(SB),NOSPLIT,$0-0
+       JMP     runtime·timeSleep(SB)
+ TEXT time·startTimer(SB),NOSPLIT,$0-0
+       JMP     runtime·startTimer(SB)
+ TEXT time·stopTimer(SB),NOSPLIT,$0-0
+       JMP     runtime·stopTimer(SB)
+ TEXT sync·runtime_Syncsemacquire(SB),NOSPLIT,$0-0
+       JMP     runtime·syncsemacquire(SB)
+ TEXT sync·runtime_Syncsemrelease(SB),NOSPLIT,$0-0
+       JMP     runtime·syncsemrelease(SB)
+ TEXT sync·runtime_Syncsemcheck(SB),NOSPLIT,$0-0
+       JMP     runtime·syncsemcheck(SB)
+ TEXT sync·runtime_Semacquire(SB),NOSPLIT,$0-0
+       JMP     runtime·asyncsemacquire(SB)
+ TEXT sync·runtime_Semrelease(SB),NOSPLIT,$0-0
+       JMP     runtime·asyncsemrelease(SB)
+ TEXT sync·runtime_registerPoolCleanup(SB),NOSPLIT,$0-0
+       JMP     runtime·registerPoolCleanup(SB)
+ TEXT net·runtime_Semacquire(SB),NOSPLIT,$0-0
+       JMP     runtime·asyncsemacquire(SB)
+ TEXT net·runtime_Semrelease(SB),NOSPLIT,$0-0
+       JMP     runtime·asyncsemrelease(SB)
+ TEXT runtime∕pprof·runtime_cyclesPerSecond(SB),NOSPLIT,$0-0
+       JMP     runtime·tickspersecond(SB)
+ TEXT bytes·Compare(SB),NOSPLIT,$0-0
+       JMP     runtime·cmpbytes(SB)
+ TEXT runtime·reflectcall(SB), NOSPLIT, $0-0
+       JMP     reflect·call(SB)
+ TEXT reflect·chanclose(SB), NOSPLIT, $0-0
+       JMP     runtime·closechan(SB)
+ TEXT reflect·chanlen(SB), NOSPLIT, $0-0
+       JMP     runtime·reflect_chanlen(SB)
+ TEXT reflect·chancap(SB), NOSPLIT, $0-0
+       JMP     runtime·reflect_chancap(SB)
+ TEXT reflect·chansend(SB), NOSPLIT, $0-0
+       JMP     runtime·reflect_chansend(SB)
+ TEXT reflect·chanrecv(SB), NOSPLIT, $0-0
+       JMP     runtime·reflect_chanrecv(SB)
+ TEXT runtime∕debug·freeOSMemory(SB), NOSPLIT, $0-0
+       JMP     runtime·freeOSMemory(SB)
+ TEXT net·runtime_pollServerInit(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollServerInit(SB)
+ TEXT net·runtime_pollOpen(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollOpen(SB)
+ TEXT net·runtime_pollClose(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollClose(SB)
+ TEXT net·runtime_pollReset(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollReset(SB)
+ TEXT net·runtime_pollWait(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollWait(SB)
+ TEXT net·runtime_pollWaitCanceled(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollWaitCanceled(SB)
+ TEXT net·runtime_pollSetDeadline(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollSetDeadline(SB)
+ TEXT net·runtime_pollUnblock(SB),NOSPLIT,$0-0
+       JMP     runtime·netpollUnblock(SB)
+ TEXT syscall·setenv_c(SB), NOSPLIT, $0-0
+       JMP     runtime·syscall_setenv_c(SB)
+ TEXT reflect·makemap(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_makemap(SB)
+ TEXT reflect·mapaccess(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapaccess(SB)
+ TEXT reflect·mapassign(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapassign(SB)
+ TEXT reflect·mapdelete(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapdelete(SB)
+ TEXT reflect·mapiterinit(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapiterinit(SB)
+ TEXT reflect·mapiterkey(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapiterkey(SB)
+ TEXT reflect·mapiternext(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_mapiternext(SB)
+ TEXT reflect·maplen(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_maplen(SB)
+ TEXT reflect·ismapkey(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_ismapkey(SB)
+ TEXT reflect·ifaceE2I(SB),NOSPLIT,$0-0
+       JMP     runtime·reflect_ifaceE2I(SB)
+ TEXT reflect·unsafe_New(SB),NOSPLIT,$0-0
+       JMP     runtime·newobject(SB)
+ TEXT reflect·unsafe_NewArray(SB),NOSPLIT,$0-0
+       JMP     runtime·newarray(SB)
+ TEXT reflect·makechan(SB),NOSPLIT,$0-0
+       JMP     runtime·makechan(SB)
+ TEXT reflect·rselect(SB), NOSPLIT, $0-0
+       JMP     runtime·reflect_rselect(SB)
+ TEXT os·sigpipe(SB), NOSPLIT, $0-0
+       JMP     runtime·os_sigpipe(SB)
Simple merge
diff --cc test/nosplit.go
index b5399ad38d4ea545ca617518f87e2ea360344586,c9d008acd396cc3eaae69353af4bbd9ed525af1a..8dab2fc7a751eb5bf7610b87d39c843a45879148
@@@ -264,7 -255,15 +264,15 @@@ TestCases
                                }
                                name := m[1]
                                size, _ := strconv.Atoi(m[2])
 -                              if goarch == "amd64" && size%8 == 4 {
+                               // The limit was originally 128 but is now 384.
+                               // Instead of rewriting the test cases above, adjust
+                               // the first stack frame to use up the extra 32 bytes.
+                               if i == 0 {
+                                       size += 384 - 128
+                               }
 +                              if size%ptrSize == 4 {
                                        continue TestCases
                                }
                                nosplit := m[3]