aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2015-02-23 14:20:01 -0500
committerRuss Cox <rsc@golang.org>2015-02-23 19:56:40 +0000
commit3af0d791bed25e6cb4689fed9cc8379554971cb8 (patch)
treeeec8f2e1994580960a68c9cc06911ed934a1e35f
parentd10ede5edec7ace23e68c15ed996e64aec20d6bc (diff)
downloadgo-3af0d791bed25e6cb4689fed9cc8379554971cb8.tar.gz
go-3af0d791bed25e6cb4689fed9cc8379554971cb8.zip
[dev.cc] cmd/6a, cmd/6g etc: replace C implementations with Go implementations
Change-Id: I58e00a39cf63df07813d21453f91e68eef6a413c Reviewed-on: https://go-review.googlesource.com/5635 Reviewed-by: Rob Pike <r@golang.org>
-rw-r--r--src/cmd/5a/Makefile10
-rw-r--r--src/cmd/5a/a.h173
-rw-r--r--src/cmd/5a/a.y385
-rw-r--r--src/cmd/5a/doc.go20
-rw-r--r--src/cmd/5a/lex.c538
-rw-r--r--src/cmd/5a/lex.go (renamed from src/cmd/new5a/lex.go)0
-rw-r--r--src/cmd/5a/y.go (renamed from src/cmd/new5a/y.go)0
-rw-r--r--src/cmd/5a/y.tab.c2855
-rw-r--r--src/cmd/5a/y.tab.h166
-rw-r--r--src/cmd/5g/Makefile5
-rw-r--r--src/cmd/5g/cgen.c1840
-rw-r--r--src/cmd/5g/cgen.go (renamed from src/cmd/new5g/cgen.go)0
-rw-r--r--src/cmd/5g/cgen64.c760
-rw-r--r--src/cmd/5g/cgen64.go (renamed from src/cmd/new5g/cgen64.go)0
-rw-r--r--src/cmd/5g/doc.go15
-rw-r--r--src/cmd/5g/galign.c87
-rw-r--r--src/cmd/5g/galign.go (renamed from src/cmd/new5g/galign.go)0
-rw-r--r--src/cmd/5g/gg.go (renamed from src/cmd/new5g/gg.go)0
-rw-r--r--src/cmd/5g/gg.h177
-rw-r--r--src/cmd/5g/ggen.c751
-rw-r--r--src/cmd/5g/ggen.go (renamed from src/cmd/new5g/ggen.go)0
-rw-r--r--src/cmd/5g/gsubr.c1527
-rw-r--r--src/cmd/5g/gsubr.go (renamed from src/cmd/new5g/gsubr.go)0
-rw-r--r--src/cmd/5g/peep.c1619
-rw-r--r--src/cmd/5g/peep.go (renamed from src/cmd/new5g/peep.go)0
-rw-r--r--src/cmd/5g/prog.c160
-rw-r--r--src/cmd/5g/prog.go (renamed from src/cmd/new5g/prog.go)0
-rw-r--r--src/cmd/5g/reg.c146
-rw-r--r--src/cmd/5g/reg.go (renamed from src/cmd/new5g/reg.go)0
-rw-r--r--src/cmd/5g/util.go (renamed from src/cmd/new5g/util.go)0
-rw-r--r--src/cmd/6a/Makefile10
-rw-r--r--src/cmd/6a/a.h188
-rw-r--r--src/cmd/6a/a.y383
-rw-r--r--src/cmd/6a/doc.go20
-rw-r--r--src/cmd/6a/lex.c1137
-rw-r--r--src/cmd/6a/lex.go (renamed from src/cmd/new6a/lex.go)0
-rw-r--r--src/cmd/6a/y.go (renamed from src/cmd/new6a/y.go)0
-rw-r--r--src/cmd/6a/y.tab.c2800
-rw-r--r--src/cmd/6a/y.tab.h139
-rw-r--r--src/cmd/6g/Makefile5
-rw-r--r--src/cmd/6g/cgen.c1745
-rw-r--r--src/cmd/6g/cgen.go (renamed from src/cmd/new6g/cgen.go)0
-rw-r--r--src/cmd/6g/doc.go15
-rw-r--r--src/cmd/6g/galign.c110
-rw-r--r--src/cmd/6g/galign.go (renamed from src/cmd/new6g/galign.go)0
-rw-r--r--src/cmd/6g/gg.go (renamed from src/cmd/new6g/gg.go)0
-rw-r--r--src/cmd/6g/gg.h176
-rw-r--r--src/cmd/6g/ggen.c1046
-rw-r--r--src/cmd/6g/ggen.go (renamed from src/cmd/new6g/ggen.go)0
-rw-r--r--src/cmd/6g/gsubr.c1737
-rw-r--r--src/cmd/6g/gsubr.go (renamed from src/cmd/new6g/gsubr.go)0
-rw-r--r--src/cmd/6g/peep.c988
-rw-r--r--src/cmd/6g/peep.go (renamed from src/cmd/new6g/peep.go)0
-rw-r--r--src/cmd/6g/prog.c318
-rw-r--r--src/cmd/6g/prog.go (renamed from src/cmd/new6g/prog.go)0
-rw-r--r--src/cmd/6g/reg.c153
-rw-r--r--src/cmd/6g/reg.go (renamed from src/cmd/new6g/reg.go)0
-rw-r--r--src/cmd/6g/util.go (renamed from src/cmd/new6g/util.go)0
-rw-r--r--src/cmd/8a/Makefile10
-rw-r--r--src/cmd/8a/a.h186
-rw-r--r--src/cmd/8a/a.y381
-rw-r--r--src/cmd/8a/doc.go21
-rw-r--r--src/cmd/8a/lex.c914
-rw-r--r--src/cmd/8a/lex.go (renamed from src/cmd/new8a/lex.go)0
-rw-r--r--src/cmd/8a/y.go (renamed from src/cmd/new8a/y.go)0
-rw-r--r--src/cmd/8a/y.tab.c2778
-rw-r--r--src/cmd/8a/y.tab.h135
-rw-r--r--src/cmd/8g/Makefile5
-rw-r--r--src/cmd/8g/cgen.c1590
-rw-r--r--src/cmd/8g/cgen.go (renamed from src/cmd/new8g/cgen.go)0
-rw-r--r--src/cmd/8g/cgen64.c549
-rw-r--r--src/cmd/8g/cgen64.go (renamed from src/cmd/new8g/cgen64.go)0
-rw-r--r--src/cmd/8g/doc.go15
-rw-r--r--src/cmd/8g/galign.c87
-rw-r--r--src/cmd/8g/galign.go (renamed from src/cmd/new8g/galign.go)0
-rw-r--r--src/cmd/8g/gg.go (renamed from src/cmd/new8g/gg.go)0
-rw-r--r--src/cmd/8g/gg.h189
-rw-r--r--src/cmd/8g/ggen.c1165
-rw-r--r--src/cmd/8g/ggen.go (renamed from src/cmd/new8g/ggen.go)0
-rw-r--r--src/cmd/8g/gsubr.c1874
-rw-r--r--src/cmd/8g/gsubr.go (renamed from src/cmd/new8g/gsubr.go)0
-rw-r--r--src/cmd/8g/peep.c773
-rw-r--r--src/cmd/8g/peep.go (renamed from src/cmd/new8g/peep.go)0
-rw-r--r--src/cmd/8g/prog.c349
-rw-r--r--src/cmd/8g/prog.go (renamed from src/cmd/new8g/prog.go)0
-rw-r--r--src/cmd/8g/reg.c112
-rw-r--r--src/cmd/8g/reg.go (renamed from src/cmd/new8g/reg.go)0
-rw-r--r--src/cmd/8g/util.go (renamed from src/cmd/new8g/util.go)0
-rw-r--r--src/cmd/9a/Makefile10
-rw-r--r--src/cmd/9a/a.h172
-rw-r--r--src/cmd/9a/a.y544
-rw-r--r--src/cmd/9a/doc.go21
-rw-r--r--src/cmd/9a/lex.c726
-rw-r--r--src/cmd/9a/lex.go (renamed from src/cmd/new9a/lex.go)0
-rw-r--r--src/cmd/9a/y.go (renamed from src/cmd/new9a/y.go)0
-rw-r--r--src/cmd/9a/y.tab.c3466
-rw-r--r--src/cmd/9a/y.tab.h190
-rw-r--r--src/cmd/9g/cgen.c1758
-rw-r--r--src/cmd/9g/cgen.go (renamed from src/cmd/new9g/cgen.go)0
-rw-r--r--src/cmd/9g/doc.go16
-rw-r--r--src/cmd/9g/galign.c94
-rw-r--r--src/cmd/9g/galign.go (renamed from src/cmd/new9g/galign.go)0
-rw-r--r--src/cmd/9g/gg.go (renamed from src/cmd/new9g/gg.go)0
-rw-r--r--src/cmd/9g/gg.h169
-rw-r--r--src/cmd/9g/ggen.c965
-rw-r--r--src/cmd/9g/ggen.go (renamed from src/cmd/new9g/ggen.go)0
-rw-r--r--src/cmd/9g/gsubr.c1158
-rw-r--r--src/cmd/9g/gsubr.go (renamed from src/cmd/new9g/gsubr.go)0
-rw-r--r--src/cmd/9g/opt.go (renamed from src/cmd/new9g/opt.go)0
-rw-r--r--src/cmd/9g/opt.h13
-rw-r--r--src/cmd/9g/peep.c959
-rw-r--r--src/cmd/9g/peep.go (renamed from src/cmd/new9g/peep.go)0
-rw-r--r--src/cmd/9g/prog.c308
-rw-r--r--src/cmd/9g/prog.go (renamed from src/cmd/new9g/prog.go)0
-rw-r--r--src/cmd/9g/reg.c172
-rw-r--r--src/cmd/9g/reg.go (renamed from src/cmd/new9g/reg.go)0
-rw-r--r--src/cmd/9g/util.go (renamed from src/cmd/new9g/util.go)0
-rw-r--r--src/cmd/gc/Makefile17
-rw-r--r--src/cmd/gc/align.c689
-rw-r--r--src/cmd/gc/array.c107
-rwxr-xr-xsrc/cmd/gc/bisonerrors156
-rw-r--r--src/cmd/gc/bits.c173
-rw-r--r--src/cmd/gc/builtin.c165
-rw-r--r--src/cmd/gc/bv.c213
-rw-r--r--src/cmd/gc/closure.c659
-rw-r--r--src/cmd/gc/const.c1678
-rw-r--r--src/cmd/gc/cplx.c494
-rw-r--r--src/cmd/gc/dcl.c1479
-rw-r--r--src/cmd/gc/doc.go95
-rw-r--r--src/cmd/gc/esc.c1342
-rw-r--r--src/cmd/gc/export.c563
-rw-r--r--src/cmd/gc/fmt.c1697
-rw-r--r--src/cmd/gc/gen.c987
-rw-r--r--src/cmd/gc/go.errors79
-rw-r--r--src/cmd/gc/go.h1757
-rw-r--r--src/cmd/gc/go.y2225
-rw-r--r--src/cmd/gc/gsubr.c654
-rw-r--r--src/cmd/gc/init.c194
-rw-r--r--src/cmd/gc/inl.c986
-rw-r--r--src/cmd/gc/lex.c2590
-rw-r--r--src/cmd/gc/md5.c302
-rw-r--r--src/cmd/gc/md5.h16
-rwxr-xr-xsrc/cmd/gc/mkbuiltin36
-rw-r--r--src/cmd/gc/mkbuiltin1.c102
-rwxr-xr-xsrc/cmd/gc/mkopnames24
-rw-r--r--src/cmd/gc/mparith1.c655
-rw-r--r--src/cmd/gc/mparith2.c689
-rw-r--r--src/cmd/gc/mparith3.c346
-rw-r--r--src/cmd/gc/obj.c498
-rw-r--r--src/cmd/gc/order.c1164
-rw-r--r--src/cmd/gc/pgen.c547
-rw-r--r--src/cmd/gc/plive.c2005
-rw-r--r--src/cmd/gc/popt.c1022
-rw-r--r--src/cmd/gc/popt.h152
-rw-r--r--src/cmd/gc/racewalk.c653
-rw-r--r--src/cmd/gc/range.c378
-rw-r--r--src/cmd/gc/reflect.c1609
-rw-r--r--src/cmd/gc/reg.c1233
-rw-r--r--src/cmd/gc/runtime.go191
-rw-r--r--src/cmd/gc/select.c375
-rw-r--r--src/cmd/gc/sinit.c1502
-rw-r--r--src/cmd/gc/subr.c3856
-rw-r--r--src/cmd/gc/swt.c944
-rw-r--r--src/cmd/gc/typecheck.c3649
-rw-r--r--src/cmd/gc/unsafe.c150
-rw-r--r--src/cmd/gc/unsafe.go18
-rw-r--r--src/cmd/gc/walk.c4189
-rw-r--r--src/cmd/gc/y.tab.c5134
-rw-r--r--src/cmd/gc/y.tab.h167
-rw-r--r--src/cmd/gc/yerr.h79
-rw-r--r--src/cmd/new5a/a.y795
-rw-r--r--src/cmd/new6a/a.y723
-rw-r--r--src/cmd/new8a/a.y713
-rw-r--r--src/cmd/new9a/a.y1055
-rw-r--r--src/cmd/objwriter/main.go411
175 files changed, 856 insertions, 97603 deletions
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
deleted file mode 100644
index 27290ddd71..0000000000
--- a/src/cmd/5a/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
- LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
deleted file mode 100644
index 8a6764b166..0000000000
--- a/src/cmd/5a/a.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno utils/5a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
-//
-// 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 <bio.h>
-#include <link.h>
-#include "../5l/5.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef getc
-#undef ungetc
-#undef BUFSIZ
-
-#define getc ccgetc
-#define ungetc ccungetc
-
-typedef struct Sym Sym;
-typedef struct Io Io;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 8192
-#define BUFSIZ 8192
-#define HISTSZ 20
-#ifndef EOF
-#define EOF (-1)
-#endif
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- char* macro;
- int32 value;
- ushort type;
- char *name;
- char* labelname;
- char sym;
-};
-#define S ((Sym*)0)
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-
- Always = C_SCOND_NONE,
-};
-
-EXTERN int debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN int newflag;
-EXTERN char* hunk;
-EXTERN char** include;
-EXTERN Io* iofree;
-EXTERN Io* ionext;
-EXTERN Io* iostack;
-EXTERN int32 lineno;
-EXTERN int nerrors;
-EXTERN int32 nhunk;
-EXTERN int ninclude;
-EXTERN int32 nsymb;
-EXTERN Addr nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-EXTERN Link* ctxt;
-EXTERN Biobuf bstdout;
-EXTERN Prog* lastpc;
-
-void* alloc(int32);
-void* allocn(void*, int32, int32);
-void ensuresymb(int32);
-void errorexit(void);
-void pushio(void);
-void newio(void);
-void newfile(char*, int);
-Sym* slookup(char*);
-Sym* lookup(void);
-Sym* labellookup(Sym*);
-void settext(LSym*);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void pinit(char*);
-void cclean(void);
-int isreg(Addr*);
-void outcode(int, int, Addr*, int, Addr*);
-int filbuf(void);
-Sym* getsym(void);
-void domacro(void);
-void macund(void);
-void macdef(void);
-void macexpand(Sym*, char*);
-void macinc(void);
-void maclin(void);
-void macprag(void);
-void macif(int);
-void macend(void);
-void dodefine(char*);
-void prfile(int32);
-void linehist(char*, int);
-void gethunk(void);
-void yyerror(char*, ...);
-int yyparse(void);
-void setinclude(char*);
-int assemble(char*);
-void listinit(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index 10e9f6feea..39fab8fa26 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -29,20 +29,23 @@
// THE SOFTWARE.
%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
+package main
+
+import (
+ "cmd/internal/asm"
+ "cmd/internal/obj"
+ . "cmd/internal/obj/arm"
+)
%}
-%union
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
+
+%union {
+ sym *asm.Sym
+ lval int32
+ dval float64
+ sval string
+ addr obj.Addr
}
+
%left '|'
%left '^'
%left '&'
@@ -51,12 +54,12 @@
%left '*' '/' '%'
%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
-%token <lval> LTYPEB LGLOBL LTYPEC LTYPED LTYPEE
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE
%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
%token <lval> LCONST LSP LSB LFP LPC
%token <lval> LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
-%token <lval> LCOND LS LAT
+%token <lval> LCOND LS LAT LGLOBL
%token <dval> LFCONST
%token <sval> LSCONST
%token <sym> LNAME LLAB LVAR
@@ -68,30 +71,32 @@
prog:
| prog
{
- stmtline = lineno;
+ stmtline = asm.Lineno;
}
line
line:
LNAME ':'
{
- $1 = labellookup($1);
- if($1->type == LLAB && $1->value != pc)
- yyerror("redeclaration of %s", $1->labelname);
- $1->type = LLAB;
- $1->value = pc;
+ $1 = asm.LabelLookup($1);
+ if $1.Type == LLAB && $1.Value != int64(asm.PC) {
+ yyerror("redeclaration of %s", $1.Labelname)
+ }
+ $1.Type = LLAB;
+ $1.Value = int64(asm.PC)
}
line
| LNAME '=' expr ';'
{
- $1->type = LVAR;
- $1->value = $3;
+ $1.Type = LVAR;
+ $1.Value = int64($3);
}
| LVAR '=' expr ';'
{
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
+ if $1.Value != int64($3) {
+ yyerror("redeclaration of %s", $1.Name)
+ }
+ $1.Value = int64($3);
}
| ';'
| inst ';'
@@ -171,20 +176,20 @@ inst:
*/
| LTYPE8 cond ioreg ',' '[' reglist ']'
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset = $6;
+ g.Type = obj.TYPE_CONST;
+ g.Offset = int64($6);
outcode($1, $2, &$3, 0, &g);
}
| LTYPE8 cond '[' reglist ']' ',' ioreg
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset = $4;
+ g.Type = obj.TYPE_CONST;
+ g.Offset = int64($4);
outcode($1, $2, &g, 0, &$7);
}
/*
@@ -192,15 +197,15 @@ inst:
*/
| LTYPE9 cond reg ',' ireg ',' reg
{
- outcode($1, $2, &$5, $3.reg, &$7);
+ outcode($1, $2, &$5, int32($3.Reg), &$7);
}
| LTYPE9 cond reg ',' ireg comma
{
- outcode($1, $2, &$5, $3.reg, &$3);
+ outcode($1, $2, &$5, int32($3.Reg), &$3);
}
| LTYPE9 cond comma ireg ',' reg
{
- outcode($1, $2, &$4, $6.reg, &$6);
+ outcode($1, $2, &$4, int32($6.Reg), &$6);
}
/*
* RET
@@ -214,16 +219,16 @@ inst:
*/
| LTYPEB name ',' '$' textsize
{
- settext($2.sym);
+ asm.Settext($2.Sym);
outcode($1, Always, &$2, 0, &$5);
}
| LTYPEB name ',' con ',' '$' textsize
{
- settext($2.sym);
+ asm.Settext($2.Sym);
outcode($1, Always, &$2, 0, &$7);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST;
+ lastpc.From3.Offset = int64($4)
}
}
/*
@@ -231,27 +236,28 @@ inst:
*/
| LGLOBL name ',' imm
{
- settext($2.sym);
- outcode($1, Always, &$2, 0, &$4);
+ asm.Settext($2.Sym)
+ outcode($1, Always, &$2, 0, &$4)
}
| LGLOBL name ',' con ',' imm
{
- settext($2.sym);
- outcode($1, Always, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym)
+ outcode($1, Always, &$2, 0, &$6)
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = int64($4)
}
}
+
/*
* DATA
*/
| LTYPEC name '/' con ',' ximm
{
- outcode($1, Always, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ outcode($1, Always, &$2, 0, &$6)
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = int64($4)
}
}
/*
@@ -285,18 +291,18 @@ inst:
}
| LTYPEL cond freg ',' freg comma
{
- outcode($1, $2, &$3, $5.reg, &nullgen);
+ outcode($1, $2, &$3, int32($5.Reg), &nullgen);
}
/*
* MCR MRC
*/
| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset =
+ g.Type = obj.TYPE_CONST;
+ g.Offset = int64(
(0xe << 24) | /* opcode */
($1 << 20) | /* MCR/MRC */
(($2^C_SCOND_XOR) << 28) | /* scond */
@@ -306,7 +312,7 @@ inst:
(($9 & 15) << 16) | /* Crn */
(($11 & 15) << 0) | /* Crm */
(($12 & 7) << 5) | /* coprocessor information */
- (1<<4); /* must be set */
+ (1<<4)); /* must be set */
outcode(AMRC, Always, &nullgen, 0, &g);
}
/*
@@ -314,17 +320,17 @@ inst:
*/
| LTYPEM cond reg ',' reg ',' regreg
{
- outcode($1, $2, &$3, $5.reg, &$7);
+ outcode($1, $2, &$3, int32($5.Reg), &$7);
}
/*
- * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff -> r4
+ * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4
* MULAW{T,B} r1,r2,r3,r4
*/
| LTYPEN cond reg ',' reg ',' reg ',' spreg
{
- $7.type = TYPE_REGREG2;
- $7.offset = $9;
- outcode($1, $2, &$3, $5.reg, &$7);
+ $7.Type = obj.TYPE_REGREG2;
+ $7.Offset = int64($9);
+ outcode($1, $2, &$3, int32($5.Reg), &$7);
}
/*
* PLD
@@ -338,8 +344,9 @@ inst:
*/
| LTYPEPC gen ',' gen
{
- if($2.type != TYPE_CONST || $4.type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
+ if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST {
+ yyerror("arguments to PCDATA must be integer constants")
+ }
outcode($1, Always, &$2, 0, &$4);
}
/*
@@ -347,10 +354,12 @@ inst:
*/
| LTYPEF gen ',' gen
{
- if($2.type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM)
- yyerror("value for FUNCDATA must be symbol reference");
+ if $2.Type != obj.TYPE_CONST {
+ yyerror("index for FUNCDATA must be integer constant")
+ }
+ if $4.Type != obj.NAME_EXTERN && $4.Type != obj.NAME_STATIC && $4.Type != obj.TYPE_MEM {
+ yyerror("value for FUNCDATA must be symbol reference")
+ }
outcode($1, Always, &$2, 0, &$4);
}
/*
@@ -361,13 +370,43 @@ inst:
outcode($1, Always, &nullgen, 0, &nullgen);
}
+textsize:
+ LCONST
+ {
+ $$ = nullgen;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = int64($1)
+ $$.U.Argsize = obj.ArgsSizeUnknown;
+ }
+| '-' LCONST
+ {
+ $$ = nullgen;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -int64($2)
+ $$.U.Argsize = obj.ArgsSizeUnknown;
+ }
+| LCONST '-' LCONST
+ {
+ $$ = nullgen;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = int64($1)
+ $$.U.Argsize = int32($3);
+ }
+| '-' LCONST '-' LCONST
+ {
+ $$ = nullgen;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -int64($2)
+ $$.U.Argsize = int32($4);
+ }
+
cond:
{
$$ = Always;
}
| cond LCOND
{
- $$ = ($1 & ~C_SCOND) | $2;
+ $$ = ($1 & ^ C_SCOND) | $2;
}
| cond LS
{
@@ -381,65 +420,36 @@ rel:
con '(' LPC ')'
{
$$ = nullgen;
- $$.type = TYPE_BRANCH;
- $$.offset = $1 + pc;
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = int64($1) + int64(asm.PC);
}
| LNAME offset
{
- $1 = labellookup($1);
+ $1 = asm.LabelLookup($1);
$$ = nullgen;
- if(pass == 2 && $1->type != LLAB)
- yyerror("undefined label: %s", $1->labelname);
- $$.type = TYPE_BRANCH;
- $$.offset = $1->value + $2;
- }
-
-textsize:
- LCONST
- {
- $$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = ArgsSizeUnknown;
- }
-| '-' LCONST
- {
- $$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = ArgsSizeUnknown;
- }
-| LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = $3;
- }
-| '-' LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = $4;
+ if asm.Pass == 2 && $1.Type != LLAB {
+ yyerror("undefined label: %s", $1.Labelname)
+ }
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1.Value + int64($2);
}
ximm: '$' con
{
$$ = nullgen;
- $$.type = TYPE_CONST;
- $$.offset = $2;
+ $$.Type = obj.TYPE_CONST;
+ $$.Offset = int64($2);
}
| '$' oreg
{
$$ = $2;
- $$.type = TYPE_ADDR;
+ $$.Type = obj.TYPE_ADDR;
}
| '$' LSCONST
{
$$ = nullgen;
- $$.type = TYPE_SCONST;
- memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ $$.Type = obj.TYPE_SCONST;
+ $$.U.Sval = $2
}
| fcon
@@ -447,45 +457,34 @@ fcon:
'$' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $2;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$3;
}
reglist:
spreg
{
- if($1 < REG_R0 || $1 > REG_R15)
- yyerror("invalid register in reglist");
-
- $$ = 1 << ($1&15);
+ $$ = 1 << uint($1&15);
}
| spreg '-' spreg
{
- int i;
-
- if($1 < REG_R0 || $1 > REG_R15)
- yyerror("invalid register in reglist");
- if($3 < REG_R0 || $3 > REG_R15)
- yyerror("invalid register in reglist");
-
$$=0;
- for(i=$1; i<=$3; i++)
- $$ |= 1<<(i&15);
- for(i=$3; i<=$1; i++)
- $$ |= 1<<(i&15);
+ for i:=$1; i<=$3; i++ {
+ $$ |= 1<<uint(i&15)
+ }
+ for i:=$3; i<=$1; i++ {
+ $$ |= 1<<uint(i&15)
+ }
}
| spreg comma reglist
{
- if($1 < REG_R0 || $1 > REG_R15)
- yyerror("invalid register in reglist");
-
- $$ = (1<<($1&15)) | $3;
+ $$ = (1<<uint($1&15)) | $3;
}
gen:
@@ -495,25 +494,25 @@ gen:
| shift '(' spreg ')'
{
$$ = $1;
- $$.reg = $3;
+ $$.Reg = int16($3);
}
| LPSR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LFCR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| con
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM;
+ $$.Offset = int64($1);
}
| oreg
| freg
@@ -523,7 +522,7 @@ nireg:
| name
{
$$ = $1;
- if($1.name != NAME_EXTERN && $1.name != NAME_STATIC) {
+ if($1.Name != obj.NAME_EXTERN && $1.Name != obj.NAME_STATIC) {
}
}
@@ -531,9 +530,9 @@ ireg:
'(' spreg ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
- $$.offset = 0;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($2);
+ $$.Offset = 0;
}
ioreg:
@@ -541,9 +540,9 @@ ioreg:
| con '(' sreg ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($3);
+ $$.Offset = int64($1);
}
oreg:
@@ -551,8 +550,8 @@ oreg:
| name '(' sreg ')'
{
$$ = $1;
- $$.type = TYPE_MEM;
- $$.reg = $3;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($3);
}
| ioreg
@@ -564,64 +563,66 @@ imsr:
imm: '$' con
{
$$ = nullgen;
- $$.type = TYPE_CONST;
- $$.offset = $2;
+ $$.Type = obj.TYPE_CONST;
+ $$.Offset = int64($2);
}
reg:
spreg
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
regreg:
'(' spreg ',' spreg ')'
{
$$ = nullgen;
- $$.type = TYPE_REGREG;
- $$.reg = $2;
- $$.offset = $4;
+ $$.Type = obj.TYPE_REGREG;
+ $$.Reg = int16($2);
+ $$.Offset = int64($4);
}
shift:
spreg '<' '<' rcon
{
$$ = nullgen;
- $$.type = TYPE_SHIFT;
- $$.offset = $1&15 | $4 | (0 << 5);
+ $$.Type = obj.TYPE_SHIFT;
+ $$.Offset = int64($1&15) | int64($4) | (0 << 5);
}
| spreg '>' '>' rcon
{
$$ = nullgen;
- $$.type = TYPE_SHIFT;
- $$.offset = $1&15 | $4 | (1 << 5);
+ $$.Type = obj.TYPE_SHIFT;
+ $$.Offset = int64($1&15) | int64($4) | (1 << 5);
}
| spreg '-' '>' rcon
{
$$ = nullgen;
- $$.type = TYPE_SHIFT;
- $$.offset = $1&15 | $4 | (2 << 5);
+ $$.Type = obj.TYPE_SHIFT;
+ $$.Offset = int64($1&15) | int64($4) | (2 << 5);
}
| spreg LAT '>' rcon
{
$$ = nullgen;
- $$.type = TYPE_SHIFT;
- $$.offset = $1&15 | $4 | (3 << 5);
+ $$.Type = obj.TYPE_SHIFT;
+ $$.Offset = int64($1&15) | int64($4) | (3 << 5);
}
rcon:
spreg
{
- if($$ < REG_R0 || $$ > REG_R15)
- print("register value out of range in shift\n");
+ if $$ < REG_R0 || $$ > REG_R15 {
+ print("register value out of range\n")
+ }
$$ = (($1&15) << 8) | (1 << 4);
}
| con
{
- if($$ < 0 || $$ >= 32)
- print("shift value out of range\n");
+ if $$ < 0 || $$ >= 32 {
+ print("shift value out of range\n")
+ }
$$ = ($1&31) << 7;
}
@@ -633,8 +634,9 @@ sreg:
}
| LR '(' expr ')'
{
- if($3 < 0 || $3 >= NREG)
- print("register value out of range in R(...)\n");
+ if $3 < 0 || $3 >= NREG {
+ print("register value out of range\n")
+ }
$$ = REG_R0 + $3;
}
@@ -649,8 +651,9 @@ creg:
LCREG
| LC '(' expr ')'
{
- if($3 < 0 || $3 >= NREG)
- print("register value out of range in C(...)\n");
+ if $3 < 0 || $3 >= NREG {
+ print("register value out of range\n")
+ }
$$ = $3; // TODO(rsc): REG_C0+$3
}
@@ -662,40 +665,40 @@ freg:
LFREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
| LF '(' con ')'
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = REG_F0 + $3;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16(REG_F0 + $3);
}
name:
con '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $3;
- $$.sym = nil;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = int8($3);
+ $$.Sym = nil;
+ $$.Offset = int64($1);
}
| LNAME offset '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $4;
- $$.sym = linklookup(ctxt, $1->name, 0);
- $$.offset = $2;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = int8($4);
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
+ $$.Offset = int64($2);
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = NAME_STATIC;
- $$.sym = linklookup(ctxt, $1->name, 1);
- $$.offset = $4;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = obj.NAME_STATIC;
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
+ $$.Offset = int64($4);
}
offset:
@@ -720,7 +723,7 @@ con:
LCONST
| LVAR
{
- $$ = $1->value;
+ $$ = int32($1.Value);
}
| '-' con
{
@@ -732,7 +735,7 @@ con:
}
| '~' con
{
- $$ = ~$2;
+ $$ = ^$2;
}
| '(' expr ')'
{
@@ -772,11 +775,11 @@ expr:
}
| expr '<' '<' expr
{
- $$ = $1 << $4;
+ $$ = $1 << uint($4);
}
| expr '>' '>' expr
{
- $$ = $1 >> $4;
+ $$ = $1 >> uint($4);
}
| expr '&' expr
{
diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go
deleted file mode 100644
index 3e9e78fe6d..0000000000
--- a/src/cmd/5a/doc.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-5a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
- http://golang.org/doc/asm
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package main
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
deleted file mode 100644
index 6f56922a4e..0000000000
--- a/src/cmd/5a/lex.c
+++ /dev/null
@@ -1,538 +0,0 @@
-// Inferno utils/5a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.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.
-
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
- return sys&Windows;
-#else
- return sys&Plan9;
-#endif
-}
-
-int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
- if(nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
-}
-
-void
-usage(void)
-{
- print("usage: %ca [options] file.c...\n", thechar);
- flagprint(1);
- errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
-
- thechar = '5';
- thestring = "arm";
-
- ctxt = linknew(&linkarm);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- ctxt->enforce_data_order = 1;
- Binit(&bstdout, 1, OWRITE);
- listinit5();
- fmtinstall('L', Lconv);
-
- // Allow GOARCH=thestring or GOARCH=thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
-
- flagfn1("D", "name[=value]: add #define", dodef);
- flagfn1("I", "dir: add dir to include path", setinclude);
- flagcount("S", "print assembly and machine code", &debug['S']);
- flagcount("m", "debug preprocessor macros", &debug['m']);
- flagstr("o", "file: set output file", &outfile);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
-
- if(argc < 1)
- usage();
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
-
- if(assemble(argv[0]))
- errorexit();
- Bflush(&bstdout);
- if(nerrors > 0)
- errorexit();
- exits(0);
-}
-
-int
-assemble(char *file)
-{
- char *ofile, *p;
- int i, of;
-
- ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
- strcpy(ofile, file);
- p = utfrrune(ofile, '/');
- if(p) {
- include[0] = ofile;
- *p++ = 0;
- } else
- p = ofile;
- if(outfile == 0) {
- outfile = p;
- if(outfile){
- p = utfrrune(outfile, '.');
- if(p)
- if(p[1] == 's' && p[2] == 0)
- p[0] = 0;
- p = utfrune(outfile, 0);
- p[0] = '.';
- p[1] = thechar;
- p[2] = 0;
- } else
- outfile = "/dev/null";
- }
-
- of = create(outfile, OWRITE, 0664);
- if(of < 0) {
- yyerror("%ca: cannot create %s", thechar, outfile);
- errorexit();
- }
- Binit(&obuf, of, OWRITE);
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- Bprint(&obuf, "!\n");
-
- for(pass = 1; pass <= 2; pass++) {
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- if(nerrors)
- return nerrors;
- }
-
- writeobj(ctxt, &obuf);
- Bflush(&obuf);
- return 0;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, NAME_AUTO,
- "SB", LSB, NAME_EXTERN,
- "FP", LFP, NAME_PARAM,
- "PC", LPC, TYPE_BRANCH,
-
- "R", LR, REG_F0,
-
- "R0", LREG, REG_R0,
- "R1", LREG, REG_R1,
- "R2", LREG, REG_R2,
- "R3", LREG, REG_R3,
- "R4", LREG, REG_R4,
- "R5", LREG, REG_R5,
- "R6", LREG, REG_R6,
- "R7", LREG, REG_R7,
- "R8", LREG, REG_R8,
- "R9", LREG, REG_R9,
- "g", LREG, REG_R10, // avoid unintentionally clobber g using R10
- "R11", LREG, REG_R11,
- "R12", LREG, REG_R12,
- "R13", LREG, REG_R13,
- "R14", LREG, REG_R14,
- "R15", LREG, REG_R15,
-
- "F", LF, REG_F0,
-
- "F0", LFREG, REG_F0,
- "F1", LFREG, REG_F1,
- "F2", LFREG, REG_F2,
- "F3", LFREG, REG_F3,
- "F4", LFREG, REG_F4,
- "F5", LFREG, REG_F5,
- "F6", LFREG, REG_F6,
- "F7", LFREG, REG_F7,
- "F8", LFREG, REG_F8,
- "F9", LFREG, REG_F9,
- "F10", LFREG, REG_F10,
- "F11", LFREG, REG_F11,
- "F12", LFREG, REG_F12,
- "F13", LFREG, REG_F13,
- "F14", LFREG, REG_F14,
- "F15", LFREG, REG_F15,
-
- "C", LC, 0,
-
- "C0", LCREG, 0,
- "C1", LCREG, 1,
- "C2", LCREG, 2,
- "C3", LCREG, 3,
- "C4", LCREG, 4,
- "C5", LCREG, 5,
- "C6", LCREG, 6,
- "C7", LCREG, 7,
- "C8", LCREG, 8,
- "C9", LCREG, 9,
- "C10", LCREG, 10,
- "C11", LCREG, 11,
- "C12", LCREG, 12,
- "C13", LCREG, 13,
- "C14", LCREG, 14,
- "C15", LCREG, 15,
-
- "CPSR", LPSR, REG_CPSR,
- "SPSR", LPSR, REG_SPSR,
-
- "FPSR", LFCR, REG_FPSR,
- "FPCR", LFCR, REG_FPCR,
-
- ".EQ", LCOND, C_SCOND_EQ,
- ".NE", LCOND, C_SCOND_NE,
- ".CS", LCOND, C_SCOND_HS,
- ".HS", LCOND, C_SCOND_HS,
- ".CC", LCOND, C_SCOND_LO,
- ".LO", LCOND, C_SCOND_LO,
- ".MI", LCOND, C_SCOND_MI,
- ".PL", LCOND, C_SCOND_PL,
- ".VS", LCOND, C_SCOND_VS,
- ".VC", LCOND, C_SCOND_VC,
- ".HI", LCOND, C_SCOND_HI,
- ".LS", LCOND, C_SCOND_LS,
- ".GE", LCOND, C_SCOND_GE,
- ".LT", LCOND, C_SCOND_LT,
- ".GT", LCOND, C_SCOND_GT,
- ".LE", LCOND, C_SCOND_LE,
- ".AL", LCOND, C_SCOND_NONE,
-
- ".U", LS, C_UBIT,
- ".S", LS, C_SBIT,
- ".W", LS, C_WBIT,
- ".P", LS, C_PBIT,
- ".PW", LS, C_WBIT|C_PBIT,
- ".WP", LS, C_WBIT|C_PBIT,
-
- ".F", LS, C_FBIT,
-
- ".IBW", LS, C_WBIT|C_PBIT|C_UBIT,
- ".IAW", LS, C_WBIT|C_UBIT,
- ".DBW", LS, C_WBIT|C_PBIT,
- ".DAW", LS, C_WBIT,
- ".IB", LS, C_PBIT|C_UBIT,
- ".IA", LS, C_UBIT,
- ".DB", LS, C_PBIT,
- ".DA", LS, 0,
-
- "@", LAT, 0,
-
- "AND", LTYPE1, AAND,
- "EOR", LTYPE1, AEOR,
- "SUB", LTYPE1, ASUB,
- "RSB", LTYPE1, ARSB,
- "ADD", LTYPE1, AADD,
- "ADC", LTYPE1, AADC,
- "SBC", LTYPE1, ASBC,
- "RSC", LTYPE1, ARSC,
- "ORR", LTYPE1, AORR,
- "BIC", LTYPE1, ABIC,
-
- "SLL", LTYPE1, ASLL,
- "SRL", LTYPE1, ASRL,
- "SRA", LTYPE1, ASRA,
-
- "MUL", LTYPE1, AMUL,
- "MULA", LTYPEN, AMULA,
- "DIV", LTYPE1, ADIV,
- "MOD", LTYPE1, AMOD,
-
- "MULL", LTYPEM, AMULL,
- "MULAL", LTYPEM, AMULAL,
- "MULLU", LTYPEM, AMULLU,
- "MULALU", LTYPEM, AMULALU,
-
- "MVN", LTYPE2, AMVN, /* op2 ignored */
-
- "MOVB", LTYPE3, AMOVB,
- "MOVBU", LTYPE3, AMOVBU,
- "MOVH", LTYPE3, AMOVH,
- "MOVHU", LTYPE3, AMOVHU,
- "MOVW", LTYPE3, AMOVW,
-
- "MOVD", LTYPE3, AMOVD,
- "MOVDF", LTYPE3, AMOVDF,
- "MOVDW", LTYPE3, AMOVDW,
- "MOVF", LTYPE3, AMOVF,
- "MOVFD", LTYPE3, AMOVFD,
- "MOVFW", LTYPE3, AMOVFW,
- "MOVWD", LTYPE3, AMOVWD,
- "MOVWF", LTYPE3, AMOVWF,
-
- "LDREX", LTYPE3, ALDREX,
- "LDREXD", LTYPE3, ALDREXD,
- "STREX", LTYPE9, ASTREX,
- "STREXD", LTYPE9, ASTREXD,
-
-/*
- "NEGF", LTYPEI, ANEGF,
- "NEGD", LTYPEI, ANEGD,
- "SQTF", LTYPEI, ASQTF,
- "SQTD", LTYPEI, ASQTD,
- "RNDF", LTYPEI, ARNDF,
- "RNDD", LTYPEI, ARNDD,
- "URDF", LTYPEI, AURDF,
- "URDD", LTYPEI, AURDD,
- "NRMF", LTYPEI, ANRMF,
- "NRMD", LTYPEI, ANRMD,
-*/
-
- "ABSF", LTYPEI, AABSF,
- "ABSD", LTYPEI, AABSD,
- "SQRTF", LTYPEI, ASQRTF,
- "SQRTD", LTYPEI, ASQRTD,
- "CMPF", LTYPEL, ACMPF,
- "CMPD", LTYPEL, ACMPD,
- "ADDF", LTYPEK, AADDF,
- "ADDD", LTYPEK, AADDD,
- "SUBF", LTYPEK, ASUBF,
- "SUBD", LTYPEK, ASUBD,
- "MULF", LTYPEK, AMULF,
- "MULD", LTYPEK, AMULD,
- "DIVF", LTYPEK, ADIVF,
- "DIVD", LTYPEK, ADIVD,
-
- "B", LTYPE4, AB,
- "BL", LTYPE4, ABL,
- "BX", LTYPEBX, ABX,
-
- "BEQ", LTYPE5, ABEQ,
- "BNE", LTYPE5, ABNE,
- "BCS", LTYPE5, ABCS,
- "BHS", LTYPE5, ABHS,
- "BCC", LTYPE5, ABCC,
- "BLO", LTYPE5, ABLO,
- "BMI", LTYPE5, ABMI,
- "BPL", LTYPE5, ABPL,
- "BVS", LTYPE5, ABVS,
- "BVC", LTYPE5, ABVC,
- "BHI", LTYPE5, ABHI,
- "BLS", LTYPE5, ABLS,
- "BGE", LTYPE5, ABGE,
- "BLT", LTYPE5, ABLT,
- "BGT", LTYPE5, ABGT,
- "BLE", LTYPE5, ABLE,
- "BCASE", LTYPE5, ABCASE,
-
- "SWI", LTYPE6, ASWI,
-
- "CMP", LTYPE7, ACMP,
- "TST", LTYPE7, ATST,
- "TEQ", LTYPE7, ATEQ,
- "CMN", LTYPE7, ACMN,
-
- "MOVM", LTYPE8, AMOVM,
-
- "SWPBU", LTYPE9, ASWPBU,
- "SWPW", LTYPE9, ASWPW,
-
- "RET", LTYPEA, ARET,
- "RFE", LTYPEA, ARFE,
-
- "TEXT", LTYPEB, ATEXT,
- "GLOBL", LGLOBL, AGLOBL,
- "DATA", LTYPEC, ADATA,
- "CASE", LTYPED, ACASE,
- "END", LTYPEE, AEND,
- "WORD", LTYPEH, AWORD,
- "NOP", LTYPEI, ANOP,
-
- "MCR", LTYPEJ, 0,
- "MRC", LTYPEJ, 1,
-
- "PLD", LTYPEPLD, APLD,
- "UNDEF", LTYPEE, AUNDEF,
- "CLZ", LTYPE2, ACLZ,
-
- "MULWT", LTYPE1, AMULWT,
- "MULWB", LTYPE1, AMULWB,
- "MULAWT", LTYPEN, AMULAWT,
- "MULAWB", LTYPEN, AMULAWB,
-
- "USEFIELD", LTYPEN, AUSEFIELD,
- "PCDATA", LTYPEPC, APCDATA,
- "FUNCDATA", LTYPEF, AFUNCDATA,
-
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.type = TYPE_NONE;
- nullgen.name = NAME_NONE;
-
- nerrors = 0;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-int
-isreg(Addr *g)
-{
-
- USED(g);
- return 1;
-}
-
-void
-cclean(void)
-{
- outcode(AEND, Always, &nullgen, 0, &nullgen);
-}
-
-static int bcode[] =
-{
- ABEQ,
- ABNE,
- ABCS,
- ABCC,
- ABMI,
- ABPL,
- ABVS,
- ABVC,
- ABHI,
- ABLS,
- ABGE,
- ABLT,
- ABGT,
- ABLE,
- AB,
- ANOP,
-};
-
-void
-outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
-{
- Prog *p;
- Plist *pl;
-
- /* hack to make B.NE etc. work: turn it into the corresponding conditional */
- if(a == AB){
- a = bcode[(scond^C_SCOND_XOR)&0xf];
- scond = (scond & ~0xf) | C_SCOND_NONE;
- }
-
- if(pass == 1)
- goto out;
-
- p = malloc(sizeof *p);
- memset(p, 0, sizeof *p);
- p->as = a;
- p->lineno = stmtline;
- p->scond = scond;
- p->from = *g1;
- p->reg = reg;
- p->to = *g2;
- p->pc = pc;
-
- if(lastpc == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastpc->link = p;
- lastpc = p;
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/new5a/lex.go b/src/cmd/5a/lex.go
index 1afd827793..1afd827793 100644
--- a/src/cmd/new5a/lex.go
+++ b/src/cmd/5a/lex.go
diff --git a/src/cmd/new5a/y.go b/src/cmd/5a/y.go
index 17ee80ee51..17ee80ee51 100644
--- a/src/cmd/new5a/y.go
+++ b/src/cmd/5a/y.go
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
deleted file mode 100644
index 416af9a321..0000000000
--- a/src/cmd/5a/y.tab.c
+++ /dev/null
@@ -1,2855 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE1 = 258,
- LTYPE2 = 259,
- LTYPE3 = 260,
- LTYPE4 = 261,
- LTYPE5 = 262,
- LTYPE6 = 263,
- LTYPE7 = 264,
- LTYPE8 = 265,
- LTYPE9 = 266,
- LTYPEA = 267,
- LTYPEB = 268,
- LGLOBL = 269,
- LTYPEC = 270,
- LTYPED = 271,
- LTYPEE = 272,
- LTYPEG = 273,
- LTYPEH = 274,
- LTYPEI = 275,
- LTYPEJ = 276,
- LTYPEK = 277,
- LTYPEL = 278,
- LTYPEM = 279,
- LTYPEN = 280,
- LTYPEBX = 281,
- LTYPEPLD = 282,
- LCONST = 283,
- LSP = 284,
- LSB = 285,
- LFP = 286,
- LPC = 287,
- LTYPEX = 288,
- LTYPEPC = 289,
- LTYPEF = 290,
- LR = 291,
- LREG = 292,
- LF = 293,
- LFREG = 294,
- LC = 295,
- LCREG = 296,
- LPSR = 297,
- LFCR = 298,
- LCOND = 299,
- LS = 300,
- LAT = 301,
- LFCONST = 302,
- LSCONST = 303,
- LNAME = 304,
- LLAB = 305,
- LVAR = 306
- };
-#endif
-/* Tokens. */
-#define LTYPE1 258
-#define LTYPE2 259
-#define LTYPE3 260
-#define LTYPE4 261
-#define LTYPE5 262
-#define LTYPE6 263
-#define LTYPE7 264
-#define LTYPE8 265
-#define LTYPE9 266
-#define LTYPEA 267
-#define LTYPEB 268
-#define LGLOBL 269
-#define LTYPEC 270
-#define LTYPED 271
-#define LTYPEE 272
-#define LTYPEG 273
-#define LTYPEH 274
-#define LTYPEI 275
-#define LTYPEJ 276
-#define LTYPEK 277
-#define LTYPEL 278
-#define LTYPEM 279
-#define LTYPEN 280
-#define LTYPEBX 281
-#define LTYPEPLD 282
-#define LCONST 283
-#define LSP 284
-#define LSB 285
-#define LFP 286
-#define LPC 287
-#define LTYPEX 288
-#define LTYPEPC 289
-#define LTYPEF 290
-#define LR 291
-#define LREG 292
-#define LF 293
-#define LFREG 294
-#define LC 295
-#define LCREG 296
-#define LPSR 297
-#define LFCR 298
-#define LCOND 299
-#define LS 300
-#define LAT 301
-#define LFCONST 302
-#define LSCONST 303
-#define LNAME 304
-#define LLAB 305
-#define LVAR 306
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 39 "a.y"
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
-}
-/* Line 193 of yacc.c. */
-#line 214 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 227 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 655
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 72
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 35
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 134
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 344
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 306
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 68, 12, 5, 2,
- 69, 70, 10, 8, 65, 9, 2, 11, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 62, 64,
- 6, 63, 7, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 66, 2, 67, 4, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 2, 71, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 5, 9, 10, 15, 20, 25,
- 27, 30, 33, 41, 48, 54, 60, 66, 71, 76,
- 80, 84, 89, 96, 104, 112, 120, 127, 134, 138,
- 144, 152, 157, 164, 171, 176, 180, 186, 192, 200,
- 207, 220, 228, 238, 241, 246, 251, 254, 255, 258,
- 261, 262, 265, 270, 273, 275, 278, 282, 287, 290,
- 293, 296, 298, 301, 305, 307, 311, 315, 317, 319,
- 321, 326, 328, 330, 332, 334, 336, 338, 340, 344,
- 346, 351, 353, 358, 360, 362, 364, 366, 369, 371,
- 377, 382, 387, 392, 397, 399, 401, 403, 405, 410,
- 412, 414, 416, 421, 423, 425, 427, 432, 437, 443,
- 451, 452, 455, 458, 460, 462, 464, 466, 468, 471,
- 474, 477, 481, 482, 485, 487, 491, 495, 499, 503,
- 507, 512, 517, 521, 525
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 73, 0, -1, -1, -1, 73, 74, 75, -1, -1,
- 59, 62, 76, 75, -1, 59, 63, 106, 64, -1,
- 61, 63, 106, 64, -1, 64, -1, 77, 64, -1,
- 1, 64, -1, 13, 78, 90, 65, 97, 65, 92,
- -1, 13, 78, 90, 65, 97, 65, -1, 13, 78,
- 90, 65, 92, -1, 14, 78, 90, 65, 92, -1,
- 15, 78, 85, 65, 85, -1, 16, 78, 79, 80,
- -1, 16, 78, 79, 86, -1, 36, 79, 87, -1,
- 17, 79, 80, -1, 18, 78, 79, 85, -1, 19,
- 78, 90, 65, 97, 79, -1, 20, 78, 88, 65,
- 66, 84, 67, -1, 20, 78, 66, 84, 67, 65,
- 88, -1, 21, 78, 92, 65, 87, 65, 92, -1,
- 21, 78, 92, 65, 87, 79, -1, 21, 78, 79,
- 87, 65, 92, -1, 22, 78, 79, -1, 23, 101,
- 65, 68, 81, -1, 23, 101, 65, 104, 65, 68,
- 81, -1, 24, 101, 65, 91, -1, 24, 101, 65,
- 104, 65, 91, -1, 25, 101, 11, 104, 65, 82,
- -1, 26, 78, 92, 79, -1, 29, 79, 82, -1,
- 30, 78, 100, 65, 100, -1, 32, 78, 99, 65,
- 100, -1, 32, 78, 99, 65, 49, 65, 100, -1,
- 33, 78, 100, 65, 100, 79, -1, 31, 78, 104,
- 65, 106, 65, 97, 65, 98, 65, 98, 105, -1,
- 34, 78, 92, 65, 92, 65, 93, -1, 35, 78,
- 92, 65, 92, 65, 92, 65, 97, -1, 37, 89,
- -1, 44, 85, 65, 85, -1, 45, 85, 65, 85,
- -1, 27, 79, -1, -1, 78, 54, -1, 78, 55,
- -1, -1, 65, 79, -1, 104, 69, 42, 70, -1,
- 59, 102, -1, 38, -1, 9, 38, -1, 38, 9,
- 38, -1, 9, 38, 9, 38, -1, 68, 104, -1,
- 68, 89, -1, 68, 58, -1, 83, -1, 68, 57,
- -1, 68, 9, 57, -1, 97, -1, 97, 9, 97,
- -1, 97, 79, 84, -1, 92, -1, 82, -1, 94,
- -1, 94, 69, 97, 70, -1, 52, -1, 53, -1,
- 104, -1, 89, -1, 100, -1, 87, -1, 101, -1,
- 69, 97, 70, -1, 87, -1, 104, 69, 96, 70,
- -1, 101, -1, 101, 69, 96, 70, -1, 88, -1,
- 92, -1, 91, -1, 94, -1, 68, 104, -1, 97,
- -1, 69, 97, 65, 97, 70, -1, 97, 6, 6,
- 95, -1, 97, 7, 7, 95, -1, 97, 9, 7,
- 95, -1, 97, 56, 7, 95, -1, 97, -1, 104,
- -1, 47, -1, 42, -1, 46, 69, 106, 70, -1,
- 96, -1, 39, -1, 51, -1, 50, 69, 106, 70,
- -1, 100, -1, 83, -1, 49, -1, 48, 69, 104,
- 70, -1, 104, 69, 103, 70, -1, 59, 102, 69,
- 103, 70, -1, 59, 6, 7, 102, 69, 40, 70,
- -1, -1, 8, 104, -1, 9, 104, -1, 40, -1,
- 39, -1, 41, -1, 38, -1, 61, -1, 9, 104,
- -1, 8, 104, -1, 71, 104, -1, 69, 106, 70,
- -1, -1, 65, 106, -1, 104, -1, 106, 8, 106,
- -1, 106, 9, 106, -1, 106, 10, 106, -1, 106,
- 11, 106, -1, 106, 12, 106, -1, 106, 6, 6,
- 106, -1, 106, 7, 7, 106, -1, 106, 5, 106,
- -1, 106, 4, 106, -1, 106, 3, 106, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 68, 68, 70, 69, 77, 76, 85, 90, 96,
- 97, 98, 104, 108, 112, 119, 126, 133, 137, 144,
- 151, 158, 165, 172, 181, 193, 197, 201, 208, 215,
- 220, 232, 237, 249, 260, 267, 274, 278, 282, 286,
- 293, 315, 323, 332, 339, 348, 359, 365, 368, 372,
- 377, 378, 381, 387, 398, 405, 412, 419, 427, 433,
- 438, 444, 447, 453, 461, 468, 483, 492, 493, 494,
- 495, 500, 506, 512, 518, 519, 522, 523, 531, 540,
- 541, 550, 551, 557, 560, 561, 562, 564, 572, 580,
- 589, 595, 601, 607, 615, 621, 629, 630, 634, 642,
- 643, 649, 650, 658, 659, 662, 668, 676, 684, 692,
- 702, 705, 709, 715, 716, 717, 720, 721, 725, 729,
- 733, 737, 743, 746, 752, 753, 757, 761, 765, 769,
- 773, 777, 781, 785, 789
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
- "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4",
- "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB",
- "LGLOBL", "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI",
- "LTYPEJ", "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD",
- "LCONST", "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF",
- "LR", "LREG", "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND",
- "LS", "LAT", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='",
- "';'", "','", "'['", "']'", "'$'", "'('", "')'", "'~'", "$accept",
- "prog", "@1", "line", "@2", "inst", "cond", "comma", "rel", "textsize",
- "ximm", "fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg",
- "imsr", "imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg",
- "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
- 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 58, 61, 59, 44, 91, 93, 36, 40,
- 41, 126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 72, 73, 74, 73, 76, 75, 75, 75, 75,
- 75, 75, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 78, 78, 78,
- 79, 79, 80, 80, 81, 81, 81, 81, 82, 82,
- 82, 82, 83, 83, 84, 84, 84, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 86, 86, 87, 88,
- 88, 89, 89, 89, 90, 90, 90, 91, 92, 93,
- 94, 94, 94, 94, 95, 95, 96, 96, 96, 97,
- 97, 98, 98, 99, 99, 100, 100, 101, 101, 101,
- 102, 102, 102, 103, 103, 103, 104, 104, 104, 104,
- 104, 104, 105, 105, 106, 106, 106, 106, 106, 106,
- 106, 106, 106, 106, 106
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 0, 3, 0, 4, 4, 4, 1,
- 2, 2, 7, 6, 5, 5, 5, 4, 4, 3,
- 3, 4, 6, 7, 7, 7, 6, 6, 3, 5,
- 7, 4, 6, 6, 4, 3, 5, 5, 7, 6,
- 12, 7, 9, 2, 4, 4, 2, 0, 2, 2,
- 0, 2, 4, 2, 1, 2, 3, 4, 2, 2,
- 2, 1, 2, 3, 1, 3, 3, 1, 1, 1,
- 4, 1, 1, 1, 1, 1, 1, 1, 3, 1,
- 4, 1, 4, 1, 1, 1, 1, 2, 1, 5,
- 4, 4, 4, 4, 1, 1, 1, 1, 4, 1,
- 1, 1, 4, 1, 1, 1, 4, 4, 5, 7,
- 0, 2, 2, 1, 1, 1, 1, 1, 2, 2,
- 2, 3, 0, 2, 1, 3, 3, 3, 3, 3,
- 4, 4, 3, 3, 3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 3, 1, 0, 0, 47, 47, 47, 47, 50,
- 47, 47, 47, 47, 47, 0, 0, 0, 47, 50,
- 50, 47, 47, 47, 47, 47, 47, 50, 0, 0,
- 0, 0, 0, 9, 4, 0, 11, 0, 0, 0,
- 50, 50, 0, 50, 0, 0, 50, 50, 0, 0,
- 116, 110, 117, 0, 0, 0, 0, 0, 0, 0,
- 46, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 79, 83, 43, 81, 0, 100, 97, 0, 96, 0,
- 105, 71, 72, 0, 68, 61, 0, 74, 67, 69,
- 99, 88, 75, 73, 0, 5, 0, 0, 10, 48,
- 49, 0, 0, 85, 84, 86, 0, 0, 0, 51,
- 110, 20, 0, 0, 0, 0, 0, 0, 0, 0,
- 88, 28, 119, 118, 0, 0, 0, 0, 124, 0,
- 120, 0, 0, 0, 0, 50, 35, 0, 0, 0,
- 104, 0, 103, 0, 0, 0, 0, 19, 0, 0,
- 0, 0, 0, 0, 62, 60, 59, 58, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 87, 0,
- 0, 0, 110, 17, 18, 76, 77, 0, 53, 0,
- 21, 0, 0, 50, 0, 0, 0, 0, 110, 111,
- 112, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 121, 0, 0, 114, 113, 115, 0, 31,
- 0, 0, 34, 0, 0, 0, 0, 0, 0, 0,
- 78, 0, 0, 0, 0, 63, 44, 0, 0, 0,
- 0, 0, 45, 6, 7, 8, 14, 88, 15, 16,
- 53, 0, 0, 50, 0, 0, 0, 0, 0, 50,
- 0, 0, 134, 133, 132, 0, 0, 125, 126, 127,
- 128, 129, 0, 54, 29, 0, 107, 0, 0, 36,
- 0, 105, 37, 50, 0, 0, 82, 80, 98, 106,
- 70, 90, 94, 95, 91, 92, 93, 13, 52, 22,
- 0, 65, 66, 0, 27, 50, 26, 0, 108, 130,
- 131, 55, 0, 0, 32, 33, 0, 0, 39, 0,
- 0, 12, 24, 23, 25, 0, 0, 56, 30, 0,
- 38, 0, 41, 0, 109, 57, 0, 0, 0, 0,
- 101, 0, 0, 42, 0, 0, 0, 0, 122, 89,
- 102, 0, 40, 123
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 3, 34, 165, 35, 37, 109, 111, 264,
- 84, 85, 182, 86, 174, 70, 71, 87, 102, 103,
- 88, 322, 89, 281, 90, 120, 331, 141, 92, 73,
- 127, 208, 128, 342, 129
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -130
-static const yytype_int16 yypact[] =
-{
- -130, 12, -130, 305, -35, -130, -130, -130, -130, -33,
- -130, -130, -130, -130, -130, 427, 427, 427, -130, -33,
- -33, -130, -130, -130, -130, -130, -130, -33, 445, 370,
- 370, 10, -24, -130, -130, -30, -130, 140, 140, 335,
- -13, -33, 449, -13, 140, 70, 484, -13, 359, 359,
- -130, 114, -130, 359, 359, 27, -11, 62, 76, 167,
- -130, 7, 171, 424, 64, 171, 167, 167, 65, 405,
- -130, -130, -130, 68, 74, -130, -130, 78, -130, 86,
- -130, -130, -130, 402, -130, -130, 96, -130, -130, 107,
- -130, 21, -130, 74, 118, -130, 359, 359, -130, -130,
- -130, 359, 131, -130, -130, -130, 150, 158, 473, -130,
- 98, -130, 155, 370, 187, 43, 192, 199, 65, 205,
- -130, -130, -130, -130, 262, 359, 359, 203, -130, 90,
- -130, 106, 164, 233, 359, -33, -130, 211, 223, -3,
- -130, 226, -130, 231, 235, 240, 43, -130, 220, 122,
- 608, 359, 359, 491, -130, -130, -130, 74, 370, 43,
- 287, 291, 300, 301, 370, 305, 560, 582, -130, 43,
- 43, 370, 114, -130, -130, -130, -130, 264, -130, 267,
- -130, 43, 279, -4, 281, 122, 283, 65, 98, -130,
- -130, 164, 359, 359, 359, 345, 356, 359, 359, 359,
- 359, 359, -130, 15, 306, -130, -130, -130, 282, -130,
- 307, 310, -130, 32, 359, 308, 132, 32, 43, 43,
- -130, 315, 316, 225, 321, -130, -130, 322, 405, 405,
- 405, 405, -130, -130, -130, -130, -130, 311, -130, -130,
- 203, 204, 323, -33, 333, 43, 43, 43, 43, 334,
- 331, 337, 631, 611, 547, 359, 359, 228, 228, -130,
- -130, -130, 332, 371, -130, 353, -130, 357, 7, -130,
- 350, 336, -130, -33, 340, 361, -130, -130, -130, -130,
- -130, -130, -130, -130, -130, -130, -130, 43, -130, -130,
- 513, -130, -130, 360, -130, 146, -130, 384, -130, 303,
- 303, 425, 399, 15, -130, -130, 43, 32, -130, 373,
- 43, -130, -130, -130, -130, 375, 408, -130, -130, 383,
- -130, 43, -130, 385, -130, -130, 120, 390, 43, 380,
- -130, 391, 43, -130, 359, 120, 394, 275, 403, -130,
- -130, 359, -130, 622
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -130, -130, -130, 302, -130, -130, 589, 24, 362, 166,
- -58, 411, -57, -8, -130, -61, -43, -7, 22, -129,
- -21, -130, 72, 34, -94, -29, 137, -130, -51, 3,
- -84, 286, 20, -130, 61
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -65
-static const yytype_int16 yytable[] =
-{
- 91, 91, 116, 136, 209, 245, 215, 147, 91, 91,
- 91, 137, 2, 142, 143, 91, 104, 104, 55, 57,
- 58, 72, 94, 104, 262, 119, 178, 160, 161, 36,
- 162, 107, 41, 42, 98, 56, 56, 56, 135, 97,
- 148, 99, 100, 60, 61, 144, 145, 175, 74, 93,
- 93, 68, 41, 263, 154, 221, 222, 186, 132, 93,
- 106, 41, 112, -64, 108, 117, 114, 113, 122, 123,
- 118, 121, 95, 96, 130, 83, 156, 163, 48, 49,
- 79, 80, 75, 138, 91, 76, 183, 134, 240, 77,
- 78, 222, 131, 192, 193, 194, 195, 196, 197, 198,
- 199, 200, 201, 157, 250, 180, 125, 126, 50, 105,
- 105, 176, 79, 80, 48, 49, 105, 148, 99, 100,
- 124, 168, 125, 126, 99, 100, 249, 133, 177, 91,
- 227, 52, 139, 93, 146, 91, 115, 149, 304, 69,
- 237, 54, 91, 150, 50, 189, 190, 151, 236, 238,
- 226, 204, 243, 210, 211, 152, 232, 166, 167, 212,
- 202, 158, 269, 239, 76, 272, 273, 52, 77, 78,
- 329, 330, 224, 123, 203, 53, 159, 54, 93, 75,
- 79, 271, 76, 164, 93, 75, 77, 78, 76, 292,
- 293, 93, 77, 78, 99, 100, 169, 274, 275, 282,
- 282, 282, 282, 205, 206, 207, 75, 246, 101, 76,
- 305, 41, 223, 77, 78, 170, 291, 183, 183, 79,
- 80, 99, 100, 171, 179, 99, 100, 294, 192, 193,
- 194, 195, 196, 197, 198, 199, 200, 201, 199, 200,
- 201, 48, 49, 205, 206, 207, 242, 312, 283, 283,
- 283, 283, 181, 252, 253, 254, 320, 184, 257, 258,
- 259, 260, 261, 284, 285, 286, 311, 289, 185, 188,
- 187, 50, 191, 296, 314, 270, 213, 319, 192, 193,
- 194, 195, 196, 197, 198, 199, 200, 201, 214, 323,
- 220, 216, 327, 228, 52, 278, 217, 308, 229, 333,
- 218, 101, 53, 336, 54, 219, 4, 230, 231, 242,
- 117, 197, 198, 199, 200, 201, 299, 300, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 241, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 48, 49, 340, 244, 247, 248, 29,
- 30, 255, 266, 192, 193, 194, 195, 196, 197, 198,
- 199, 200, 201, 256, 31, 225, 32, 48, 49, 33,
- 301, 265, 267, 50, 75, 268, 287, 76, 48, 49,
- 302, 77, 78, 79, 80, 276, 277, 81, 82, 99,
- 100, 279, 280, 288, 51, 337, 52, 50, 290, 295,
- 297, 307, 343, 83, 69, 309, 54, 298, 50, 75,
- 48, 153, 76, 48, 49, 306, 77, 78, 79, 80,
- 52, 303, 81, 82, 315, 101, 310, 313, 53, 51,
- 54, 52, 48, 49, 316, 48, 49, 317, 83, 69,
- 50, 54, 321, 50, 75, 324, 325, 76, 326, 334,
- 328, 77, 78, 48, 49, 332, 335, 48, 49, 154,
- 155, 51, 50, 52, 339, 50, 52, 233, 341, 318,
- 173, 69, 338, 54, 53, 140, 54, 251, 99, 100,
- 0, 48, 49, 50, 0, 52, 51, 50, 52, 0,
- 0, 0, 0, 53, 0, 54, 53, 0, 54, 48,
- 49, 0, 0, 0, 51, 0, 52, 0, 110, 0,
- 52, 50, 0, 0, 69, 0, 54, 0, 53, 0,
- 54, 48, 49, 75, 0, 0, 76, 0, 0, 50,
- 77, 78, 172, 0, 52, 0, 0, 0, 99, 100,
- 0, 0, 69, 0, 54, 0, 0, 0, 225, 41,
- 0, 50, 52, 195, 196, 197, 198, 199, 200, 201,
- 53, 0, 54, 192, 193, 194, 195, 196, 197, 198,
- 199, 200, 201, 0, 52, 0, 0, 0, 0, 0,
- 0, 0, 69, 0, 54, 192, 193, 194, 195, 196,
- 197, 198, 199, 200, 201, 38, 39, 40, 0, 43,
- 44, 45, 46, 47, 0, 0, 0, 59, 0, 0,
- 62, 63, 64, 65, 66, 67, 194, 195, 196, 197,
- 198, 199, 200, 201, 234, 192, 193, 194, 195, 196,
- 197, 198, 199, 200, 201, 193, 194, 195, 196, 197,
- 198, 199, 200, 201, 0, 0, 235, 205, 206, 207,
- 76, 0, 0, 0, 77, 78
-};
-
-static const yytype_int16 yycheck[] =
-{
- 29, 30, 45, 61, 133, 9, 9, 68, 37, 38,
- 39, 62, 0, 64, 65, 44, 37, 38, 15, 16,
- 17, 28, 30, 44, 9, 46, 110, 6, 7, 64,
- 9, 39, 65, 9, 64, 15, 16, 17, 59, 63,
- 69, 54, 55, 19, 20, 66, 67, 108, 28, 29,
- 30, 27, 65, 38, 57, 149, 150, 118, 69, 39,
- 38, 65, 42, 67, 40, 45, 44, 43, 48, 49,
- 46, 47, 62, 63, 54, 68, 83, 56, 8, 9,
- 48, 49, 39, 63, 113, 42, 115, 11, 172, 46,
- 47, 185, 65, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 83, 188, 113, 8, 9, 38, 37,
- 38, 108, 48, 49, 8, 9, 44, 146, 54, 55,
- 6, 101, 8, 9, 54, 55, 187, 65, 108, 158,
- 159, 61, 68, 113, 69, 164, 66, 69, 267, 69,
- 169, 71, 171, 69, 38, 125, 126, 69, 169, 170,
- 158, 131, 181, 133, 134, 69, 164, 96, 97, 135,
- 70, 65, 213, 171, 42, 216, 217, 61, 46, 47,
- 50, 51, 152, 153, 68, 69, 69, 71, 158, 39,
- 48, 49, 42, 65, 164, 39, 46, 47, 42, 246,
- 247, 171, 46, 47, 54, 55, 65, 218, 219, 228,
- 229, 230, 231, 39, 40, 41, 39, 183, 68, 42,
- 268, 65, 151, 46, 47, 65, 245, 246, 247, 48,
- 49, 54, 55, 65, 69, 54, 55, 248, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 10, 11,
- 12, 8, 9, 39, 40, 41, 42, 290, 228, 229,
- 230, 231, 65, 192, 193, 194, 307, 65, 197, 198,
- 199, 200, 201, 229, 230, 231, 287, 243, 69, 7,
- 65, 38, 69, 249, 295, 214, 65, 306, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 65, 310,
- 70, 65, 321, 6, 61, 70, 65, 273, 7, 328,
- 65, 68, 69, 332, 71, 65, 1, 7, 7, 42,
- 290, 8, 9, 10, 11, 12, 255, 256, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 69, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 8, 9, 70, 67, 66, 65, 44,
- 45, 6, 70, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 7, 59, 57, 61, 8, 9, 64,
- 38, 65, 65, 38, 39, 65, 65, 42, 8, 9,
- 9, 46, 47, 48, 49, 70, 70, 52, 53, 54,
- 55, 70, 70, 70, 59, 334, 61, 38, 65, 65,
- 69, 65, 341, 68, 69, 65, 71, 70, 38, 39,
- 8, 9, 42, 8, 9, 65, 46, 47, 48, 49,
- 61, 68, 52, 53, 40, 68, 65, 67, 69, 59,
- 71, 61, 8, 9, 9, 8, 9, 38, 68, 69,
- 38, 71, 69, 38, 39, 70, 38, 42, 65, 69,
- 65, 46, 47, 8, 9, 65, 65, 8, 9, 57,
- 58, 59, 38, 61, 70, 38, 61, 165, 65, 303,
- 108, 69, 335, 71, 69, 64, 71, 191, 54, 55,
- -1, 8, 9, 38, -1, 61, 59, 38, 61, -1,
- -1, -1, -1, 69, -1, 71, 69, -1, 71, 8,
- 9, -1, -1, -1, 59, -1, 61, -1, 59, -1,
- 61, 38, -1, -1, 69, -1, 71, -1, 69, -1,
- 71, 8, 9, 39, -1, -1, 42, -1, -1, 38,
- 46, 47, 59, -1, 61, -1, -1, -1, 54, 55,
- -1, -1, 69, -1, 71, -1, -1, -1, 57, 65,
- -1, 38, 61, 6, 7, 8, 9, 10, 11, 12,
- 69, -1, 71, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, -1, 61, -1, -1, -1, -1, -1,
- -1, -1, 69, -1, 71, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 6, 7, 8, -1, 10,
- 11, 12, 13, 14, -1, -1, -1, 18, -1, -1,
- 21, 22, 23, 24, 25, 26, 5, 6, 7, 8,
- 9, 10, 11, 12, 64, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, -1, -1, 64, 39, 40, 41,
- 42, -1, -1, -1, 46, 47
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 73, 0, 74, 1, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 29, 30, 31, 32, 33, 34, 35, 36, 37, 44,
- 45, 59, 61, 64, 75, 77, 64, 78, 78, 78,
- 78, 65, 79, 78, 78, 78, 78, 78, 8, 9,
- 38, 59, 61, 69, 71, 101, 104, 101, 101, 78,
- 79, 79, 78, 78, 78, 78, 78, 78, 79, 69,
- 87, 88, 89, 101, 104, 39, 42, 46, 47, 48,
- 49, 52, 53, 68, 82, 83, 85, 89, 92, 94,
- 96, 97, 100, 104, 85, 62, 63, 63, 64, 54,
- 55, 68, 90, 91, 92, 94, 90, 85, 79, 79,
- 59, 80, 104, 79, 90, 66, 88, 104, 79, 92,
- 97, 79, 104, 104, 6, 8, 9, 102, 104, 106,
- 104, 65, 69, 65, 11, 92, 82, 100, 104, 68,
- 83, 99, 100, 100, 92, 92, 69, 87, 97, 69,
- 69, 69, 69, 9, 57, 58, 89, 104, 65, 69,
- 6, 7, 9, 56, 65, 76, 106, 106, 104, 65,
- 65, 65, 59, 80, 86, 87, 101, 104, 102, 69,
- 85, 65, 84, 97, 65, 69, 87, 65, 7, 104,
- 104, 69, 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 70, 68, 104, 39, 40, 41, 103, 91,
- 104, 104, 79, 65, 65, 9, 65, 65, 65, 65,
- 70, 96, 96, 106, 104, 57, 85, 97, 6, 7,
- 7, 7, 85, 75, 64, 64, 92, 97, 92, 85,
- 102, 69, 42, 97, 67, 9, 79, 66, 65, 87,
- 102, 103, 106, 106, 106, 6, 7, 106, 106, 106,
- 106, 106, 9, 38, 81, 65, 70, 65, 65, 100,
- 106, 49, 100, 100, 92, 92, 70, 70, 70, 70,
- 70, 95, 97, 104, 95, 95, 95, 65, 70, 79,
- 65, 97, 84, 84, 92, 65, 79, 69, 70, 106,
- 106, 38, 9, 68, 91, 82, 65, 65, 79, 65,
- 65, 92, 88, 67, 92, 40, 9, 38, 81, 97,
- 100, 69, 93, 92, 70, 38, 65, 97, 65, 50,
- 51, 98, 65, 97, 69, 65, 97, 106, 98, 70,
- 70, 65, 105, 106
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 3:
-#line 70 "a.y"
- {
- stmtline = lineno;
- }
- break;
-
- case 5:
-#line 77 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyvsp[(1) - (2)].sym)->type = LLAB;
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 7:
-#line 86 "a.y"
- {
- (yyvsp[(1) - (4)].sym)->type = LVAR;
- (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 8:
-#line 91 "a.y"
- {
- if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
- yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
- (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 12:
-#line 105 "a.y"
- {
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
- }
- break;
-
- case 13:
-#line 109 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
- }
- break;
-
- case 14:
-#line 113 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 15:
-#line 120 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 16:
-#line 127 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 17:
-#line 134 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 18:
-#line 138 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 19:
-#line 145 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 20:
-#line 152 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 21:
-#line 159 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 22:
-#line 166 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
- }
- break;
-
- case 23:
-#line 173 "a.y"
- {
- Addr g;
-
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset = (yyvsp[(6) - (7)].lval);
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), 0, &g);
- }
- break;
-
- case 24:
-#line 182 "a.y"
- {
- Addr g;
-
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset = (yyvsp[(4) - (7)].lval);
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, 0, &(yyvsp[(7) - (7)].addr));
- }
- break;
-
- case 25:
-#line 194 "a.y"
- {
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
- }
- break;
-
- case 26:
-#line 198 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr));
- }
- break;
-
- case 27:
-#line 202 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 28:
-#line 209 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, 0, &nullgen);
- }
- break;
-
- case 29:
-#line 216 "a.y"
- {
- settext((yyvsp[(2) - (5)].addr).sym);
- outcode((yyvsp[(1) - (5)].lval), Always, &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 30:
-#line 221 "a.y"
- {
- settext((yyvsp[(2) - (7)].addr).sym);
- outcode((yyvsp[(1) - (7)].lval), Always, &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
- }
- }
- break;
-
- case 31:
-#line 233 "a.y"
- {
- settext((yyvsp[(2) - (4)].addr).sym);
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 32:
-#line 238 "a.y"
- {
- settext((yyvsp[(2) - (6)].addr).sym);
- outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 33:
-#line 250 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 34:
-#line 261 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), 0, &nullgen);
- }
- break;
-
- case 35:
-#line 268 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 36:
-#line 275 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 37:
-#line 279 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 38:
-#line 283 "a.y"
- {
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
- }
- break;
-
- case 39:
-#line 287 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
- }
- break;
-
- case 40:
-#line 294 "a.y"
- {
- Addr g;
-
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset =
- (0xe << 24) | /* opcode */
- ((yyvsp[(1) - (12)].lval) << 20) | /* MCR/MRC */
- (((yyvsp[(2) - (12)].lval)^C_SCOND_XOR) << 28) | /* scond */
- (((yyvsp[(3) - (12)].lval) & 15) << 8) | /* coprocessor number */
- (((yyvsp[(5) - (12)].lval) & 7) << 21) | /* coprocessor operation */
- (((yyvsp[(7) - (12)].lval) & 15) << 12) | /* arm register */
- (((yyvsp[(9) - (12)].lval) & 15) << 16) | /* Crn */
- (((yyvsp[(11) - (12)].lval) & 15) << 0) | /* Crm */
- (((yyvsp[(12) - (12)].lval) & 7) << 5) | /* coprocessor information */
- (1<<4); /* must be set */
- outcode(AMRC, Always, &nullgen, 0, &g);
- }
- break;
-
- case 41:
-#line 316 "a.y"
- {
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
- }
- break;
-
- case 42:
-#line 324 "a.y"
- {
- (yyvsp[(7) - (9)].addr).type = TYPE_REGREG2;
- (yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval);
- outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr));
- }
- break;
-
- case 43:
-#line 333 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), 0, &nullgen);
- }
- break;
-
- case 44:
-#line 340 "a.y"
- {
- if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 45:
-#line 349 "a.y"
- {
- if((yyvsp[(2) - (4)].addr).type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM)
- yyerror("value for FUNCDATA must be symbol reference");
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 46:
-#line 360 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, 0, &nullgen);
- }
- break;
-
- case 47:
-#line 365 "a.y"
- {
- (yyval.lval) = Always;
- }
- break;
-
- case 48:
-#line 369 "a.y"
- {
- (yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 49:
-#line 373 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 52:
-#line 382 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
- }
- break;
-
- case 53:
-#line 388 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- (yyval.addr) = nullgen;
- if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 54:
-#line 399 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 55:
-#line 406 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 56:
-#line 413 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
- (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 57:
-#line 420 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
- (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 58:
-#line 428 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 59:
-#line 434 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- (yyval.addr).type = TYPE_ADDR;
- }
- break;
-
- case 60:
-#line 439 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SCONST;
- memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
- }
- break;
-
- case 62:
-#line 448 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
- }
- break;
-
- case 63:
-#line 454 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
- }
- break;
-
- case 64:
-#line 462 "a.y"
- {
- if((yyvsp[(1) - (1)].lval) < REG_R0 || (yyvsp[(1) - (1)].lval) > REG_R15)
- yyerror("invalid register in reglist");
-
- (yyval.lval) = 1 << ((yyvsp[(1) - (1)].lval)&15);
- }
- break;
-
- case 65:
-#line 469 "a.y"
- {
- int i;
-
- if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15)
- yyerror("invalid register in reglist");
- if((yyvsp[(3) - (3)].lval) < REG_R0 || (yyvsp[(3) - (3)].lval) > REG_R15)
- yyerror("invalid register in reglist");
-
- (yyval.lval)=0;
- for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++)
- (yyval.lval) |= 1<<(i&15);
- for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++)
- (yyval.lval) |= 1<<(i&15);
- }
- break;
-
- case 66:
-#line 484 "a.y"
- {
- if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15)
- yyerror("invalid register in reglist");
-
- (yyval.lval) = (1<<((yyvsp[(1) - (3)].lval)&15)) | (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 70:
-#line 496 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (4)].addr);
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 71:
-#line 501 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 72:
-#line 507 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 73:
-#line 513 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 77:
-#line 524 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (1)].addr);
- if((yyvsp[(1) - (1)].addr).name != NAME_EXTERN && (yyvsp[(1) - (1)].addr).name != NAME_STATIC) {
- }
- }
- break;
-
- case 78:
-#line 532 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
- (yyval.addr).offset = 0;
- }
- break;
-
- case 80:
-#line 542 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 82:
-#line 552 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (4)].addr);
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 87:
-#line 565 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 88:
-#line 573 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 89:
-#line 581 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REGREG;
- (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
- (yyval.addr).offset = (yyvsp[(4) - (5)].lval);
- }
- break;
-
- case 90:
-#line 590 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SHIFT;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (0 << 5);
- }
- break;
-
- case 91:
-#line 596 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SHIFT;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (1 << 5);
- }
- break;
-
- case 92:
-#line 602 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SHIFT;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (2 << 5);
- }
- break;
-
- case 93:
-#line 608 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SHIFT;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (3 << 5);
- }
- break;
-
- case 94:
-#line 616 "a.y"
- {
- if((yyval.lval) < REG_R0 || (yyval.lval) > REG_R15)
- print("register value out of range in shift\n");
- (yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4);
- }
- break;
-
- case 95:
-#line 622 "a.y"
- {
- if((yyval.lval) < 0 || (yyval.lval) >= 32)
- print("shift value out of range\n");
- (yyval.lval) = ((yyvsp[(1) - (1)].lval)&31) << 7;
- }
- break;
-
- case 97:
-#line 631 "a.y"
- {
- (yyval.lval) = REGPC;
- }
- break;
-
- case 98:
-#line 635 "a.y"
- {
- if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
- print("register value out of range in R(...)\n");
- (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 100:
-#line 644 "a.y"
- {
- (yyval.lval) = REGSP;
- }
- break;
-
- case 102:
-#line 651 "a.y"
- {
- if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
- print("register value out of range in C(...)\n");
- (yyval.lval) = (yyvsp[(3) - (4)].lval); // TODO(rsc): REG_C0+$3
- }
- break;
-
- case 105:
-#line 663 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 106:
-#line 669 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 107:
-#line 677 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(3) - (4)].lval);
- (yyval.addr).sym = nil;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 108:
-#line 685 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(4) - (5)].lval);
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
- (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
- }
- break;
-
- case 109:
-#line 693 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = NAME_STATIC;
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
- (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
- }
- break;
-
- case 110:
-#line 702 "a.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 111:
-#line 706 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 112:
-#line 710 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 117:
-#line 722 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
- }
- break;
-
- case 118:
-#line 726 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 119:
-#line 730 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 120:
-#line 734 "a.y"
- {
- (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 121:
-#line 738 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 122:
-#line 743 "a.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 123:
-#line 747 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 125:
-#line 754 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 126:
-#line 758 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 127:
-#line 762 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 128:
-#line 766 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 129:
-#line 770 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 130:
-#line 774 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 131:
-#line 778 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 132:
-#line 782 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 133:
-#line 786 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 134:
-#line 790 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 2642 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
deleted file mode 100644
index fbbdbef99b..0000000000
--- a/src/cmd/5a/y.tab.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE1 = 258,
- LTYPE2 = 259,
- LTYPE3 = 260,
- LTYPE4 = 261,
- LTYPE5 = 262,
- LTYPE6 = 263,
- LTYPE7 = 264,
- LTYPE8 = 265,
- LTYPE9 = 266,
- LTYPEA = 267,
- LTYPEB = 268,
- LGLOBL = 269,
- LTYPEC = 270,
- LTYPED = 271,
- LTYPEE = 272,
- LTYPEG = 273,
- LTYPEH = 274,
- LTYPEI = 275,
- LTYPEJ = 276,
- LTYPEK = 277,
- LTYPEL = 278,
- LTYPEM = 279,
- LTYPEN = 280,
- LTYPEBX = 281,
- LTYPEPLD = 282,
- LCONST = 283,
- LSP = 284,
- LSB = 285,
- LFP = 286,
- LPC = 287,
- LTYPEX = 288,
- LTYPEPC = 289,
- LTYPEF = 290,
- LR = 291,
- LREG = 292,
- LF = 293,
- LFREG = 294,
- LC = 295,
- LCREG = 296,
- LPSR = 297,
- LFCR = 298,
- LCOND = 299,
- LS = 300,
- LAT = 301,
- LFCONST = 302,
- LSCONST = 303,
- LNAME = 304,
- LLAB = 305,
- LVAR = 306
- };
-#endif
-/* Tokens. */
-#define LTYPE1 258
-#define LTYPE2 259
-#define LTYPE3 260
-#define LTYPE4 261
-#define LTYPE5 262
-#define LTYPE6 263
-#define LTYPE7 264
-#define LTYPE8 265
-#define LTYPE9 266
-#define LTYPEA 267
-#define LTYPEB 268
-#define LGLOBL 269
-#define LTYPEC 270
-#define LTYPED 271
-#define LTYPEE 272
-#define LTYPEG 273
-#define LTYPEH 274
-#define LTYPEI 275
-#define LTYPEJ 276
-#define LTYPEK 277
-#define LTYPEL 278
-#define LTYPEM 279
-#define LTYPEN 280
-#define LTYPEBX 281
-#define LTYPEPLD 282
-#define LCONST 283
-#define LSP 284
-#define LSB 285
-#define LFP 286
-#define LPC 287
-#define LTYPEX 288
-#define LTYPEPC 289
-#define LTYPEF 290
-#define LR 291
-#define LREG 292
-#define LF 293
-#define LFREG 294
-#define LC 295
-#define LCREG 296
-#define LPSR 297
-#define LFCR 298
-#define LCOND 299
-#define LS 300
-#define LAT 301
-#define LFCONST 302
-#define LSCONST 303
-#define LNAME 304
-#define LLAB 305
-#define LVAR 306
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 39 "a.y"
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
-}
-/* Line 1529 of yacc.c. */
-#line 159 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
deleted file mode 100644
index 3f528d7517..0000000000
--- a/src/cmd/5g/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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.
-
-include ../../Make.dist
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
deleted file mode 100644
index 354e0cbfd6..0000000000
--- a/src/cmd/5g/cgen.c
+++ /dev/null
@@ -1,1840 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2, f0, f1;
- int a, w, rg;
- Prog *p1, *p2, *p3;
- Addr addr;
-
- if(debug['g']) {
- dump("\ncgen-n", n);
- dump("cgen-res", res);
- }
- if(n == N || n->type == T)
- goto ret;
-
- if(res == N || res->type == T)
- fatal("cgen: res nil");
-
- switch(n->op) {
- case OSLICE:
- case OSLICEARR:
- case OSLICESTR:
- case OSLICE3:
- case OSLICE3ARR:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_slice(n, &n1);
- cgen(&n1, res);
- } else
- cgen_slice(n, res);
- return;
- case OEFACE:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_eface(n, &n1);
- cgen(&n1, res);
- } else
- cgen_eface(n, res);
- return;
- }
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(n->ullman >= UINF) {
- if(n->op == OINDREG)
- fatal("cgen: this is going to misscompile");
- if(res->ullman >= UINF) {
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- goto ret;
- }
- }
-
- if(isfat(n->type)) {
- if(n->type->width < 0)
- fatal("forgot to compute width for %T", n->type);
- sgen(n, res, n->type->width);
- goto ret;
- }
-
-
- // update addressability for string, slice
- // can't do in walk because n->left->addable
- // changes if n->left is an escaping local variable.
- switch(n->op) {
- case OSPTR:
- case OLEN:
- if(isslice(n->left->type) || istype(n->left->type, TSTRING))
- n->addable = n->left->addable;
- break;
- case OCAP:
- if(isslice(n->left->type))
- n->addable = n->left->addable;
- break;
- case OITAB:
- n->addable = n->left->addable;
- break;
- }
-
- // if both are addressable, move
- if(n->addable && res->addable) {
- if(is64(n->type) || is64(res->type) ||
- n->op == OREGISTER || res->op == OREGISTER ||
- iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
- gmove(n, res);
- } else {
- regalloc(&n1, n->type, N);
- gmove(n, &n1);
- cgen(&n1, res);
- regfree(&n1);
- }
- goto ret;
- }
-
- // if both are not addressable, use a temporary.
- if(!n->addable && !res->addable) {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
-
- if(complexop(n, res)) {
- complexgen(n, res);
- return;
- }
-
- // if n is sudoaddable generate addr and move
- if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
- a = optoas(OAS, n->type);
- if(sudoaddable(a, n, &addr, &w)) {
- if (res->op != OREGISTER) {
- regalloc(&n2, res->type, N);
- p1 = gins(a, N, &n2);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- gmove(&n2, res);
- regfree(&n2);
- } else {
- p1 = gins(a, N, res);
- p1->from = addr;
- if(debug['g'])
- print("%P [ignore previous line]\n", p1);
- }
- sudoclean();
- goto ret;
- }
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- nl = n->left;
- nr = n->right;
-
- if(nl != N && nl->ullman >= UINF)
- if(nr != N && nr->ullman >= UINF) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- n2 = *n;
- n2.left = &n1;
- cgen(&n2, res);
- goto ret;
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
- switch(n->op) {
- // math goes to cgen64.
- case OMINUS:
- case OCOM:
- case OADD:
- case OSUB:
- case OMUL:
- case OLROT:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- cgen64(n, res);
- return;
- }
- }
-
- if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
- goto flt;
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen: unknown op %+hN", n);
- break;
-
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- fatal("unexpected complex");
- break;
-
- // these call bgen to get a bool value
- case OOROR:
- case OANDAND:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case ONOT:
- p1 = gbranch(AB, T, 0);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AB, T, 0);
- patch(p1, pc);
- bgen(n, 1, 0, p2);
- gmove(nodbool(0), res);
- patch(p3, pc);
- goto ret;
-
- case OPLUS:
- cgen(nl, res);
- goto ret;
-
- // unary
- case OCOM:
- a = optoas(OXOR, nl->type);
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, -1);
- gins(a, &n2, &n1);
- goto norm;
-
- case OMINUS:
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- nodconst(&n2, nl->type, 0);
- gins(optoas(OMINUS, nl->type), &n2, &n1);
- goto norm;
-
- // symmetric binary
- case OAND:
- case OOR:
- case OXOR:
- case OADD:
- case OMUL:
- a = optoas(n->op, nl->type);
- goto sbop;
-
- // asymmetric binary
- case OSUB:
- a = optoas(n->op, nl->type);
- goto abop;
-
- case OHMUL:
- cgen_hmul(nl, nr, res);
- break;
-
- case OLROT:
- case OLSH:
- case ORSH:
- cgen_shift(n->op, n->bounded, nl, nr, res);
- break;
-
- case OCONV:
- if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- break;
- }
- if(nl->addable && !is64(nl->type)) {
- regalloc(&n1, nl->type, res);
- gmove(nl, &n1);
- } else {
- if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
- tempname(&n1, nl->type);
- else
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- }
- if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
- tempname(&n2, n->type);
- else
- regalloc(&n2, n->type, N);
- gmove(&n1, &n2);
- gmove(&n2, res);
- if(n1.op == OREGISTER)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- break;
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME: // PHEAP or PPARAMREF var
- igen(n, &n1, res);
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OITAB:
- // interface table is first word of interface value
- igen(nl, &n1, res);
- n1.type = n->type;
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OSPTR:
- // pointer is the first word of string or slice.
- if(isconst(nl, CTSTR)) {
- regalloc(&n1, types[tptr], res);
- p1 = gins(AMOVW, N, &n1);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- igen(nl, &n1, res);
- n1.type = n->type;
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(istype(nl->type, TSTRING) || isslice(nl->type)) {
- // both slice and string have len one pointer into the struct.
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_nel;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OLEN: unknown type %lT", nl->type);
- break;
-
- case OCAP:
- if(istype(nl->type, TCHAN)) {
- // chan has cap in the second 32-bit word.
- // a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- cgen(nl, &n1);
-
- nodconst(&n2, types[tptr], 0);
- gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- rg = -1;
- if(n->ullman >= UINF) {
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- rg = res->val.u.reg;
- reg[rg]--;
- }
- }
- if(n->op == OCALLMETH)
- cgen_callmeth(n, 0);
- else
- cgen_call(n, 0);
- if(rg >= 0)
- reg[rg]++;
- cgen_callret(n, res);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_callret(n, res);
- break;
-
- case OMOD:
- case ODIV:
- a = optoas(n->op, nl->type);
- goto abop;
- }
- goto ret;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- // TODO(kaib): use fewer registers here.
- if(nl->ullman >= nr->ullman) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- switch(n->op) {
- case OADD:
- case OSUB:
- case OAND:
- case OOR:
- case OXOR:
- if(smallintconst(nr)) {
- n2 = *nr;
- break;
- }
- default:
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- }
- } else {
- switch(n->op) {
- case OADD:
- case OSUB:
- case OAND:
- case OOR:
- case OXOR:
- if(smallintconst(nr)) {
- n2 = *nr;
- break;
- }
- default:
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
- }
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- }
- gins(a, &n2, &n1);
-norm:
- // Normalize result for types smaller than word.
- if(n->type->width < widthptr) {
- switch(n->op) {
- case OADD:
- case OSUB:
- case OMUL:
- case OCOM:
- case OMINUS:
- gins(optoas(OAS, n->type), &n1, &n1);
- break;
- }
- }
- gmove(&n1, res);
- regfree(&n1);
- if(n2.op != OLITERAL)
- regfree(&n2);
- goto ret;
-
-flt: // floating-point.
- regalloc(&f0, nl->type, res);
- if(nr != N)
- goto flt2;
-
- if(n->op == OMINUS) {
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- n->op = OMUL;
- goto flt2;
- }
-
- // unary
- cgen(nl, &f0);
- if(n->op != OCONV && n->op != OPLUS)
- gins(optoas(n->op, n->type), &f0, &f0);
- gmove(&f0, res);
- regfree(&f0);
- goto ret;
-
-flt2: // binary
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &f0);
- regalloc(&f1, n->type, N);
- gmove(&f0, &f1);
- cgen(nr, &f0);
- gins(optoas(n->op, n->type), &f0, &f1);
- } else {
- cgen(nr, &f0);
- regalloc(&f1, n->type, N);
- cgen(nl, &f1);
- gins(optoas(n->op, n->type), &f0, &f1);
- }
- gmove(&f1, res);
- regfree(&f0);
- regfree(&f1);
- goto ret;
-
-ret:
- ;
-}
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-Prog*
-cgenindex(Node *n, Node *res, int bounded)
-{
- Node tmp, lo, hi, zero, n1, n2;
-
- if(!is64(n->type)) {
- cgen(n, res);
- return nil;
- }
-
- tempname(&tmp, types[TINT64]);
- cgen(n, &tmp);
- split64(&tmp, &lo, &hi);
- gmove(&lo, res);
- if(bounded) {
- splitclean();
- return nil;
- }
- regalloc(&n1, types[TINT32], N);
- regalloc(&n2, types[TINT32], N);
- nodconst(&zero, types[TINT32], 0);
- gmove(&hi, &n1);
- gmove(&zero, &n2);
- gcmp(ACMP, &n1, &n2);
- regfree(&n2);
- regfree(&n1);
- splitclean();
- return gbranch(ABNE, T, -1);
-}
-
-/*
- * generate:
- * res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl;
- Node n1, n2, n3;
- int r;
-
- if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T || res == N || res->type == T)
- fatal("agen");
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(isconst(n, CTNIL) && n->type->width > widthptr) {
- // Use of a nil interface or nil slice.
- // Create a temporary we can take the address of and read.
- // The generated code is just going to panic, so it need not
- // be terribly efficient. See issue 3670.
- tempname(&n1, n->type);
- gvardef(&n1);
- clearfat(&n1);
- regalloc(&n2, types[tptr], res);
- gins(AMOVW, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
-
- if(n->addable) {
- memset(&n1, 0, sizeof n1);
- n1.op = OADDR;
- n1.left = n;
- regalloc(&n2, types[tptr], res);
- gins(AMOVW, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
- nl = n->left;
-
- switch(n->op) {
- default:
- fatal("agen: unknown op %+hN", n);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- r = -1;
- if(n->ullman >= UINF) {
- if(res->op == OREGISTER || res->op == OINDREG) {
- r = res->val.u.reg;
- reg[r]--;
- }
- }
- if(n->op == OCALLMETH)
- cgen_callmeth(n, 0);
- else
- cgen_call(n, 0);
- if(r >= 0)
- reg[r]++;
- cgen_aret(n, res);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, res, 0);
- cgen_aret(n, res);
- break;
-
- case OSLICE:
- case OSLICEARR:
- case OSLICESTR:
- case OSLICE3:
- case OSLICE3ARR:
- tempname(&n1, n->type);
- cgen_slice(n, &n1);
- agen(&n1, res);
- break;
-
- case OEFACE:
- tempname(&n1, n->type);
- cgen_eface(n, &n1);
- agen(&n1, res);
- break;
-
- case OINDEX:
- agenr(n, &n1, res);
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case ONAME:
- // should only get here with names in this func.
- if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
- dump("bad agen", n);
- fatal("agen: bad ONAME funcdepth %d != %d",
- n->funcdepth, funcdepth);
- }
-
- // should only get here for heap vars or paramref
- if(!(n->class & PHEAP) && n->class != PPARAMREF) {
- dump("bad agen", n);
- fatal("agen: bad ONAME class %#x", n->class);
- }
- cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- cgen_checknil(res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[TINT32], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- cgen_checknil(res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT32], n->xoffset);
- regalloc(&n2, n1.type, N);
- regalloc(&n3, types[tptr], N);
- gmove(&n1, &n2);
- gmove(res, &n3);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- }
- break;
- }
-
-ret:
- ;
-}
-
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
- Node n1;
- int r;
-
- if(debug['g']) {
- dump("\nigen-n", n);
- }
- switch(n->op) {
- case ONAME:
- if((n->class&PHEAP) || n->class == PPARAMREF)
- break;
- *a = *n;
- return;
-
- case OINDREG:
- // Increase the refcount of the register so that igen's caller
- // has to call regfree.
- if(n->val.u.reg != REGSP)
- reg[n->val.u.reg]++;
- *a = *n;
- return;
-
- case ODOT:
- igen(n->left, a, res);
- a->xoffset += n->xoffset;
- a->type = n->type;
- return;
-
- case ODOTPTR:
- if(n->left->addable
- || n->left->op == OCALLFUNC
- || n->left->op == OCALLMETH
- || n->left->op == OCALLINTER) {
- // igen-able nodes.
- igen(n->left, &n1, res);
- regalloc(a, types[tptr], &n1);
- gmove(&n1, a);
- regfree(&n1);
- } else {
- regalloc(a, types[tptr], res);
- cgen(n->left, a);
- }
- cgen_checknil(a);
- a->op = OINDREG;
- a->xoffset = n->xoffset;
- a->type = n->type;
- return;
-
- case OCALLMETH:
- case OCALLFUNC:
- case OCALLINTER:
- // Release res so that it is available for cgen_call.
- // Pick it up again after the call.
- r = -1;
- if(n->ullman >= UINF) {
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- r = res->val.u.reg;
- reg[r]--;
- }
- }
- switch(n->op) {
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
- case OCALLFUNC:
- cgen_call(n, 0);
- break;
- case OCALLINTER:
- cgen_callinter(n, N, 0);
- break;
- }
- if(r >= 0)
- reg[r]++;
- regalloc(a, types[tptr], res);
- cgen_aret(n, a);
- a->op = OINDREG;
- a->type = n->type;
- return;
- }
-
- agenr(n, a, res);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * allocate a register in res and generate
- * newreg = &n
- * The caller must call regfree(a).
- */
-void
-cgenr(Node *n, Node *a, Node *res)
-{
- Node n1;
-
- if(debug['g'])
- dump("cgenr-n", n);
-
- if(isfat(n->type))
- fatal("cgenr on fat node");
-
- if(n->addable) {
- regalloc(a, types[tptr], res);
- gmove(n, a);
- return;
- }
-
- switch(n->op) {
- case ONAME:
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- igen(n, &n1, res);
- regalloc(a, types[tptr], &n1);
- gmove(&n1, a);
- regfree(&n1);
- break;
- default:
- regalloc(a, n->type, res);
- cgen(n, a);
- break;
- }
-}
-
-/*
- * generate:
- * newreg = &n;
- *
- * caller must regfree(a).
- * The generated code checks that the result is not nil.
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
- Node *nl, *nr;
- Node n1, n2, n3, n4, tmp;
- Prog *p1, *p2;
- uint32 w;
- uint64 v;
- int bounded;
-
- if(debug['g'])
- dump("agenr-n", n);
-
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- case ODOT:
- case ODOTPTR:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- igen(n, &n1, res);
- regalloc(a, types[tptr], &n1);
- agen(&n1, a);
- regfree(&n1);
- break;
-
- case OIND:
- cgenr(n->left, a, res);
- cgen_checknil(a);
- break;
-
- case OINDEX:
- p2 = nil; // to be patched to panicindex.
- w = n->type->width;
- bounded = debug['B'] || n->bounded;
- if(nr->addable) {
- if(!isconst(nr, CTINT))
- tempname(&tmp, types[TINT32]);
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
- p2 = cgenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- } else
- if(nl->addable) {
- if(!isconst(nr, CTINT)) {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- if(!isconst(nl, CTSTR)) {
- agenr(nl, &n3, res);
- }
- } else {
- tempname(&tmp, types[TINT32]);
- p2 = cgenindex(nr, &tmp, bounded);
- nr = &tmp;
- if(!isconst(nl, CTSTR))
- agenr(nl, &n3, res);
- regalloc(&n1, tmp.type, N);
- gins(optoas(OAS, tmp.type), &tmp, &n1);
- }
-
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // w is width
-
- // constant index
- if(isconst(nr, CTINT)) {
- if(isconst(nl, CTSTR))
- fatal("constant string constant index");
- v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->bounded) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- regalloc(&n4, n1.type, N);
- gmove(&n1, &n4);
- nodconst(&n2, types[TUINT32], v);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
- regfree(&n4);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- *a = n3;
- break;
- }
-
- regalloc(&n2, types[TINT32], &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->bounded) {
- // check bounds
- if(isconst(nl, CTSTR)) {
- nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- regalloc(&n4, types[TUINT32], N);
- gmove(&n1, &n4);
- } else {
- nodconst(&n4, types[TUINT32], nl->type->bound);
- }
- gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
- if(n4.op == OREGISTER)
- regfree(&n4);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(AMOVW, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.type = TYPE_ADDR;
- } else
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- if(w == 0) {
- // nothing to do
- } else if(w == 1 || w == 2 || w == 4 || w == 8) {
- memset(&n4, 0, sizeof n4);
- n4.op = OADDR;
- n4.left = &n2;
- cgen(&n4, &n3);
- if (w == 1)
- gins(AADD, &n2, &n3);
- else if(w == 2)
- gshift(AADD, &n2, SHIFT_LL, 1, &n3);
- else if(w == 4)
- gshift(AADD, &n2, SHIFT_LL, 2, &n3);
- else if(w == 8)
- gshift(AADD, &n2, SHIFT_LL, 3, &n3);
- } else {
- regalloc(&n4, types[TUINT32], N);
- nodconst(&n1, types[TUINT32], w);
- gmove(&n1, &n4);
- gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- regfree(&n4);
- }
-
- *a = n3;
- regfree(&n2);
- break;
-
- default:
- regalloc(a, types[tptr], res);
- agen(n, a);
- break;
- }
-}
-
-void
-gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
-{
- Node n1, n2, n3;
- int a;
-
- regalloc(&n1, t, N);
- cgen(n, &n1);
- a = optoas(OCMP, t);
- if(a != ACMP) {
- nodconst(&n2, t, 0);
- regalloc(&n3, t, N);
- gmove(&n2, &n3);
- gcmp(a, &n1, &n3);
- regfree(&n3);
- } else
- gins(ATST, &n1, N);
- a = optoas(o, t);
- patch(gbranch(a, t, likely), to);
- regfree(&n1);
-}
-
-/*
- * generate:
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, n3, tmp;
- NodeList *ll;
- Prog *p1, *p2;
-
- if(debug['g']) {
- dump("\nbgen", n);
- }
-
- if(n == N)
- n = nodbool(1);
-
- if(n->ninit != nil)
- genlist(n->ninit);
-
- if(n->type == T) {
- convlit(&n, types[TBOOL]);
- if(n->type == T)
- goto ret;
- }
-
- et = n->type->etype;
- if(et != TBOOL) {
- yyerror("cgen: bad type %T for %O", n->type, n->op);
- patch(gins(AEND, N, N), to);
- goto ret;
- }
- nr = N;
-
- switch(n->op) {
- default:
- a = ONE;
- if(!true)
- a = OEQ;
- gencmp0(n, n->type, a, likely, to);
- goto ret;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AB, T, 0), to);
- goto ret;
-
- case OANDAND:
- case OOROR:
- if((n->op == OANDAND) == true) {
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- } else {
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
- }
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- goto ret;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- goto ret;
- }
-
- switch(n->op) {
-
- case ONOT:
- bgen(nl, !true, likely, to);
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- a = n->op;
- if(!true) {
- if(isfloat[nl->type->etype]) {
- // brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AB, T, 0);
- p2 = gbranch(AB, T, 0);
- patch(p1, pc);
- ll = n->ninit;
- n->ninit = nil;
- bgen(n, 1, -likely, p2);
- n->ninit = ll;
- patch(gbranch(AB, T, 0), to);
- patch(p2, pc);
- goto ret;
- }
- a = brcom(a);
- true = !true;
- }
-
- // make simplest on right
- if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
- a = brrev(a);
- r = nl;
- nl = nr;
- nr = r;
- }
-
- if(isslice(nl->type)) {
- // only valid to cmp darray to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal array comparison");
- break;
- }
-
- igen(nl, &n1, N);
- n1.xoffset += Array_array;
- n1.type = types[tptr];
- gencmp0(&n1, types[tptr], a, likely, to);
- regfree(&n1);
- break;
- }
-
- if(isinter(nl->type)) {
- // front end shold only leave cmp to literal nil
- if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
- yyerror("illegal interface comparison");
- break;
- }
-
- igen(nl, &n1, N);
- n1.type = types[tptr];
- n1.xoffset += 0;
- gencmp0(&n1, types[tptr], a, likely, to);
- regfree(&n1);
- break;
- }
-
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, likely, to);
- break;
- }
-
- if(is64(nr->type)) {
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- cmp64(nl, nr, a, likely, to);
- break;
- }
-
- if(nr->op == OLITERAL) {
- if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) {
- gencmp0(nl, nl->type, a, likely, to);
- break;
- }
- if(nr->val.ctype == CTNIL) {
- gencmp0(nl, nl->type, a, likely, to);
- break;
- }
- }
-
- a = optoas(a, nr->type);
-
- if(nr->ullman >= UINF) {
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
-
- tempname(&tmp, nl->type);
- gmove(&n1, &tmp);
- regfree(&n1);
-
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
-
- regalloc(&n1, nl->type, N);
- cgen(&tmp, &n1);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type, likely), to);
-
- regfree(&n1);
- regfree(&n2);
- break;
- }
-
- tempname(&n3, nl->type);
- cgen(nl, &n3);
-
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
-
- regalloc(&n1, nl->type, N);
- gmove(&n3, &n1);
-
- regalloc(&n2, nr->type, N);
- gmove(&tmp, &n2);
-
- gcmp(optoas(OCMP, nr->type), &n1, &n2);
- if(isfloat[nl->type->etype]) {
- if(n->op == ONE) {
- p1 = gbranch(ABVS, nr->type, likely);
- patch(gbranch(a, nr->type, likely), to);
- patch(p1, to);
- } else {
- p1 = gbranch(ABVS, nr->type, -likely);
- patch(gbranch(a, nr->type, likely), to);
- patch(p1, pc);
- }
- } else {
- patch(gbranch(a, nr->type, likely), to);
- }
- regfree(&n1);
- regfree(&n2);
- break;
- }
- goto ret;
-
-ret:
- ;
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 off;
-
- switch(n->op) {
- case OINDREG:
- return n->xoffset;
-
- case ODOT:
- t = n->left->type;
- if(isptr[t->etype])
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- return off + n->xoffset;
-
- case OINDEX:
- t = n->left->type;
- if(!isfixedarray(t))
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- if(isconst(n->right, CTINT))
- return off + t->type->width * mpgetfix(n->right->val.u.xval);
- return 1000;
-
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- t = structfirst(&flist, getoutarg(t));
- if(t != T)
- return t->width + 4; // correct for LR
- break;
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000;
-}
-
-/*
- * block copy:
- * memmove(&res, &n, w);
- * NB: character copy assumed little endian architecture
- */
-void
-sgen(Node *n, Node *res, int64 w)
-{
- Node dst, src, tmp, nend, r0, r1, r2, *f;
- int32 c, odst, osrc;
- int dir, align, op;
- Prog *p, *ploop;
- NodeList *l;
-
- if(debug['g']) {
- print("\nsgen w=%lld\n", w);
- dump("r", n);
- dump("res", res);
- }
-
- if(n->ullman >= UINF && res->ullman >= UINF)
- fatal("sgen UINF");
-
- if(w < 0 || (int32)w != w)
- fatal("sgen copy %lld", w);
-
- if(n->type == T)
- fatal("sgen: missing type");
-
- if(w == 0) {
- // evaluate side effects only.
- regalloc(&dst, types[tptr], N);
- agen(res, &dst);
- agen(n, &dst);
- regfree(&dst);
- return;
- }
-
- // If copying .args, that's all the results, so record definition sites
- // for them for the liveness analysis.
- if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
- for(l = curfn->dcl; l != nil; l = l->next)
- if(l->n->class == PPARAMOUT)
- gvardef(l->n);
-
- // Avoid taking the address for simple enough types.
- if(componentgen(n, res))
- return;
-
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align = n->type->align;
- switch(align) {
- default:
- fatal("sgen: invalid alignment %d for %T", align, n->type);
- case 1:
- op = AMOVB;
- break;
- case 2:
- op = AMOVH;
- break;
- case 4:
- op = AMOVW;
- break;
- }
- if(w%align)
- fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
- c = w / align;
-
- // offset on the stack
- osrc = stkof(n);
- odst = stkof(res);
- if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
- // osrc and odst both on stack, and at least one is in
- // an unknown position. Could generate code to test
- // for forward/backward copy, but instead just copy
- // to a temporary location first.
- tempname(&tmp, n->type);
- sgen(n, &tmp, w);
- sgen(&tmp, res, w);
- return;
- }
- if(osrc%align != 0 || odst%align != 0)
- fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir = align;
- if(osrc < odst && odst < osrc+w)
- dir = -dir;
-
- if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) {
- r0.op = OREGISTER;
- r0.val.u.reg = REGALLOC_R0;
- r1.op = OREGISTER;
- r1.val.u.reg = REGALLOC_R0 + 1;
- r2.op = OREGISTER;
- r2.val.u.reg = REGALLOC_R0 + 2;
-
- regalloc(&src, types[tptr], &r1);
- regalloc(&dst, types[tptr], &r2);
- if(n->ullman >= res->ullman) {
- // eval n first
- agen(n, &src);
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- } else {
- // eval res first
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- agen(n, &src);
- }
- regalloc(&tmp, types[tptr], &r0);
- f = sysfunc("duffcopy");
- p = gins(ADUFFCOPY, N, f);
- afunclit(&p->to, f);
- // 8 and 128 = magic constants: see ../../runtime/asm_arm.s
- p->to.offset = 8*(128-c);
-
- regfree(&tmp);
- regfree(&src);
- regfree(&dst);
- return;
- }
-
- if(n->ullman >= res->ullman) {
- agenr(n, &dst, res); // temporarily use dst
- regalloc(&src, types[tptr], N);
- gins(AMOVW, &dst, &src);
- if(res->op == ONAME)
- gvardef(res);
- agen(res, &dst);
- } else {
- if(res->op == ONAME)
- gvardef(res);
- agenr(res, &dst, res);
- agenr(n, &src, N);
- }
-
- regalloc(&tmp, types[TUINT32], N);
-
- // set up end marker
- memset(&nend, 0, sizeof nend);
- if(c >= 4) {
- regalloc(&nend, types[TUINT32], N);
-
- p = gins(AMOVW, &src, &nend);
- p->from.type = TYPE_ADDR;
- if(dir < 0)
- p->from.offset = dir;
- else
- p->from.offset = w;
- }
-
- // move src and dest to the end of block if necessary
- if(dir < 0) {
- p = gins(AMOVW, &src, &src);
- p->from.type = TYPE_ADDR;
- p->from.offset = w + dir;
-
- p = gins(AMOVW, &dst, &dst);
- p->from.type = TYPE_ADDR;
- p->from.offset = w + dir;
- }
-
- // move
- if(c >= 4) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
- p->scond |= C_PBIT;
- ploop = p;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = dir;
- p->scond |= C_PBIT;
-
- p = gins(ACMP, &src, N);
- raddr(&nend, p);
-
- patch(gbranch(ABNE, T, 0), ploop);
- regfree(&nend);
- } else {
- while(c-- > 0) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
- p->scond |= C_PBIT;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = dir;
- p->scond |= C_PBIT;
- }
- }
-
- regfree(&dst);
- regfree(&src);
- regfree(&tmp);
-}
-
-static int
-cadable(Node *n)
-{
- if(!n->addable) {
- // dont know how it happens,
- // but it does
- return 0;
- }
-
- switch(n->op) {
- case ONAME:
- return 1;
- }
- return 0;
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if cant.
- */
-int
-componentgen(Node *nr, Node *nl)
-{
- Node nodl, nodr, tmp;
- Type *t;
- int freel, freer;
- vlong fldcount;
- vlong loffset, roffset;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- t = nl->type;
-
- // Slices are ok.
- if(isslice(t))
- break;
- // Small arrays are ok.
- if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
- break;
-
- goto no;
-
- case TSTRUCT:
- // Small structs with non-fat types are ok.
- // Zero-sized structs are treated separately elsewhere.
- fldcount = 0;
- for(t=nl->type->type; t; t=t->down) {
- if(isfat(t->type))
- goto no;
- if(t->etype != TFIELD)
- fatal("componentgen: not a TFIELD: %lT", t);
- fldcount++;
- }
- if(fldcount == 0 || fldcount > 4)
- goto no;
-
- break;
-
- case TSTRING:
- case TINTER:
- break;
- }
-
- nodl = *nl;
- if(!cadable(nl)) {
- if(nr != N && !cadable(nr))
- goto no;
- igen(nl, &nodl, N);
- freel = 1;
- }
-
- if(nr != N) {
- nodr = *nr;
- if(!cadable(nr)) {
- igen(nr, &nodr, N);
- freer = 1;
- }
- } else {
- // When zeroing, prepare a register containing zero.
- nodconst(&tmp, nl->type, 0);
- regalloc(&nodr, types[TUINT], N);
- gmove(&tmp, &nodr);
- freer = 1;
- }
-
- // nl and nr are 'cadable' which basically means they are names (variables) now.
- // If they are the same variable, don't generate any code, because the
- // VARDEF we generate will mark the old value as dead incorrectly.
- // (And also the assignments are useless.)
- if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
- goto yes;
-
- switch(nl->type->etype) {
- case TARRAY:
- // componentgen for arrays.
- if(nl->op == ONAME)
- gvardef(nl);
- t = nl->type;
- if(!isslice(t)) {
- nodl.type = t->type;
- nodr.type = nodl.type;
- for(fldcount=0; fldcount < t->bound; fldcount++) {
- if(nr == N)
- clearslim(&nodl);
- else
- gmove(&nodr, &nodl);
- nodl.xoffset += t->type->width;
- nodr.xoffset += t->type->width;
- }
- goto yes;
- }
-
- // componentgen for slices.
- nodl.xoffset += Array_array;
- nodl.type = ptrto(nl->type->type);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_cap-Array_nel;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRING:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TINTER:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRUCT:
- if(nl->op == ONAME)
- gvardef(nl);
- loffset = nodl.xoffset;
- roffset = nodr.xoffset;
- // funarg structs may not begin at offset zero.
- if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
- loffset -= nl->type->type->width;
- if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
- roffset -= nr->type->type->width;
-
- for(t=nl->type->type; t; t=t->down) {
- nodl.xoffset = loffset + t->width;
- nodl.type = t->type;
-
- if(nr == N)
- clearslim(&nodl);
- else {
- nodr.xoffset = roffset + t->width;
- nodr.type = nodl.type;
- gmove(&nodr, &nodl);
- }
- }
- goto yes;
- }
-
-no:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 0;
-
-yes:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 1;
-}
diff --git a/src/cmd/new5g/cgen.go b/src/cmd/5g/cgen.go
index bdee52aca6..bdee52aca6 100644
--- a/src/cmd/new5g/cgen.go
+++ b/src/cmd/5g/cgen.go
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
deleted file mode 100644
index 9abab4c650..0000000000
--- a/src/cmd/5g/cgen64.c
+++ /dev/null
@@ -1,760 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
- Node t1, t2, *l, *r;
- Node lo1, lo2, hi1, hi2;
- Node al, ah, bl, bh, cl, ch, s, n1, creg;
- Prog *p1, *p2, *p3, *p4, *p5, *p6;
-
- uint64 v;
-
- if(res->op != OINDREG && res->op != ONAME) {
- dump("n", n);
- dump("res", res);
- fatal("cgen64 %O of %O", n->op, res->op);
- }
-
- l = n->left;
- if(!l->addable) {
- tempname(&t1, l->type);
- cgen(l, &t1);
- l = &t1;
- }
-
- split64(l, &lo1, &hi1);
- switch(n->op) {
- default:
- fatal("cgen64 %O", n->op);
-
- case OMINUS:
- split64(res, &lo2, &hi2);
-
- regalloc(&t1, lo1.type, N);
- regalloc(&al, lo1.type, N);
- regalloc(&ah, hi1.type, N);
-
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
-
- gmove(ncon(0), &t1);
- p1 = gins(ASUB, &al, &t1);
- p1->scond |= C_SBIT;
- gins(AMOVW, &t1, &lo2);
-
- gmove(ncon(0), &t1);
- gins(ASBC, &ah, &t1);
- gins(AMOVW, &t1, &hi2);
-
- regfree(&t1);
- regfree(&al);
- regfree(&ah);
- splitclean();
- splitclean();
- return;
-
- case OCOM:
- regalloc(&t1, lo1.type, N);
- gmove(ncon(-1), &t1);
-
- split64(res, &lo2, &hi2);
- regalloc(&n1, lo1.type, N);
-
- gins(AMOVW, &lo1, &n1);
- gins(AEOR, &t1, &n1);
- gins(AMOVW, &n1, &lo2);
-
- gins(AMOVW, &hi1, &n1);
- gins(AEOR, &t1, &n1);
- gins(AMOVW, &n1, &hi2);
-
- regfree(&t1);
- regfree(&n1);
- splitclean();
- splitclean();
- return;
-
- case OADD:
- case OSUB:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- case OLROT:
- // binary operators.
- // common setup below.
- break;
- }
-
- // setup for binary operators
- r = n->right;
- if(r != N && !r->addable) {
- tempname(&t2, r->type);
- cgen(r, &t2);
- r = &t2;
- }
- if(is64(r->type))
- split64(r, &lo2, &hi2);
-
- regalloc(&al, lo1.type, N);
- regalloc(&ah, hi1.type, N);
-
- // Do op. Leave result in ah:al.
- switch(n->op) {
- default:
- fatal("cgen64: not implemented: %N\n", n);
-
- case OADD:
- // TODO: Constants
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi2, &bh);
- gins(AMOVW, &lo2, &bl);
- p1 = gins(AADD, &bl, &al);
- p1->scond |= C_SBIT;
- gins(AADC, &bh, &ah);
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OSUB:
- // TODO: Constants.
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo2, &bl);
- gins(AMOVW, &hi2, &bh);
- p1 = gins(ASUB, &bl, &al);
- p1->scond |= C_SBIT;
- gins(ASBC, &bh, &ah);
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OMUL:
- // TODO(kaib): this can be done with 4 regs and does not need 6
- regalloc(&bl, types[TPTR32], N);
- regalloc(&bh, types[TPTR32], N);
- regalloc(&cl, types[TPTR32], N);
- regalloc(&ch, types[TPTR32], N);
-
- // load args into bh:bl and bh:bl.
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
- gins(AMOVW, &hi2, &ch);
- gins(AMOVW, &lo2, &cl);
-
- // bl * cl -> ah al
- p1 = gins(AMULLU, N, N);
- p1->from.type = TYPE_REG;
- p1->from.reg = bl.val.u.reg;
- p1->reg = cl.val.u.reg;
- p1->to.type = TYPE_REGREG;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = al.val.u.reg;
-//print("%P\n", p1);
-
- // bl * ch + ah -> ah
- p1 = gins(AMULA, N, N);
- p1->from.type = TYPE_REG;
- p1->from.reg = bl.val.u.reg;
- p1->reg = ch.val.u.reg;
- p1->to.type = TYPE_REGREG2;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
- // bh * cl + ah -> ah
- p1 = gins(AMULA, N, N);
- p1->from.type = TYPE_REG;
- p1->from.reg = bh.val.u.reg;
- p1->reg = cl.val.u.reg;
- p1->to.type = TYPE_REGREG2;
- p1->to.reg = ah.val.u.reg;
- p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
- regfree(&bh);
- regfree(&bl);
- regfree(&ch);
- regfree(&cl);
-
- break;
-
- case OLROT:
- // We only rotate by a constant c in [0,64).
- // if c >= 32:
- // lo, hi = hi, lo
- // c -= 32
- // if c == 0:
- // no-op
- // else:
- // t = hi
- // shld hi:lo, c
- // shld lo:t, c
- v = mpgetfix(r->val.u.xval);
- regalloc(&bl, lo1.type, N);
- regalloc(&bh, hi1.type, N);
- if(v >= 32) {
- // reverse during load to do the first 32 bits of rotate
- v -= 32;
- gins(AMOVW, &hi1, &bl);
- gins(AMOVW, &lo1, &bh);
- } else {
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
- }
- if(v == 0) {
- gins(AMOVW, &bh, &ah);
- gins(AMOVW, &bl, &al);
- } else {
- // rotate by 1 <= v <= 31
- // MOVW bl<<v, al
- // MOVW bh<<v, ah
- // OR bl>>(32-v), ah
- // OR bh>>(32-v), al
- gshift(AMOVW, &bl, SHIFT_LL, v, &al);
- gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
- gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
- gshift(AORR, &bh, SHIFT_LR, 32-v, &al);
- }
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OLSH:
- regalloc(&bl, lo1.type, N);
- regalloc(&bh, hi1.type, N);
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
-
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
- // here and below (verify it optimizes to EOR)
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
- } else
- if(v > 32) {
- gins(AEOR, &al, &al);
- // MOVW bl<<(v-32), ah
- gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
- } else
- if(v == 32) {
- gins(AEOR, &al, &al);
- gins(AMOVW, &bl, &ah);
- } else
- if(v > 0) {
- // MOVW bl<<v, al
- gshift(AMOVW, &bl, SHIFT_LL, v, &al);
-
- // MOVW bh<<v, ah
- gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
-
- // OR bl>>(32-v), ah
- gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
- } else {
- gins(AMOVW, &bl, &al);
- gins(AMOVW, &bh, &ah);
- }
- goto olsh_break;
- }
-
- regalloc(&s, types[TUINT32], N);
- regalloc(&creg, types[TUINT32], N);
- if (is64(r->type)) {
- // shift is >= 1<<32
- split64(r, &cl, &ch);
- gmove(&ch, &s);
- gins(ATST, &s, N);
- p6 = gbranch(ABNE, T, 0);
- gmove(&cl, &s);
- splitclean();
- } else {
- gmove(r, &s);
- p6 = P;
- }
- gins(ATST, &s, N);
-
- // shift == 0
- p1 = gins(AMOVW, &bl, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &ah);
- p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T, 0);
-
- // shift is < 32
- nodconst(&n1, types[TUINT32], 32);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO bl<<s, al
- p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
- p1->scond = C_SCOND_LO;
-
- // MOVW.LO bh<<s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO s, creg
- p1 = gins(ASUB, &s, &creg);
- p1->scond = C_SCOND_LO;
-
- // OR.LO bl>>creg, ah
- p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
- p1->scond = C_SCOND_LO;
-
- // BLO end
- p3 = gbranch(ABLO, T, 0);
-
- // shift == 32
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bl, &ah);
- p1->scond = C_SCOND_EQ;
- p4 = gbranch(ABEQ, T, 0);
-
- // shift is < 64
- nodconst(&n1, types[TUINT32], 64);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // EOR.LO al, al
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_LO;
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO creg, s
- p1 = gins(ASUB, &creg, &s);
- p1->scond = C_SCOND_LO;
-
- // MOVW bl<<s, ah
- p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
- p1->scond = C_SCOND_LO;
-
- p5 = gbranch(ABLO, T, 0);
-
- // shift >= 64
- if (p6 != P) patch(p6, pc);
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
-
- patch(p2, pc);
- patch(p3, pc);
- patch(p4, pc);
- patch(p5, pc);
- regfree(&s);
- regfree(&creg);
-
-olsh_break:
- regfree(&bl);
- regfree(&bh);
- break;
-
-
- case ORSH:
- regalloc(&bl, lo1.type, N);
- regalloc(&bh, hi1.type, N);
- gins(AMOVW, &hi1, &bh);
- gins(AMOVW, &lo1, &bl);
-
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, al
- gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
-
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- gins(AEOR, &al, &al);
- gins(AEOR, &ah, &ah);
- }
- } else
- if(v > 32) {
- if(bh.type->etype == TINT32) {
- // MOVW bh->(v-32), al
- gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
-
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- // MOVW bh>>(v-32), al
- gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
- gins(AEOR, &ah, &ah);
- }
- } else
- if(v == 32) {
- gins(AMOVW, &bh, &al);
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, ah
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- } else {
- gins(AEOR, &ah, &ah);
- }
- } else
- if( v > 0) {
- // MOVW bl>>v, al
- gshift(AMOVW, &bl, SHIFT_LR, v, &al);
-
- // OR bh<<(32-v), al
- gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->v, ah
- gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
- } else {
- // MOVW bh>>v, ah
- gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
- }
- } else {
- gins(AMOVW, &bl, &al);
- gins(AMOVW, &bh, &ah);
- }
- goto orsh_break;
- }
-
- regalloc(&s, types[TUINT32], N);
- regalloc(&creg, types[TUINT32], N);
- if(is64(r->type)) {
- // shift is >= 1<<32
- split64(r, &cl, &ch);
- gmove(&ch, &s);
- gins(ATST, &s, N);
- if(bh.type->etype == TINT32)
- p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- else
- p1 = gins(AEOR, &ah, &ah);
- p1->scond = C_SCOND_NE;
- p6 = gbranch(ABNE, T, 0);
- gmove(&cl, &s);
- splitclean();
- } else {
- gmove(r, &s);
- p6 = P;
- }
- gins(ATST, &s, N);
-
- // shift == 0
- p1 = gins(AMOVW, &bl, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &ah);
- p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T, 0);
-
- // check if shift is < 32
- nodconst(&n1, types[TUINT32], 32);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO bl>>s, al
- p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO s,creg
- p1 = gins(ASUB, &s, &creg);
- p1->scond = C_SCOND_LO;
-
- // OR.LO bh<<(32-s), al
- p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
- p1->scond = C_SCOND_LO;
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
- } else {
- // MOVW bh>>s, ah
- p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
- }
- p1->scond = C_SCOND_LO;
-
- // BLO end
- p3 = gbranch(ABLO, T, 0);
-
- // shift == 32
- p1 = gins(AMOVW, &bh, &al);
- p1->scond = C_SCOND_EQ;
- if(bh.type->etype == TINT32)
- gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
- else
- gins(AEOR, &ah, &ah);
- p4 = gbranch(ABEQ, T, 0);
-
- // check if shift is < 64
- nodconst(&n1, types[TUINT32], 64);
- gmove(&n1, &creg);
- gcmp(ACMP, &s, &creg);
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
- p1->scond = C_SCOND_LO;
-
- // SUB.LO creg, s
- p1 = gins(ASUB, &creg, &s);
- p1->scond = C_SCOND_LO;
-
- if(bh.type->etype == TINT32) {
- // MOVW bh->(s-32), al
- p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
- p1->scond = C_SCOND_LO;
- } else {
- // MOVW bh>>(v-32), al
- p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
- p1->scond = C_SCOND_LO;
- }
-
- // BLO end
- p5 = gbranch(ABLO, T, 0);
-
- // s >= 64
- if(p6 != P)
- patch(p6, pc);
- if(bh.type->etype == TINT32) {
- // MOVW bh->31, al
- gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
- } else {
- gins(AEOR, &al, &al);
- }
-
- patch(p2, pc);
- patch(p3, pc);
- patch(p4, pc);
- patch(p5, pc);
- regfree(&s);
- regfree(&creg);
-
-
-orsh_break:
- regfree(&bl);
- regfree(&bh);
- break;
-
- case OXOR:
- case OAND:
- case OOR:
- // TODO(kaib): literal optimizations
- // make constant the right side (it usually is anyway).
-// if(lo1.op == OLITERAL) {
-// nswap(&lo1, &lo2);
-// nswap(&hi1, &hi2);
-// }
-// if(lo2.op == OLITERAL) {
-// // special cases for constants.
-// lv = mpgetfix(lo2.val.u.xval);
-// hv = mpgetfix(hi2.val.u.xval);
-// splitclean(); // right side
-// split64(res, &lo2, &hi2);
-// switch(n->op) {
-// case OXOR:
-// gmove(&lo1, &lo2);
-// gmove(&hi1, &hi2);
-// switch(lv) {
-// case 0:
-// break;
-// case 0xffffffffu:
-// gins(ANOTL, N, &lo2);
-// break;
-// default:
-// gins(AXORL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// break;
-// case 0xffffffffu:
-// gins(ANOTL, N, &hi2);
-// break;
-// default:
-// gins(AXORL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-
-// case OAND:
-// switch(lv) {
-// case 0:
-// gins(AMOVL, ncon(0), &lo2);
-// break;
-// default:
-// gmove(&lo1, &lo2);
-// if(lv != 0xffffffffu)
-// gins(AANDL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// gins(AMOVL, ncon(0), &hi2);
-// break;
-// default:
-// gmove(&hi1, &hi2);
-// if(hv != 0xffffffffu)
-// gins(AANDL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-
-// case OOR:
-// switch(lv) {
-// case 0:
-// gmove(&lo1, &lo2);
-// break;
-// case 0xffffffffu:
-// gins(AMOVL, ncon(0xffffffffu), &lo2);
-// break;
-// default:
-// gmove(&lo1, &lo2);
-// gins(AORL, ncon(lv), &lo2);
-// break;
-// }
-// switch(hv) {
-// case 0:
-// gmove(&hi1, &hi2);
-// break;
-// case 0xffffffffu:
-// gins(AMOVL, ncon(0xffffffffu), &hi2);
-// break;
-// default:
-// gmove(&hi1, &hi2);
-// gins(AORL, ncon(hv), &hi2);
-// break;
-// }
-// break;
-// }
-// splitclean();
-// splitclean();
-// goto out;
-// }
- regalloc(&n1, lo1.type, N);
- gins(AMOVW, &lo1, &al);
- gins(AMOVW, &hi1, &ah);
- gins(AMOVW, &lo2, &n1);
- gins(optoas(n->op, lo1.type), &n1, &al);
- gins(AMOVW, &hi2, &n1);
- gins(optoas(n->op, lo1.type), &n1, &ah);
- regfree(&n1);
- break;
- }
- if(is64(r->type))
- splitclean();
- splitclean();
-
- split64(res, &lo1, &hi1);
- gins(AMOVW, &al, &lo1);
- gins(AMOVW, &ah, &hi1);
- splitclean();
-
-//out:
- regfree(&al);
- regfree(&ah);
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
-{
- Node lo1, hi1, lo2, hi2, r1, r2;
- Prog *br;
- Type *t;
-
- split64(nl, &lo1, &hi1);
- split64(nr, &lo2, &hi2);
-
- // compare most significant word;
- // if they differ, we're done.
- t = hi1.type;
- regalloc(&r1, types[TINT32], N);
- regalloc(&r2, types[TINT32], N);
- gins(AMOVW, &hi1, &r1);
- gins(AMOVW, &hi2, &r2);
- gcmp(ACMP, &r1, &r2);
- regfree(&r1);
- regfree(&r2);
-
- br = P;
- switch(op) {
- default:
- fatal("cmp64 %O %T", op, t);
- case OEQ:
- // cmp hi
- // bne L
- // cmp lo
- // beq to
- // L:
- br = gbranch(ABNE, T, -likely);
- break;
- case ONE:
- // cmp hi
- // bne to
- // cmp lo
- // bne to
- patch(gbranch(ABNE, T, likely), to);
- break;
- case OGE:
- case OGT:
- // cmp hi
- // bgt to
- // blt L
- // cmp lo
- // bge to (or bgt to)
- // L:
- patch(gbranch(optoas(OGT, t), T, likely), to);
- br = gbranch(optoas(OLT, t), T, -likely);
- break;
- case OLE:
- case OLT:
- // cmp hi
- // blt to
- // bgt L
- // cmp lo
- // ble to (or jlt to)
- // L:
- patch(gbranch(optoas(OLT, t), T, likely), to);
- br = gbranch(optoas(OGT, t), T, -likely);
- break;
- }
-
- // compare least significant word
- t = lo1.type;
- regalloc(&r1, types[TINT32], N);
- regalloc(&r2, types[TINT32], N);
- gins(AMOVW, &lo1, &r1);
- gins(AMOVW, &lo2, &r2);
- gcmp(ACMP, &r1, &r2);
- regfree(&r1);
- regfree(&r2);
-
- // jump again
- patch(gbranch(optoas(op, t), T, likely), to);
-
- // point first branch down here if appropriate
- if(br != P)
- patch(br, pc);
-
- splitclean();
- splitclean();
-}
diff --git a/src/cmd/new5g/cgen64.go b/src/cmd/5g/cgen64.go
index f89c21cf08..f89c21cf08 100644
--- a/src/cmd/new5g/cgen64.go
+++ b/src/cmd/5g/cgen64.go
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
deleted file mode 100644
index aebdcab712..0000000000
--- a/src/cmd/5g/doc.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-5g is the version of the gc compiler for the ARM.
-The $GOARCH for these tools is arm.
-
-It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
deleted file mode 100644
index c4d74f0a71..0000000000
--- a/src/cmd/5g/galign.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int thechar = '5';
-char* thestring = "arm";
-LinkArch* thelinkarch = &linkarm;
-
-void
-linkarchinit(void)
-{
-}
-
-vlong MAXWIDTH = (1LL<<32) - 1;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- {"int", TINT, TINT32},
- {"uint", TUINT, TUINT32},
- {"uintptr", TUINTPTR, TUINT32},
- {0}
-};
-
-void
-betypeinit(void)
-{
- widthptr = 4;
- widthint = 4;
- widthreg = 4;
-
- listinit5();
-}
-
-void
-main(int argc, char **argv)
-{
- thearch.thechar = thechar;
- thearch.thestring = thestring;
- thearch.thelinkarch = thelinkarch;
- thearch.typedefs = typedefs;
- thearch.REGSP = REGSP;
- thearch.REGCTXT = REGCTXT;
- thearch.MAXWIDTH = MAXWIDTH;
- thearch.anyregalloc = anyregalloc;
- thearch.betypeinit = betypeinit;
- thearch.bgen = bgen;
- thearch.cgen = cgen;
- thearch.cgen_call = cgen_call;
- thearch.cgen_callinter = cgen_callinter;
- thearch.cgen_ret = cgen_ret;
- thearch.clearfat = clearfat;
- thearch.defframe = defframe;
- thearch.excise = excise;
- thearch.expandchecks = expandchecks;
- thearch.gclean = gclean;
- thearch.ginit = ginit;
- thearch.gins = gins;
- thearch.ginscall = ginscall;
- thearch.igen = igen;
- thearch.linkarchinit = linkarchinit;
- thearch.peep = peep;
- thearch.proginfo = proginfo;
- thearch.regalloc = regalloc;
- thearch.regfree = regfree;
- thearch.regtyp = regtyp;
- thearch.sameaddr = sameaddr;
- thearch.smallindir = smallindir;
- thearch.stackaddr = stackaddr;
- thearch.excludedregs = excludedregs;
- thearch.RtoB = RtoB;
- thearch.FtoB = RtoB;
- thearch.BtoR = BtoR;
- thearch.BtoF = BtoF;
- thearch.optoas = optoas;
- thearch.doregbits = doregbits;
- thearch.regnames = regnames;
-
- gcmain(argc, argv);
-}
diff --git a/src/cmd/new5g/galign.go b/src/cmd/5g/galign.go
index d2eeeab456..d2eeeab456 100644
--- a/src/cmd/new5g/galign.go
+++ b/src/cmd/5g/galign.go
diff --git a/src/cmd/new5g/gg.go b/src/cmd/5g/gg.go
index 7a7fb3b774..7a7fb3b774 100644
--- a/src/cmd/new5g/gg.go
+++ b/src/cmd/5g/gg.go
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
deleted file mode 100644
index b12c7e2561..0000000000
--- a/src/cmd/5g/gg.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#include "../gc/go.h"
-#include "../5l/5.out.h"
-
-enum
-{
- REGALLOC_R0 = REG_R0,
- REGALLOC_RMAX = REGEXT,
- REGALLOC_F0 = REG_F0,
- REGALLOC_FMAX = FREGEXT,
-};
-
-EXTERN uchar reg[REGALLOC_FMAX+1];
-extern long unmappedzero;
-
-/*
- * gen.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_dcl(Node*);
-int needconvert(Type*, Type*);
-void genconv(Type*, Type*);
-void allocparams(void);
-void checklabels(void);
-void ginscall(Node*, int);
-
-/*
- * cgen
- */
-void agen(Node*, Node*);
-Prog* cgenindex(Node *, Node *, int);
-void igen(Node*, Node*, Node*);
-void agenr(Node *n, Node *a, Node *res);
-vlong fieldoffset(Type*, Node*);
-void sgen(Node*, Node*, int64);
-void gmove(Node*, Node*);
-Prog* gins(int, Node*, Node*);
-int samaddr(Node*, Node*);
-void raddr(Node *n, Prog *p);
-Prog* gcmp(int, Node*, Node*);
-Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
-Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-void cgen_hmul(Node*, Node*, Node*);
-void cgen_shift(int, int, Node*, Node*, Node*);
-int componentgen(Node*, Node*);
-
-/*
- * cgen64.c
- */
-void cmp64(Node*, Node*, int, int, Prog*);
-void cgen64(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 buildtxt(void);
-Plist* newplist(void);
-int isfat(Type*);
-int dotaddable(Node*, Node*);
-void sudoclean(void);
-int sudoaddable(int, Node*, Addr*, int*);
-void afunclit(Addr*, Node*);
-void datagostring(Strlit*, Addr*);
-void split64(Node*, Node*, Node*);
-void splitclean(void);
-Node* ncon(uint32 i);
-void gtrack(Sym*);
-
-/*
- * obj.c
- */
-void datastring(char*, int, Addr*);
-
-/*
- * list.c
- */
-void listinit(void);
-
-void zaddr(Biobuf*, Addr*, int, int);
-
-void afunclit(Addr*, Node*);
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node*, int, int, Prog*);
-void cgen(Node*, Node*);
-void cgen_call(Node*, int);
-void cgen_callinter(Node*, Node*, int);
-void cgen_ret(Node*);
-void clearfat(Node*);
-void clearp(Prog*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int, char*);
-int dgostrlitptr(Sym*, int, Strlit*);
-int dsname(Sym*, int, char*, int);
-int dsymptr(Sym*, int, Sym*, int);
-void dumpdata(void);
-void dumpit(char*, Flow*, int);
-void excise(Flow*);
-void expandchecks(Prog*);
-void fixautoused(Prog*);
-void gclean(void);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void ggloblnod(Node *nam);
-void ggloblsym(Sym *s, int32 width, int8 flags);
-void ginit(void);
-Prog* gins(int, Node*, Node*);
-void ginscall(Node*, int);
-Prog* gjmp(Prog*);
-void gtrack(Sym*);
-void gused(Node*);
-void igen(Node*, Node*, Node*);
-int isfat(Type*);
-void linkarchinit(void);
-void markautoused(Prog*);
-void naddr(Node*, Addr*, int);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void patch(Prog*, Prog*);
-void proginfo(ProgInfo*, Prog*);
-void regalloc(Node*, Type*, Node*);
-void regfree(Node*);
-void regopt(Prog*);
-int regtyp(Addr*);
-int sameaddr(Addr*, Addr*);
-int smallindir(Addr*, Addr*);
-int stackaddr(Addr*);
-Prog* unpatch(Prog*);
-
-/*
- * reg.c
- */
-uint64 excludedregs(void);
-uint64 RtoB(int);
-uint64 FtoB(int);
-int BtoR(uint64);
-int BtoF(uint64);
-uint64 doregbits(int);
-char** regnames(int*);
-
-/*
- * peep.c
- */
-void peep(Prog*);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
deleted file mode 100644
index 62b9beadb0..0000000000
--- a/src/cmd/5g/ggen.c
+++ /dev/null
@@ -1,751 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#undef EXTERN
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0);
-
-void
-defframe(Prog *ptxt)
-{
- uint32 frame, r0;
- Prog *p;
- vlong hi, lo;
- NodeList *l;
- Node *n;
-
- // fill in argument size, stack size
- ptxt->to.type = TYPE_TEXTSIZE;
- ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
- frame = rnd(stksize+maxarg, widthreg);
- ptxt->to.offset = frame;
-
- // insert code to contain ambiguously live variables
- // so that garbage collector only sees initialized values
- // when it looks for pointers.
- p = ptxt;
- lo = hi = 0;
- r0 = 0;
- for(l=curfn->dcl; l != nil; l = l->next) {
- n = l->n;
- if(!n->needzero)
- continue;
- if(n->class != PAUTO)
- fatal("needzero class %d", n->class);
- if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
- fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
- if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) {
- // merge with range we already have
- lo = rnd(n->xoffset, widthptr);
- continue;
- }
- // zero old range
- p = zerorange(p, frame, lo, hi, &r0);
-
- // set new range
- hi = n->xoffset + n->type->width;
- lo = n->xoffset;
- }
- // zero final range
- zerorange(p, frame, lo, hi, &r0);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0)
-{
- vlong cnt, i;
- Prog *p1;
- Node *f;
-
- cnt = hi - lo;
- if(cnt == 0)
- return p;
- if(*r0 == 0) {
- p = appendpp(p, AMOVW, TYPE_CONST, 0, 0, TYPE_REG, REG_R0, 0);
- *r0 = 1;
- }
- if(cnt < 4*widthptr) {
- for(i = 0; i < cnt; i += widthptr)
- p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REGSP, 4+frame+lo+i);
- } else if(!nacl && (cnt <= 128*widthptr)) {
- p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0);
- p->reg = REGSP;
- p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0);
- f = sysfunc("duffzero");
- naddr(f, &p->to, 1);
- afunclit(&p->to, f);
- p->to.offset = 4*(128-cnt/widthptr);
- } else {
- p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0);
- p->reg = REGSP;
- p = appendpp(p, AADD, TYPE_CONST, 0, cnt, TYPE_REG, REG_R2, 0);
- p->reg = REG_R1;
- p1 = p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REG_R1, 4);
- p->scond |= C_PBIT;
- p = appendpp(p, ACMP, TYPE_REG, REG_R1, 0, TYPE_NONE, 0, 0);
- p->reg = REG_R2;
- p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0);
- patch(p, p1);
- }
- return p;
-}
-
-static Prog*
-appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset)
-{
- Prog *q;
-
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.reg = freg;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.reg = treg;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-/*
- * generate:
- * call f
- * proc=-1 normal call but no return
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- * proc=3 normal call to C pointer (not Go func value)
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node r, r1, con;
- int32 extra;
-
- if(f->type != T) {
- extra = 0;
- if(proc == 1 || proc == 2)
- extra = 2 * widthptr;
- setmaxarg(f->type, extra);
- }
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- case -1: // normal call but no return
- if(f->op == ONAME && f->class == PFUNC) {
- if(f == deferreturn) {
- // Deferred calls will appear to be returning to
- // the BL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction before that return PC.
- // To avoid that instruction being an unrelated instruction,
- // insert a NOP so that we will have the right line number.
- // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0.
- // Use the latter form because the NOP pseudo-instruction
- // would be removed by the linker.
- nodreg(&r, types[TINT], REG_R0);
- p = gins(AAND, &r, &r);
- p->scond = C_SCOND_EQ;
- }
- p = gins(ABL, N, f);
- afunclit(&p->to, f);
- if(proc == -1 || noreturn(p))
- gins(AUNDEF, N, N);
- break;
- }
- nodreg(&r, types[tptr], REG_R7);
- nodreg(&r1, types[tptr], REG_R1);
- gmove(f, &r);
- r.op = OINDREG;
- gmove(&r, &r1);
- r.op = OREGISTER;
- r1.op = OINDREG;
- gins(ABL, &r, &r1);
- break;
-
- case 3: // normal call of c function pointer
- gins(ABL, N, f);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- regalloc(&r, types[tptr], N);
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(AMOVW, &con, &r);
- p = gins(AMOVW, &r, N);
- p->to.type = TYPE_MEM;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- gins(AMOVW, f, &r);
- p = gins(AMOVW, &r, N);
- p->to.type = TYPE_MEM;
- p->to.reg = REGSP;
- p->to.offset = 8;
-
- regfree(&r);
-
- if(proc == 1)
- ginscall(newproc, 0);
- else
- ginscall(deferproc, 0);
-
- if(proc == 2) {
- nodconst(&con, types[TINT32], 0);
- p = gins(ACMP, &con, N);
- p->reg = REG_R0;
- p = gbranch(ABEQ, T, +1);
- cgen_ret(N);
- patch(p, pc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- int r;
- Node *i, *f;
- Node tmpi, nodo, nodr, nodsp;
- Prog *p;
-
- i = n->left;
- if(i->op != ODOTINTER)
- fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
- f = i->right; // field
- if(f->op != ONAME)
- fatal("cgen_callinter: not ONAME %O", f->op);
-
- i = i->left; // interface
-
- // Release res register during genlist and cgen,
- // which might have their own function calls.
- r = -1;
- if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
- r = res->val.u.reg;
- reg[r]--;
- }
-
- if(!i->addable) {
- tempname(&tmpi, i->type);
- cgen(i, &tmpi);
- i = &tmpi;
- }
-
- genlist(n->list); // args
- if(r >= 0)
- reg[r]++;
-
- regalloc(&nodr, types[tptr], res);
- regalloc(&nodo, types[tptr], &nodr);
- nodo.op = OINDREG;
-
- agen(i, &nodr); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], REGSP);
- nodsp.xoffset = widthptr;
- if(proc != 0)
- nodsp.xoffset += 2 * widthptr; // leave room for size & fn
- nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // {4 or 12}(SP) = 4(REG) -- i.data
-
- nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
- cgen_checknil(&nodr); // in case offset is huge
-
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
-
- if(proc == 0) {
- // plain call: use direct c function pointer - more efficient
- cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
- nodr.op = OINDREG;
- proc = 3;
- } else {
- // go/defer. generate go func value.
- p = gins(AMOVW, &nodo, &nodr);
- p->from.type = TYPE_ADDR; // REG = &(20+offset(REG)) -- i.tab->fun[f]
- }
-
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-}
-
-/*
- * generate function call;
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_call(Node *n, int proc)
-{
- Type *t;
- Node nod, afun;
-
- if(n == N)
- return;
-
- if(n->left->ullman >= UINF) {
- // if name involves a fn call
- // precompute the address of the fn
- tempname(&afun, types[tptr]);
- cgen(n->left, &afun);
- }
-
- genlist(n->list); // assign the args
- t = n->left->type;
-
- // call tempname pointer
- if(n->left->ullman >= UINF) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, &afun);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- goto ret;
- }
-
- // call pointer
- if(n->left->op != ONAME || n->left->class != PFUNC) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, n->left);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- goto ret;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-
-
-ret:
- ;
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = return value from call.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
- Node nod;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(t->etype == TPTR32 || t->etype == TPTR64)
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_callret: nil");
-
- memset(&nod, 0, sizeof(nod));
- nod.op = OINDREG;
- nod.val.u.reg = REGSP;
- nod.addable = 1;
-
- nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
- nod.type = fp->type;
- cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
- Node nod1, nod2;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_aret: nil");
-
- memset(&nod1, 0, sizeof(nod1));
- nod1.op = OINDREG;
- nod1.val.u.reg = REGSP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- agen(&nod1, &nod2);
- gins(AMOVW, &nod2, res);
- regfree(&nod2);
- } else
- agen(&nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- Prog *p;
-
- if(n != N)
- genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- genlist(curfn->exit);
- p = gins(ARET, N, N);
- if(n != N && n->op == ORETJMP) {
- p->to.name = NAME_EXTERN;
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(n->left->sym);
- }
-}
-
-/*
- * generate high multiply
- * res = (nl * nr) >> wordsize
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
- int w;
- Node n1, n2, *tmp;
- Type *t;
- Prog *p;
-
- if(nl->ullman < nr->ullman) {
- tmp = nl;
- nl = nr;
- nr = tmp;
- }
- t = nl->type;
- w = t->width * 8;
- regalloc(&n1, t, res);
- cgen(nl, &n1);
- regalloc(&n2, t, N);
- cgen(nr, &n2);
- switch(simtype[t->etype]) {
- case TINT8:
- case TINT16:
- gins(optoas(OMUL, t), &n2, &n1);
- gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
- break;
- case TUINT8:
- case TUINT16:
- gins(optoas(OMUL, t), &n2, &n1);
- gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
- break;
- case TINT32:
- case TUINT32:
- // perform a long multiplication.
- if(issigned[t->etype])
- p = gins(AMULL, &n2, N);
- else
- p = gins(AMULLU, &n2, N);
- // n2 * n1 -> (n1 n2)
- p->reg = n1.val.u.reg;
- p->to.type = TYPE_REGREG;
- p->to.reg = n1.val.u.reg;
- p->to.offset = n2.val.u.reg;
- break;
- default:
- fatal("cgen_hmul %T", t);
- break;
- }
- cgen(&n1, res);
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, nt, t, lo, hi;
- int w, v;
- Prog *p1, *p2, *p3;
- Type *tr;
- uvlong sc;
-
- USED(bounded);
- if(nl->type->width > 4)
- fatal("cgen_shift %T", nl->type);
-
- w = nl->type->width * 8;
-
- if(op == OLROT) {
- v = mpgetfix(nr->val.u.xval);
- regalloc(&n1, nl->type, res);
- if(w == 32) {
- cgen(nl, &n1);
- gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
- } else {
- regalloc(&n2, nl->type, N);
- cgen(nl, &n2);
- gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
- gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
- regfree(&n2);
- // Ensure sign/zero-extended result.
- gins(optoas(OAS, nl->type), &n1, &n1);
- }
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- if(nr->op == OLITERAL) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc == 0) {
- // nothing to do
- } else if(sc >= nl->type->width*8) {
- if(op == ORSH && issigned[nl->type->etype])
- gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
- else
- gins(AEOR, &n1, &n1);
- } else {
- if(op == ORSH && issigned[nl->type->etype])
- gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
- else if(op == ORSH)
- gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
- else // OLSH
- gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
- }
- if(w < 32 && op == OLSH)
- gins(optoas(OAS, nl->type), &n1, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- tr = nr->type;
- if(tr->width > 4) {
- tempname(&nt, nr->type);
- if(nl->ullman >= nr->ullman) {
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- cgen(nr, &nt);
- n1 = nt;
- } else {
- cgen(nr, &nt);
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- }
- split64(&nt, &lo, &hi);
- regalloc(&n1, types[TUINT32], N);
- regalloc(&n3, types[TUINT32], N);
- gmove(&lo, &n1);
- gmove(&hi, &n3);
- splitclean();
- gins(ATST, &n3, N);
- nodconst(&t, types[TUINT32], w);
- p1 = gins(AMOVW, &t, &n1);
- p1->scond = C_SCOND_NE;
- tr = types[TUINT32];
- regfree(&n3);
- } else {
- if(nl->ullman >= nr->ullman) {
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- } else {
- regalloc(&n1, nr->type, N);
- cgen(nr, &n1);
- regalloc(&n2, nl->type, res);
- cgen(nl, &n2);
- }
- }
-
- // test for shift being 0
- gins(ATST, &n1, N);
- p3 = gbranch(ABEQ, T, -1);
-
- // test and fix up large shifts
- // TODO: if(!bounded), don't emit some of this.
- regalloc(&n3, tr, N);
- nodconst(&t, types[TUINT32], w);
- gmove(&t, &n3);
- gcmp(ACMP, &n1, &n3);
- if(op == ORSH) {
- if(issigned[nl->type->etype]) {
- p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
- } else {
- p1 = gins(AEOR, &n2, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
- }
- p1->scond = C_SCOND_HS;
- p2->scond = C_SCOND_LO;
- } else {
- p1 = gins(AEOR, &n2, &n2);
- p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
- p1->scond = C_SCOND_HS;
- p2->scond = C_SCOND_LO;
- }
- regfree(&n3);
-
- patch(p3, pc);
- // Left-shift of smaller word must be sign/zero-extended.
- if(w < 32 && op == OLSH)
- gins(optoas(OAS, nl->type), &n2, &n2);
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-}
-
-void
-clearfat(Node *nl)
-{
- uint32 w, c, q;
- Node dst, nc, nz, end, r0, r1, *f;
- Prog *p, *pl;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
- w = nl->type->width;
- // Avoid taking the address for simple enough types.
- if(componentgen(N, nl))
- return;
-
- c = w % 4; // bytes
- q = w / 4; // quads
-
- r0.op = OREGISTER;
- r0.val.u.reg = REGALLOC_R0;
- r1.op = OREGISTER;
- r1.val.u.reg = REGALLOC_R0 + 1;
- regalloc(&dst, types[tptr], &r1);
- agen(nl, &dst);
- nodconst(&nc, types[TUINT32], 0);
- regalloc(&nz, types[TUINT32], &r0);
- cgen(&nc, &nz);
-
- if(q > 128) {
- regalloc(&end, types[tptr], N);
- p = gins(AMOVW, &dst, &end);
- p->from.type = TYPE_ADDR;
- p->from.offset = q*4;
-
- p = gins(AMOVW, &nz, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = 4;
- p->scond |= C_PBIT;
- pl = p;
-
- p = gins(ACMP, &dst, N);
- raddr(&end, p);
- patch(gbranch(ABNE, T, 0), pl);
-
- regfree(&end);
- } else if(q >= 4 && !nacl) {
- f = sysfunc("duffzero");
- p = gins(ADUFFZERO, N, f);
- afunclit(&p->to, f);
- // 4 and 128 = magic constants: see ../../runtime/asm_arm.s
- p->to.offset = 4*(128-q);
- } else
- while(q > 0) {
- p = gins(AMOVW, &nz, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-//print("1. %P\n", p);
- q--;
- }
-
- while(c > 0) {
- p = gins(AMOVB, &nz, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = 1;
- p->scond |= C_PBIT;
-//print("2. %P\n", p);
- c--;
- }
- regfree(&dst);
- regfree(&nz);
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
- int reg;
- Prog *p, *p1;
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as != ACHECKNIL)
- continue;
- if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
- warnl(p->lineno, "generated nil check");
- if(p->from.type != TYPE_REG)
- fatal("invalid nil check %P", p);
- reg = p->from.reg;
- // check is
- // CMP arg, $0
- // MOV.EQ arg, 0(arg)
- p1 = mal(sizeof *p1);
- clearp(p1);
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
- p1->pc = 9999;
- p1->as = AMOVW;
- p1->from.type = TYPE_REG;
- p1->from.reg = reg;
- p1->to.type = TYPE_MEM;
- p1->to.reg = reg;
- p1->to.offset = 0;
- p1->scond = C_SCOND_EQ;
- p->as = ACMP;
- p->from.type = TYPE_CONST;
- p->from.reg = 0;
- p->from.offset = 0;
- p->reg = reg;
- }
-}
diff --git a/src/cmd/new5g/ggen.go b/src/cmd/5g/ggen.go
index 3b007d8484..3b007d8484 100644
--- a/src/cmd/new5g/ggen.go
+++ b/src/cmd/5g/ggen.go
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
deleted file mode 100644
index bdb70270a8..0000000000
--- a/src/cmd/5g/gsubr.c
+++ /dev/null
@@ -1,1527 +0,0 @@
-// Derived from Inferno utils/5c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/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 "../../runtime/funcdata.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 5l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-long unmappedzero = 4096;
-
-static int resvd[] =
-{
- 9, // reserved for m
- 10, // reserved for g
- REGSP, // reserved for SP
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 0;
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-}
-
-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\n", i);
-}
-
-int
-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;
-}
-
-uintptr regpc[REGALLOC_FMAX+1];
-
-/*
- * 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, fixfree, floatfree;
-
- if(0 && debug['r']) {
- fixfree = 0;
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
- fixfree++;
- floatfree = 0;
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- floatfree++;
- print("regalloc fix %d float %d\n", fixfree, floatfree);
- }
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
- if(is64(t))
- fatal("regalloc: 64 bit type %T");
-
- switch(et) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TPTR32:
- case TBOOL:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX)
- goto out;
- }
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0) {
- regpc[i] = (uintptr)getcallerpc(&n);
- goto out;
- }
- print("registers allocated at\n");
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- print("%d %p\n", i, regpc[i]);
- fatal("out of fixed registers");
- goto err;
-
- case TFLOAT32:
- case TFLOAT64:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX)
- goto out;
- }
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- goto out;
- fatal("out of floating point registers");
- goto err;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- tempname(n, t);
- return;
- }
- yyerror("regalloc: unknown type %T", t);
-
-err:
- nodreg(n, t, REG_R0);
- return;
-
-out:
- reg[i]++;
- nodreg(n, t, i);
-}
-
-void
-regfree(Node *n)
-{
- int i, fixfree, floatfree;
-
- if(0 && debug['r']) {
- fixfree = 0;
- for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
- fixfree++;
- floatfree = 0;
- for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
- if(reg[i] == 0)
- floatfree++;
- print("regalloc fix %d float %d\n", fixfree, floatfree);
- }
-
- if(n->op == ONAME)
- return;
- if(n->op != OREGISTER && n->op != OINDREG)
- fatal("regfree: not a register");
- i = n->val.u.reg;
- if(i == REGSP)
- return;
- if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
- fatal("regfree: reg out of range");
- if(reg[i] <= 0)
- fatal("regfree: reg %R not allocated", i);
- reg[i]--;
- if(reg[i] == 0)
- regpc[i] = 0;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
- static Node n;
-
- if(n.type == T)
- nodconst(&n, types[TUINT32], 0);
- mpmovecfix(n.val.u.xval, i);
- return &n;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
- Node n1;
- int64 i;
-
- if(!is64(n->type))
- fatal("split64 %T", n->type);
-
- if(nsclean >= nelem(sclean))
- fatal("split64 clean");
- sclean[nsclean].op = OEMPTY;
- nsclean++;
- switch(n->op) {
- default:
- switch(n->op) {
- default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- break;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- n = &n1;
- }
- break;
- case OINDREG:
- // nothing
- break;
- }
- *lo = *n;
- *hi = *n;
- lo->type = types[TUINT32];
- if(n->type->etype == TINT64)
- hi->type = types[TINT32];
- else
- hi->type = types[TUINT32];
- hi->xoffset += 4;
- break;
-
- case OLITERAL:
- convconst(&n1, n->type, &n->val);
- i = mpgetfix(n1.val.u.xval);
- nodconst(lo, types[TUINT32], (uint32)i);
- i >>= 32;
- if(n->type->etype == TINT64)
- nodconst(hi, types[TINT32], (int32)i);
- else
- nodconst(hi, types[TUINT32], (uint32)i);
- break;
- }
-}
-
-void
-splitclean(void)
-{
- if(nsclean <= 0)
- fatal("splitclean");
- nsclean--;
- if(sclean[nsclean].op != OEMPTY)
- regfree(&sclean[nsclean]);
-}
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int); */
-
-void
-gmove(Node *f, Node *t)
-{
- int a, ft, tt, fa, ta;
- Type *cvt;
- Node r1, r2, flo, fhi, tlo, thi, con;
- Prog *p1;
-
- if(debug['M'])
- print("gmove %N -> %N\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;
- // except 64-bit, which always copies via registers anyway.
- if(!is64(f->type) && !is64(t->type) && 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 TINT16:
- case TINT8:
- convconst(&con, types[TINT32], &f->val);
- regalloc(&r1, con.type, t);
- gins(AMOVW, &con, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-
- case TUINT16:
- case TUINT8:
- convconst(&con, types[TUINT32], &f->val);
- regalloc(&r1, con.type, t);
- gins(AMOVW, &con, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
- }
-
- f = &con;
- ft = simsimtype(con.type);
-
- // constants can't move directly to memory
- if(ismem(t) && !is64(t->type)) 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:
- goto fatal;
-
- /*
- * integer copy and truncate
- */
- case CASE(TINT8, TINT8): // same size
- if(!ismem(f)) {
- a = AMOVB;
- break;
- }
- case CASE(TUINT8, TINT8):
- case CASE(TINT16, TINT8): // truncate
- case CASE(TUINT16, TINT8):
- case CASE(TINT32, TINT8):
- case CASE(TUINT32, TINT8):
- a = AMOVBS;
- break;
-
- case CASE(TUINT8, TUINT8):
- if(!ismem(f)) {
- a = AMOVB;
- break;
- }
- case CASE(TINT8, TUINT8):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- a = AMOVBU;
- break;
-
- case CASE(TINT64, TINT8): // truncate low word
- case CASE(TUINT64, TINT8):
- a = AMOVBS;
- goto trunc64;
-
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- a = AMOVBU;
- goto trunc64;
-
- case CASE(TINT16, TINT16): // same size
- if(!ismem(f)) {
- a = AMOVH;
- break;
- }
- case CASE(TUINT16, TINT16):
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- a = AMOVHS;
- break;
-
- case CASE(TUINT16, TUINT16):
- if(!ismem(f)) {
- a = AMOVH;
- break;
- }
- case CASE(TINT16, TUINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- a = AMOVHU;
- break;
-
- case CASE(TINT64, TINT16): // truncate low word
- case CASE(TUINT64, TINT16):
- a = AMOVHS;
- goto trunc64;
-
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- a = AMOVHU;
- goto trunc64;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- a = AMOVW;
- break;
-
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- split64(f, &flo, &fhi);
- regalloc(&r1, t->type, N);
- gins(AMOVW, &flo, &r1);
- gins(AMOVW, &r1, t);
- regfree(&r1);
- splitclean();
- return;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- split64(f, &flo, &fhi);
- split64(t, &tlo, &thi);
- regalloc(&r1, flo.type, N);
- regalloc(&r2, fhi.type, N);
- gins(AMOVW, &flo, &r1);
- gins(AMOVW, &fhi, &r2);
- gins(AMOVW, &r1, &tlo);
- gins(AMOVW, &r2, &thi);
- regfree(&r1);
- regfree(&r2);
- splitclean();
- splitclean();
- return;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVBS;
- goto rdst;
- case CASE(TINT8, TINT64): // convert via int32
- case CASE(TINT8, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBU;
- goto rdst;
- case CASE(TUINT8, TINT64): // convert via uint32
- case CASE(TUINT8, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVHS;
- goto rdst;
- case CASE(TINT16, TINT64): // convert via int32
- case CASE(TINT16, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVHU;
- goto rdst;
- case CASE(TUINT16, TINT64): // convert via uint32
- case CASE(TUINT16, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- split64(t, &tlo, &thi);
- regalloc(&r1, tlo.type, N);
- regalloc(&r2, thi.type, N);
- gmove(f, &r1);
- p1 = gins(AMOVW, &r1, &r2);
- p1->from.type = TYPE_SHIFT;
- p1->from.offset = 2 << 5 | 31 << 7 | (r1.val.u.reg&15); // r1->31
- p1->from.reg = 0;
-//print("gmove: %P\n", p1);
- gins(AMOVW, &r1, &tlo);
- gins(AMOVW, &r2, &thi);
- regfree(&r1);
- regfree(&r2);
- splitclean();
- return;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- split64(t, &tlo, &thi);
- gmove(f, &tlo);
- regalloc(&r1, thi.type, N);
- gins(AMOVW, ncon(0), &r1);
- gins(AMOVW, &r1, &thi);
- regfree(&r1);
- splitclean();
- return;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TUINT8):
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TUINT16):
- case CASE(TFLOAT32, TINT32):
- case CASE(TFLOAT32, TUINT32):
-// case CASE(TFLOAT32, TUINT64):
-
- case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TUINT8):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TUINT16):
- case CASE(TFLOAT64, TINT32):
- case CASE(TFLOAT64, TUINT32):
-// case CASE(TFLOAT64, TUINT64):
- fa = AMOVF;
- a = AMOVFW;
- if(ft == TFLOAT64) {
- fa = AMOVD;
- a = AMOVDW;
- }
- ta = AMOVW;
- switch(tt) {
- case TINT8:
- ta = AMOVBS;
- break;
- case TUINT8:
- ta = AMOVBU;
- break;
- case TINT16:
- ta = AMOVHS;
- break;
- case TUINT16:
- ta = AMOVHU;
- break;
- }
-
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1); // load to fpu
- p1 = gins(a, &r1, &r1); // convert to w
- switch(tt) {
- case TUINT8:
- case TUINT16:
- case TUINT32:
- p1->scond |= C_UBIT;
- }
- gins(AMOVW, &r1, &r2); // copy to cpu
- gins(ta, &r2, t); // store
- regfree(&r1);
- regfree(&r2);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT32):
- case CASE(TINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT32):
- case CASE(TINT8, TFLOAT64):
- case CASE(TUINT8, TFLOAT64):
- case CASE(TINT16, TFLOAT64):
- case CASE(TUINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT64):
- case CASE(TUINT32, TFLOAT64):
- fa = AMOVW;
- switch(ft) {
- case TINT8:
- fa = AMOVBS;
- break;
- case TUINT8:
- fa = AMOVBU;
- break;
- case TINT16:
- fa = AMOVHS;
- break;
- case TUINT16:
- fa = AMOVHU;
- break;
- }
- a = AMOVWF;
- ta = AMOVF;
- if(tt == TFLOAT64) {
- a = AMOVWD;
- ta = AMOVD;
- }
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1); // load to cpu
- gins(AMOVW, &r1, &r2); // copy to fpu
- p1 = gins(a, &r2, &r2); // convert
- switch(ft) {
- case TUINT8:
- case TUINT16:
- case TUINT32:
- p1->scond |= C_UBIT;
- }
- gins(ta, &r2, t); // store
- regfree(&r1);
- regfree(&r2);
- return;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- fatal("gmove UINT64, TFLOAT not implemented");
- return;
-
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- a = AMOVF;
- break;
-
- case CASE(TFLOAT64, TFLOAT64):
- a = AMOVD;
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- regalloc(&r1, types[TFLOAT64], t);
- gins(AMOVF, f, &r1);
- gins(AMOVFD, &r1, &r1);
- gins(AMOVD, &r1, t);
- regfree(&r1);
- return;
-
- case CASE(TFLOAT64, TFLOAT32):
- regalloc(&r1, types[TFLOAT64], t);
- gins(AMOVD, f, &r1);
- gins(AMOVDF, &r1, &r1);
- gins(AMOVF, &r1, t);
- regfree(&r1);
- return;
- }
-
- gins(a, f, t);
- return;
-
-rdst:
- // TODO(kaib): we almost always require a register dest anyway, this can probably be
- // removed.
- // 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;
-
-trunc64:
- // truncate 64 bit integer
- split64(f, &flo, &fhi);
- regalloc(&r1, t->type, N);
- gins(a, &flo, &r1);
- gins(a, &r1, t);
- regfree(&r1);
- splitclean();
- return;
-
-fatal:
- // should not happen
- fatal("gmove %N -> %N", f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-// Node nod;
-// int32 v;
- Prog *p;
- Addr af, at;
-
- if(f != N && f->op == OINDEX) {
- fatal("gins OINDEX not implemented");
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(f->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
- }
- if(t != N && t->op == OINDEX) {
- fatal("gins OINDEX not implemented");
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(t->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
- }
-
- 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(debug['g'])
- print("%P\n", p);
- return p;
-}
-
-/*
- * insert n into reg slot of p
- */
-void
-raddr(Node *n, Prog *p)
-{
- Addr a;
-
- naddr(n, &a, 1);
- if(a.type != TYPE_REG) {
- if(n)
- fatal("bad in raddr: %O", n->op);
- else
- fatal("bad in raddr: <null>");
- p->reg = 0;
- } else
- p->reg = a.reg;
-}
-
-/* generate a comparison
-TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
- */
-Prog*
-gcmp(int as, Node *lhs, Node *rhs)
-{
- Prog *p;
-
- if(lhs->op != OREGISTER)
- fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
-
- p = gins(as, rhs, N);
- raddr(lhs, p);
- return p;
-}
-
-/* generate a constant shift
- * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
-*/
-Prog*
-gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
-{
- Prog *p;
-
- if(sval <= 0 || sval > 32)
- fatal("bad shift value: %d", sval);
-
- sval = sval&0x1f;
-
- p = gins(as, N, rhs);
- p->from.type = TYPE_SHIFT;
- p->from.offset = stype | sval<<7 | (lhs->val.u.reg&15);
- return p;
-}
-
-/* generate a register shift
-*/
-Prog *
-gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
-{
- Prog *p;
- p = gins(as, N, rhs);
- p->from.type = TYPE_SHIFT;
- p->from.offset = stype | (reg->val.u.reg&15) << 8 | 1<<4 | (lhs->val.u.reg&15);
- return p;
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
- int a;
-
- if(t == T)
- fatal("optoas: t is nil");
-
- a = AXXX;
- switch(CASE(op, simtype[t->etype])) {
- default:
- fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
- break;
-
-/* case CASE(OADDR, TPTR32):
- a = ALEAL;
- break;
-
- case CASE(OADDR, TPTR64):
- a = ALEAQ;
- break;
-*/
- // TODO(kaib): make sure the conditional branches work on all edge cases
- 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):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = ABLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = ABLO;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = ABLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = ABLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- case CASE(OGT, TFLOAT32):
- case CASE(OGT, TFLOAT64):
- a = ABGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- a = ABHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- case CASE(OGE, TFLOAT32):
- case CASE(OGE, TFLOAT64):
- a = ABGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- a = ABHS;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMP;
- break;
-
- case CASE(OCMP, TFLOAT32):
- a = ACMPF;
- break;
-
- case CASE(OCMP, TFLOAT64):
- a = ACMPD;
- break;
-
- case CASE(OAS, TBOOL):
- a = AMOVB;
- break;
-
- case CASE(OAS, TINT8):
- a = AMOVBS;
- break;
-
- case CASE(OAS, TUINT8):
- a = AMOVBU;
- break;
-
- case CASE(OAS, TINT16):
- a = AMOVHS;
- break;
-
- case CASE(OAS, TUINT16):
- a = AMOVHU;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVW;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVF;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVD;
- 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):
- a = AADD;
- break;
-
- case CASE(OADD, TFLOAT32):
- a = AADDF;
- break;
-
- case CASE(OADD, TFLOAT64):
- a = AADDD;
- 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):
- a = ASUB;
- break;
-
- case CASE(OSUB, TFLOAT32):
- a = ASUBF;
- break;
-
- case CASE(OSUB, TFLOAT64):
- a = ASUBD;
- 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):
- a = ARSB;
- 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):
- 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):
- a = AORR;
- 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):
- a = AEOR;
- 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):
- a = ASLL;
- break;
-
- case CASE(ORSH, TUINT8):
- case CASE(ORSH, TUINT16):
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASRL;
- break;
-
- case CASE(ORSH, TINT8):
- case CASE(ORSH, TINT16):
- case CASE(ORSH, TINT32):
- a = ASRA;
- break;
-
- case CASE(OMUL, TUINT8):
- case CASE(OMUL, TUINT16):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AMULU;
- break;
-
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TINT32):
- a = AMUL;
- break;
-
- case CASE(OMUL, TFLOAT32):
- a = AMULF;
- break;
-
- case CASE(OMUL, TFLOAT64):
- a = AMULD;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(ODIV, TUINT16):
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- a = ADIVU;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(ODIV, TINT16):
- case CASE(ODIV, TINT32):
- a = ADIV;
- break;
-
- case CASE(OMOD, TUINT8):
- case CASE(OMOD, TUINT16):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = AMODU;
- break;
-
- case CASE(OMOD, TINT8):
- case CASE(OMOD, TINT16):
- case CASE(OMOD, TINT32):
- a = AMOD;
- break;
-
-// case CASE(OEXTEND, TINT16):
-// a = ACWD;
-// break;
-
-// case CASE(OEXTEND, TINT32):
-// a = ACDQ;
-// break;
-
-// case CASE(OEXTEND, TINT64):
-// a = ACQO;
-// break;
-
- case CASE(ODIV, TFLOAT32):
- a = ADIVF;
- break;
-
- case CASE(ODIV, TFLOAT64):
- a = ADIVD;
- break;
-
- }
- return a;
-}
-
-enum
-{
- ODynam = 1<<0,
- OPtrto = 1<<1,
-};
-
-static Node clean[20];
-static int cleani = 0;
-
-void
-sudoclean(void)
-{
- if(clean[cleani-1].op != OEMPTY)
- regfree(&clean[cleani-1]);
- if(clean[cleani-2].op != OEMPTY)
- regfree(&clean[cleani-2]);
- cleani -= 2;
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
- int o;
- int64 oary[10];
- Node *nn;
-
- if(n->op != ODOT)
- return 0;
-
- o = dotoffset(n, oary, &nn);
- if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
- *n1 = *nn;
- n1->type = n->type;
- n1->xoffset += oary[0];
- return 1;
- }
- return 0;
-}
-
-/*
- * 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, int *w)
-{
- int o, i;
- int64 oary[10];
- int64 v;
- Node n1, n2, n3, n4, *nn, *l, *r;
- Node *reg, *reg1;
- Prog *p1, *p2;
- Type *t;
-
- if(n->type == T)
- return 0;
-
- memset(a, 0, sizeof *a);
-
- switch(n->op) {
- case OLITERAL:
- if(!isconst(n, CTINT))
- break;
- v = mpgetfix(n->val.u.xval);
- if(v >= 32000 || v <= -32000)
- break;
- goto lit;
-
- case ODOT:
- case ODOTPTR:
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto odot;
-
- case OINDEX:
- return 0;
- // disabled: OINDEX case is now covered by agenr
- // for a more suitable register allocation pattern.
- if(n->left->type->etype == TSTRING)
- return 0;
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto oindex;
- }
- return 0;
-
-lit:
- switch(as) {
- default:
- return 0;
- case AADD: case ASUB: case AAND: case AORR: case AEOR:
- case AMOVB: case AMOVBS: case AMOVBU:
- case AMOVH: case AMOVHS: case AMOVHU:
- case AMOVW:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- naddr(n, a, 1);
- goto yes;
-
-odot:
- o = dotoffset(n, oary, &nn);
- if(nn == N)
- goto no;
-
- if(nn->addable && o == 1 && oary[0] >= 0) {
- // directly addressable set of DOTs
- n1 = *nn;
- n1.type = n->type;
- n1.xoffset += oary[0];
- naddr(&n1, a, 1);
- goto yes;
- }
-
- regalloc(reg, types[tptr], N);
- n1 = *reg;
- n1.op = OINDREG;
- if(oary[0] >= 0) {
- agen(nn, reg);
- n1.xoffset = oary[0];
- } else {
- cgen(nn, reg);
- cgen_checknil(reg);
- n1.xoffset = -(oary[0]+1);
- }
-
- for(i=1; i<o; i++) {
- if(oary[i] >= 0)
- fatal("can't happen");
- gins(AMOVW, &n1, reg);
- cgen_checknil(reg);
- n1.xoffset = -(oary[i]+1);
- }
-
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- n1.type = n->type;
- naddr(&n1, a, 1);
- goto yes;
-
-oindex:
- l = n->left;
- r = n->right;
- if(l->ullman >= UINF && r->ullman >= UINF)
- goto no;
-
- // set o to type of array
- o = 0;
- if(isptr[l->type->etype]) {
- o += OPtrto;
- if(l->type->type->etype != TARRAY)
- fatal("not ptr ary");
- if(l->type->type->bound < 0)
- o += ODynam;
- } else {
- if(l->type->etype != TARRAY)
- fatal("not ary");
- if(l->type->bound < 0)
- o += ODynam;
- }
-
- *w = n->type->width;
- if(isconst(r, CTINT))
- goto oindex_const;
-
- switch(*w) {
- default:
- goto no;
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- }
-
- // load the array (reg)
- if(l->ullman > r->ullman) {
- regalloc(reg, types[tptr], N);
- if(o & OPtrto) {
- cgen(l, reg);
- cgen_checknil(reg);
- } else
- agen(l, reg);
- }
-
- // load the index (reg1)
- t = types[TUINT32];
- if(issigned[r->type->etype])
- t = types[TINT32];
- regalloc(reg1, t, N);
- regalloc(&n3, types[TINT32], reg1);
- p2 = cgenindex(r, &n3, debug['B'] || n->bounded);
- gmove(&n3, reg1);
- regfree(&n3);
-
- // load the array (reg)
- if(l->ullman <= r->ullman) {
- regalloc(reg, types[tptr], N);
- if(o & OPtrto) {
- cgen(l, reg);
- cgen_checknil(reg);
- } else
- agen(l, reg);
- }
-
- // check bounds
- if(!debug['B']) {
- if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_nel;
- } else {
- if(o & OPtrto)
- nodconst(&n2, types[TUINT32], l->type->type->bound);
- else
- nodconst(&n2, types[TUINT32], l->type->bound);
- }
- regalloc(&n3, n2.type, N);
- cgen(&n2, &n3);
- gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
- regfree(&n3);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_array;
- gmove(&n2, reg);
- }
-
- switch(*w) {
- case 1:
- gins(AADD, reg1, reg);
- break;
- case 2:
- gshift(AADD, reg1, SHIFT_LL, 1, reg);
- break;
- case 4:
- gshift(AADD, reg1, SHIFT_LL, 2, reg);
- break;
- case 8:
- gshift(AADD, reg1, SHIFT_LL, 3, reg);
- break;
- }
-
- naddr(reg1, a, 1);
- a->type = TYPE_MEM;
- a->reg = reg->val.u.reg;
- a->offset = 0;
- goto yes;
-
-oindex_const:
- // index is constant
- // can check statically and
- // can multiply by width statically
-
- regalloc(reg, types[tptr], N);
- if(o & OPtrto) {
- cgen(l, reg);
- cgen_checknil(reg);
- } else
- agen(l, reg);
-
- v = mpgetfix(r->val.u.xval);
- if(o & ODynam) {
- if(!debug['B'] && !n->bounded) {
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT32], v);
- regalloc(&n3, types[TUINT32], N);
- cgen(&n2, &n3);
- regalloc(&n4, n1.type, N);
- cgen(&n1, &n4);
- gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
- regfree(&n4);
- regfree(&n3);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
- ginscall(panicindex, 0);
- patch(p1, pc);
- }
-
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, reg);
- }
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v * (*w);
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- naddr(&n2, a, 1);
- goto yes;
-
-yes:
- return 1;
-
-no:
- sudoclean();
- return 0;
-}
diff --git a/src/cmd/new5g/gsubr.go b/src/cmd/5g/gsubr.go
index 857bafaf64..857bafaf64 100644
--- a/src/cmd/new5g/gsubr.go
+++ b/src/cmd/5g/gsubr.go
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
deleted file mode 100644
index 7fe3e1071f..0000000000
--- a/src/cmd/5g/peep.c
+++ /dev/null
@@ -1,1619 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.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 "../gc/popt.h"
-
-static int xtramodes(Graph*, Flow*, Adr*);
-static int shortprop(Flow *r);
-static int subprop(Flow*);
-static int copyprop(Graph*, Flow*);
-static int copy1(Adr*, Adr*, Flow*, int);
-static int copyas(Adr*, Adr*);
-static int copyau(Adr*, Adr*);
-static int copysub(Adr*, Adr*, Adr*, int);
-static int copysub1(Prog*, Adr*, Adr*, int);
-static Flow* findpre(Flow *r, Adr *v);
-static int copyau1(Prog *p, Adr *v);
-static int isdconst(Addr *a);
-static int isfloatreg(Addr*);
-static int copyu(Prog *p, Adr *v, Adr *s);
-
-static uint32 gactive;
-
-// UNUSED
-int shiftprop(Flow *r);
-void constprop(Adr *c1, Adr *v1, Flow *r);
-void predicate(Graph*);
-
-
-void
-peep(Prog *firstp)
-{
- Flow *r;
- Graph *g;
- Prog *p;
- int t;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
- gactive = 0;
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", g->start, 0);
-
- t = 0;
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ASLL:
- case ASRL:
- case ASRA:
- /*
- * elide shift into TYPE_SHIFT operand of subsequent instruction
- */
-// if(shiftprop(r)) {
-// excise(r);
-// t++;
-// break;
-// }
- break;
-
- case AMOVB:
- case AMOVH:
- case AMOVW:
- case AMOVF:
- case AMOVD:
- if(regtyp(&p->from))
- if(p->from.type == p->to.type && isfloatreg(&p->from) == isfloatreg(&p->to))
- if(p->scond == C_SCOND_NONE) {
- if(copyprop(g, r)) {
- excise(r);
- t++;
- break;
- }
- if(subprop(r) && copyprop(g, r)) {
- excise(r);
- t++;
- break;
- }
- }
- break;
-
- case AMOVHS:
- case AMOVHU:
- case AMOVBS:
- case AMOVBU:
- if(p->from.type == TYPE_REG) {
- if(shortprop(r))
- t++;
- }
- break;
-
- /*
- if(p->scond == C_SCOND_NONE)
- if(regtyp(&p->to))
- if(isdconst(&p->from)) {
- constprop(&p->from, &p->to, r->s1);
- }
- break;
- */
- }
- }
- if(t)
- goto loop1;
-
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AEOR:
- /*
- * EOR -1,x,y => MVN x,y
- */
- if(isdconst(&p->from) && p->from.offset == -1) {
- p->as = AMVN;
- p->from.type = TYPE_REG;
- if(p->reg != 0)
- p->from.reg = p->reg;
- else
- p->from.reg = p->to.reg;
- p->reg = 0;
- }
- break;
- }
- }
-
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVW:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- if(p->from.type == TYPE_MEM && p->from.offset == 0)
- xtramodes(g, r, &p->from);
- else
- if(p->to.type == TYPE_MEM && p->to.offset == 0)
- xtramodes(g, r, &p->to);
- else
- continue;
- break;
-// case ACMP:
-// /*
-// * elide CMP $0,x if calculation of x can set condition codes
-// */
-// if(isdconst(&p->from) || p->from.offset != 0)
-// continue;
-// r2 = r->s1;
-// if(r2 == nil)
-// continue;
-// t = r2->prog->as;
-// switch(t) {
-// default:
-// continue;
-// case ABEQ:
-// case ABNE:
-// case ABMI:
-// case ABPL:
-// break;
-// case ABGE:
-// t = ABPL;
-// break;
-// case ABLT:
-// t = ABMI;
-// break;
-// case ABHI:
-// t = ABNE;
-// break;
-// case ABLS:
-// t = ABEQ;
-// break;
-// }
-// r1 = r;
-// do
-// r1 = uniqp(r1);
-// while (r1 != nil && r1->prog->as == ANOP);
-// if(r1 == nil)
-// continue;
-// p1 = r1->prog;
-// if(p1->to.type != TYPE_REG)
-// continue;
-// if(p1->to.reg != p->reg)
-// if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
-// continue;
-//
-// switch(p1->as) {
-// default:
-// continue;
-// case AMOVW:
-// if(p1->from.type != TYPE_REG)
-// continue;
-// case AAND:
-// case AEOR:
-// case AORR:
-// case ABIC:
-// case AMVN:
-// case ASUB:
-// case ARSB:
-// case AADD:
-// case AADC:
-// case ASBC:
-// case ARSC:
-// break;
-// }
-// p1->scond |= C_SBIT;
-// r2->prog->as = t;
-// excise(r);
-// continue;
- }
- }
-
-// predicate(g);
-
- flowend(g);
-}
-
-int
-regtyp(Adr *a)
-{
- return a->type == TYPE_REG && (REG_R0 <= a->reg && a->reg <= REG_R15 || REG_F0 <= a->reg && a->reg <= REG_F15);
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
- Prog *p;
- Adr *v1, *v2;
- Flow *r;
- int t;
- ProgInfo info;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- if(uniqs(r) == nil)
- break;
- p = r->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
- if(info.flags & Call)
- return 0;
-
- if((info.flags & CanRegRead) && p->to.type == TYPE_REG) {
- info.flags |= RegRead;
- info.flags &= ~(CanRegRead | RightRead);
- p->reg = p->to.reg;
- }
-
- switch(p->as) {
- case AMULLU:
- case AMULA:
- case AMVN:
- return 0;
- }
-
- if((info.flags & (RightRead|RightWrite)) == RightWrite) {
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- if(p->scond == C_SCOND_NONE)
- goto gotit;
- }
-
- if(copyau(&p->from, v2) ||
- copyau1(p, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub1(p, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub1(p, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
- Prog *p;
- Adr *v1, *v2;
-
- USED(g);
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- gactive++;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active == gactive) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = gactive;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == nil) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, nil);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-// UNUSED
-/*
- * The idea is to remove redundant constants.
- * $c1->v1
- * ($c1->v2 s/$c1/v1)*
- * set v1 return
- * The v1->v2 should be eliminated by copy propagation.
- */
-void
-constprop(Adr *c1, Adr *v1, Flow *r)
-{
- Prog *p;
-
- if(debug['P'])
- print("constprop %D->%D\n", c1, v1);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(uniqp(r) == nil) {
- if(debug['P'])
- print("; merge; return\n");
- return;
- }
- if(p->as == AMOVW && copyas(&p->from, c1)) {
- if(debug['P'])
- print("; sub%D/%D", &p->from, v1);
- p->from = *v1;
- } else if(copyu(p, v1, nil) > 1) {
- if(debug['P'])
- print("; %Dset; return\n", v1);
- return;
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- constprop(c1, v1, r->s2);
- }
-}
-
-/*
- * shortprop eliminates redundant zero/sign extensions.
- *
- * MOVBS x, R
- * <no use R>
- * MOVBS R, R'
- *
- * changed to
- *
- * MOVBS x, R
- * ...
- * MOVB R, R' (compiled to mov)
- *
- * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
- */
-static int
-shortprop(Flow *r)
-{
- Prog *p, *p1;
- Flow *r1;
-
- p = r->prog;
- r1 = findpre(r, &p->from);
- if(r1 == nil)
- return 0;
-
- p1 = r1->prog;
- if(p1->as == p->as) {
- // Two consecutive extensions.
- goto gotit;
- }
-
- if(p1->as == AMOVW && isdconst(&p1->from)
- && p1->from.offset >= 0 && p1->from.offset < 128) {
- // Loaded an immediate.
- goto gotit;
- }
-
- return 0;
-
-gotit:
- if(debug['P'])
- print("shortprop\n%P\n%P", p1, p);
- switch(p->as) {
- case AMOVBS:
- case AMOVBU:
- p->as = AMOVB;
- break;
- case AMOVHS:
- case AMOVHU:
- p->as = AMOVH;
- break;
- }
- if(debug['P'])
- print(" => %A\n", p->as);
- return 1;
-}
-
-// UNUSED
-/*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
-
-int
-shiftprop(Flow *r)
-{
- Flow *r1;
- Prog *p, *p1, *p2;
- int n, o;
- Adr a;
-
- p = r->prog;
- if(p->to.type != TYPE_REG) {
- if(debug['P'])
- print("\tBOTCH: result not reg; FAILURE\n");
- return 0;
- }
- n = p->to.reg;
- a = zprog.from;
- if(p->reg != 0 && p->reg != p->to.reg) {
- a.type = TYPE_REG;
- a.reg = p->reg;
- }
- if(debug['P'])
- print("shiftprop\n%P", p);
- r1 = r;
- for(;;) {
- /* find first use of shift result; abort if shift operands or result are changed */
- r1 = uniqs(r1);
- if(r1 == nil) {
- if(debug['P'])
- print("\tbranch; FAILURE\n");
- return 0;
- }
- if(uniqp(r1) == nil) {
- if(debug['P'])
- print("\tmerge; FAILURE\n");
- return 0;
- }
- p1 = r1->prog;
- if(debug['P'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, nil)) {
- case 0: /* not used or set */
- if((p->from.type == TYPE_REG && copyu(p1, &p->from, nil) > 1) ||
- (a.type == TYPE_REG && copyu(p1, &a, nil) > 1)) {
- if(debug['P'])
- print("\targs modified; FAILURE\n");
- return 0;
- }
- continue;
- case 3: /* set, not used */ {
- if(debug['P'])
- print("\tBOTCH: noref; FAILURE\n");
- return 0;
- }
- }
- break;
- }
- /* check whether substitution can be done */
- switch(p1->as) {
- default:
- if(debug['P'])
- print("\tnon-dpi; FAILURE\n");
- return 0;
-
- case AAND:
- case AEOR:
- case AADD:
- case AADC:
- case AORR:
- case ASUB:
- case ASBC:
- case ARSB:
- case ARSC:
- if(p1->reg == n || (p1->reg == 0 && p1->to.type == TYPE_REG && p1->to.reg == n)) {
- if(p1->from.type != TYPE_REG) {
- if(debug['P'])
- print("\tcan't swap; FAILURE\n");
- return 0;
- }
- p1->reg = p1->from.reg;
- p1->from.reg = n;
- switch(p1->as) {
- case ASUB:
- p1->as = ARSB;
- break;
- case ARSB:
- p1->as = ASUB;
- break;
- case ASBC:
- p1->as = ARSC;
- break;
- case ARSC:
- p1->as = ASBC;
- break;
- }
- if(debug['P'])
- print("\t=>%P", p1);
- }
- case ABIC:
- case ATST:
- case ACMP:
- case ACMN:
- if(p1->reg == n) {
- if(debug['P'])
- print("\tcan't swap; FAILURE\n");
- return 0;
- }
- if(p1->reg == 0 && p1->to.reg == n) {
- if(debug['P'])
- print("\tshift result used twice; FAILURE\n");
- return 0;
- }
-// case AMVN:
- if(p1->from.type == TYPE_SHIFT) {
- if(debug['P'])
- print("\tshift result used in shift; FAILURE\n");
- return 0;
- }
- if(p1->from.type != TYPE_REG || p1->from.reg != n) {
- if(debug['P'])
- print("\tBOTCH: where is it used?; FAILURE\n");
- return 0;
- }
- break;
- }
- /* check whether shift result is used subsequently */
- p2 = p1;
- if(p1->to.reg != n)
- for (;;) {
- r1 = uniqs(r1);
- if(r1 == nil) {
- if(debug['P'])
- print("\tinconclusive; FAILURE\n");
- return 0;
- }
- p1 = r1->prog;
- if(debug['P'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, nil)) {
- case 0: /* not used or set */
- continue;
- case 3: /* set, not used */
- break;
- default:/* used */
- if(debug['P'])
- print("\treused; FAILURE\n");
- return 0;
- }
- break;
- }
-
- /* make the substitution */
- p2->from.reg = 0;
- o = p->reg;
- if(o == 0)
- o = p->to.reg;
- o &= 15;
-
- switch(p->from.type){
- case TYPE_CONST:
- o |= (p->from.offset&0x1f)<<7;
- break;
- case TYPE_REG:
- o |= (1<<4) | ((p->from.reg&15)<<8);
- break;
- }
- switch(p->as){
- case ASLL:
- o |= 0<<5;
- break;
- case ASRL:
- o |= 1<<5;
- break;
- case ASRA:
- o |= 2<<5;
- break;
- }
- p2->from = zprog.from;
- p2->from.type = TYPE_SHIFT;
- p2->from.offset = o;
- if(debug['P'])
- print("\t=>%P\tSUCCEED\n", p2);
- return 1;
-}
-
-/*
- * findpre returns the last instruction mentioning v
- * before r. It must be a set, and there must be
- * a unique path from that instruction to r.
- */
-static Flow*
-findpre(Flow *r, Adr *v)
-{
- Flow *r1;
-
- for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
- if(uniqs(r1) != r)
- return nil;
- switch(copyu(r1->prog, v, nil)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- return nil;
- case 3: /* set */
- case 4: /* set and used */
- return r1;
- }
- }
- return nil;
-}
-
-/*
- * findinc finds ADD instructions with a constant
- * argument which falls within the immed_12 range.
- */
-static Flow*
-findinc(Flow *r, Flow *r2, Adr *v)
-{
- Flow *r1;
- Prog *p;
-
-
- for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
- if(uniqp(r1) != r)
- return nil;
- switch(copyu(r1->prog, v, nil)) {
- case 0: /* not touched */
- continue;
- case 4: /* set and used */
- p = r1->prog;
- if(p->as == AADD)
- if(isdconst(&p->from))
- if(p->from.offset > -4096 && p->from.offset < 4096)
- return r1;
- default:
- return nil;
- }
- }
- return nil;
-}
-
-static int
-nochange(Flow *r, Flow *r2, Prog *p)
-{
- Adr a[3];
- int i, n;
-
- if(r == r2)
- return 1;
- n = 0;
- if(p->reg != 0 && p->reg != p->to.reg) {
- a[n].type = TYPE_REG;
- a[n++].reg = p->reg;
- }
- switch(p->from.type) {
- case TYPE_SHIFT:
- a[n].type = TYPE_REG;
- a[n++].reg = REG_R0 + (p->from.offset&0xf);
- case TYPE_REG:
- a[n].type = TYPE_REG;
- a[n++].reg = p->from.reg;
- }
- if(n == 0)
- return 1;
- for(; r!=nil && r!=r2; r=uniqs(r)) {
- p = r->prog;
- for(i=0; i<n; i++)
- if(copyu(p, &a[i], nil) > 1)
- return 0;
- }
- return 1;
-}
-
-static int
-findu1(Flow *r, Adr *v)
-{
- for(; r != nil; r = r->s1) {
- if(r->active)
- return 0;
- r->active = 1;
- switch(copyu(r->prog, v, nil)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- case 4: /* set and used */
- return 1;
- case 3: /* set */
- return 0;
- }
- if(r->s2)
- if (findu1(r->s2, v))
- return 1;
- }
- return 0;
-}
-
-static int
-finduse(Graph *g, Flow *r, Adr *v)
-{
- Flow *r1;
-
- for(r1=g->start; r1!=nil; r1=r1->link)
- r1->active = 0;
- return findu1(r, v);
-}
-
-/*
- * xtramodes enables the ARM post increment and
- * shift offset addressing modes to transform
- * MOVW 0(R3),R1
- * ADD $4,R3,R3
- * into
- * MOVW.P 4(R3),R1
- * and
- * ADD R0,R1
- * MOVBU 0(R1),R0
- * into
- * MOVBU R0<<0(R1),R0
- */
-static int
-xtramodes(Graph *g, Flow *r, Adr *a)
-{
- Flow *r1, *r2, *r3;
- Prog *p, *p1;
- Adr v;
-
- p = r->prog;
- v = *a;
- v.type = TYPE_REG;
- r1 = findpre(r, &v);
- if(r1 != nil) {
- p1 = r1->prog;
- if(p1->to.type == TYPE_REG && p1->to.reg == v.reg)
- switch(p1->as) {
- case AADD:
- if(p1->scond & C_SBIT)
- // avoid altering ADD.S/ADC sequences.
- break;
- if(p1->from.type == TYPE_REG ||
- (p1->from.type == TYPE_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
- ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
- ((p1->from.type == TYPE_ADDR || p1->from.type == TYPE_CONST) &&
- p1->from.offset > -4096 && p1->from.offset < 4096))
- if(nochange(uniqs(r1), r, p1)) {
- if(a != &p->from || v.reg != p->to.reg)
- if (finduse(g, r->s1, &v)) {
- if(p1->reg == 0 || p1->reg == v.reg)
- /* pre-indexing */
- p->scond |= C_WBIT;
- else return 0;
- }
- switch (p1->from.type) {
- case TYPE_REG:
- /* register offset */
- if(nacl)
- return 0;
- *a = zprog.from;
- a->type = TYPE_SHIFT;
- a->offset = p1->from.reg&15;
- break;
- case TYPE_SHIFT:
- /* scaled register offset */
- if(nacl)
- return 0;
- *a = zprog.from;
- a->type = TYPE_SHIFT;
- case TYPE_CONST:
- case TYPE_ADDR:
- /* immediate offset */
- a->offset = p1->from.offset;
- break;
- }
- if(p1->reg != 0)
- a->reg = p1->reg;
- excise(r1);
- return 1;
- }
- break;
- case AMOVW:
- if(p1->from.type == TYPE_REG)
- if((r2 = findinc(r1, r, &p1->from)) != nil) {
- for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
- ;
- if(r3 == r) {
- /* post-indexing */
- p1 = r2->prog;
- a->reg = p1->to.reg;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- if(!finduse(g, r, &r1->prog->to))
- excise(r1);
- excise(r2);
- return 1;
- }
- }
- break;
- }
- }
- if(a != &p->from || a->reg != p->to.reg)
- if((r1 = findinc(r, nil, &v)) != nil) {
- /* post-indexing */
- p1 = r1->prog;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- excise(r1);
- return 1;
- }
- return 0;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-static int
-copyu(Prog *p, Adr *v, Adr *s)
-{
- switch(p->as) {
-
- default:
- print("copyu: can't find %A\n", p->as);
- return 2;
-
- case AMOVM:
- if(v->type != TYPE_REG)
- return 0;
- if(p->from.type == TYPE_CONST) { /* read reglist, read/rar */
- if(s != nil) {
- if(p->from.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v)) {
- if(p->scond&C_WBIT)
- return 2;
- return 1;
- }
- if(p->from.offset&(1<<v->reg))
- return 1;
- } else { /* read/rar, write reglist */
- if(s != nil) {
- if(p->to.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->from, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->from, v)) {
- if(p->scond&C_WBIT)
- return 2;
- if(p->to.offset&(1<<v->reg))
- return 4;
- return 1;
- }
- if(p->to.offset&(1<<v->reg))
- return 3;
- }
- return 0;
-
- case ANOP: /* read,, write */
- case AMOVW:
- case AMOVF:
- case AMOVD:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVFW:
- case AMOVWF:
- case AMOVDW:
- case AMOVWD:
- case AMOVFD:
- case AMOVDF:
- if(p->scond&(C_WBIT|C_PBIT))
- if(v->type == TYPE_REG) {
- if(p->from.type == TYPE_MEM || p->from.type == TYPE_SHIFT) {
- if(p->from.reg == v->reg)
- return 2;
- } else {
- if(p->to.reg == v->reg)
- return 2;
- }
- }
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->scond != C_SCOND_NONE)
- return 2;
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case AMULLU: /* read, read, write, write */
- case AMULL:
- case AMULA:
- case AMVN:
- return 2;
-
- case AADD: /* read, read, write */
- case AADC:
- case ASUB:
- case ASBC:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case AMULU:
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
-
- case ACHECKNIL: /* read */
- case ACMPF: /* read, read, */
- case ACMPD:
- case ACMP:
- case ACMN:
- case ACASE:
- case ATST: /* read,, */
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(copysub1(p, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->scond != C_SCOND_NONE)
- return 2;
- if(p->reg == 0)
- p->reg = p->to.reg;
- if(copyau(&p->from, v))
- return 4;
- if(copyau1(p, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ABEQ: /* read, read */
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub1(p, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- return 0;
-
- case AB: /* funny */
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET: /* funny */
- if(s != nil)
- return 1;
- return 3;
-
- case ABL: /* funny */
- if(v->type == TYPE_REG) {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if(REG_R0 < v->reg && v->reg <= REGEXT)
- return 2;
- if(v->reg == REGARG)
- return 2;
- if(REG_F0 < v->reg && v->reg <= FREGEXT)
- return 2;
- }
- if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg)
- return 2;
-
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
- case ADUFFZERO:
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R1 is ptr to memory, used and set, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == REGALLOC_R0)
- return 1;
- if(v->reg == REGALLOC_R0+1)
- return 2;
- }
- return 0;
- case ADUFFCOPY:
- // R0 is scratch, set by DUFFCOPY, cannot be substituted.
- // R1, R2 areptr to src, dst, used and set, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == REGALLOC_R0)
- return 3;
- if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2)
- return 2;
- }
- return 0;
-
- case ATEXT: /* funny */
- if(v->type == TYPE_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
-
- case APCDATA:
- case AFUNCDATA:
- case AVARDEF:
- case AVARKILL:
- return 0;
- }
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
-
- if(regtyp(v)) {
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- } else
- if(v->type == TYPE_CONST) { /* for constprop */
- if(a->type == v->type)
- if(a->name == v->name)
- if(a->sym == v->sym)
- if(a->reg == v->reg)
- if(a->offset == v->offset)
- return 1;
- }
- return 0;
-}
-
-int
-sameaddr(Adr *a, Adr *v)
-{
- if(a->type != v->type)
- return 0;
- if(regtyp(v) && a->reg == v->reg)
- return 1;
- // TODO(rsc): Change v->type to v->name and enable.
- //if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
- // if(v->offset == a->offset)
- // return 1;
- //}
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(v->type == TYPE_REG) {
- if(a->type == TYPE_ADDR && a->reg != 0) {
- if(a->reg == v->reg)
- return 1;
- } else
- if(a->type == TYPE_MEM) {
- if(a->reg == v->reg)
- return 1;
- } else
- if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) {
- if(a->reg == v->reg)
- return 1;
- if(a->offset == v->reg)
- return 1;
- } else
- if(a->type == TYPE_SHIFT) {
- if((a->offset&0xf) == v->reg - REG_R0)
- return 1;
- if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0)
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * compare v to the center
- * register in p (p->reg)
- */
-static int
-copyau1(Prog *p, Adr *v)
-{
- if(v->type == TYPE_REG && v->reg == 0)
- return 0;
- return p->reg == v->reg;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau(a, v)) {
- if(a->type == TYPE_SHIFT) {
- if((a->offset&0xf) == v->reg - REG_R0)
- a->offset = (a->offset&~0xf)|(s->reg&0xf);
- if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0)
- a->offset = (a->offset&~(0xf<<8))|((s->reg&0xf)<<8);
- } else
- if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) {
- if(a->offset == v->reg)
- a->offset = s->reg;
- if(a->reg == v->reg)
- a->reg = s->reg;
- } else
- a->reg = s->reg;
- }
- return 0;
-}
-
-static int
-copysub1(Prog *p1, Adr *v, Adr *s, int f)
-{
-
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-struct {
- int opcode;
- int notopcode;
- int scond;
- int notscond;
-} predinfo[] = {
- { ABEQ, ABNE, 0x0, 0x1, },
- { ABNE, ABEQ, 0x1, 0x0, },
- { ABCS, ABCC, 0x2, 0x3, },
- { ABHS, ABLO, 0x2, 0x3, },
- { ABCC, ABCS, 0x3, 0x2, },
- { ABLO, ABHS, 0x3, 0x2, },
- { ABMI, ABPL, 0x4, 0x5, },
- { ABPL, ABMI, 0x5, 0x4, },
- { ABVS, ABVC, 0x6, 0x7, },
- { ABVC, ABVS, 0x7, 0x6, },
- { ABHI, ABLS, 0x8, 0x9, },
- { ABLS, ABHI, 0x9, 0x8, },
- { ABGE, ABLT, 0xA, 0xB, },
- { ABLT, ABGE, 0xB, 0xA, },
- { ABGT, ABLE, 0xC, 0xD, },
- { ABLE, ABGT, 0xD, 0xC, },
-};
-
-typedef struct {
- Flow *start;
- Flow *last;
- Flow *end;
- int len;
-} Joininfo;
-
-enum {
- Join,
- Split,
- End,
- Branch,
- Setcond,
- Toolong
-};
-
-enum {
- Falsecond,
- Truecond,
- Delbranch,
- Keepbranch
-};
-
-static int
-isbranch(Prog *p)
-{
- return (ABEQ <= p->as) && (p->as <= ABLE);
-}
-
-static int
-predicable(Prog *p)
-{
- switch(p->as) {
- case ANOP:
- case AXXX:
- case ADATA:
- case AGLOBL:
- case ATEXT:
- case AWORD:
- case ABCASE:
- case ACASE:
- return 0;
- }
- if(isbranch(p))
- return 0;
- return 1;
-}
-
-/*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
-static int
-modifiescpsr(Prog *p)
-{
- switch(p->as) {
- case AMULLU:
- case AMULA:
- case AMULU:
- case ADIVU:
-
- case ATEQ:
- case ACMN:
- case ATST:
- case ACMP:
- case AMUL:
- case ADIV:
- case AMOD:
- case AMODU:
- case ABL:
- return 1;
- }
- if(p->scond & C_SBIT)
- return 1;
- return 0;
-}
-
-/*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
-static int
-joinsplit(Flow *r, Joininfo *j)
-{
- j->start = r;
- j->last = r;
- j->len = 0;
- do {
- if (r->p2 && (r->p1 || r->p2->p2link)) {
- j->end = r;
- return Join;
- }
- if (r->s1 && r->s2) {
- j->end = r;
- return Split;
- }
- j->last = r;
- if (r->prog->as != ANOP)
- j->len++;
- if (!r->s1 && !r->s2) {
- j->end = r->link;
- return End;
- }
- if (r->s2) {
- j->end = r->s2;
- return Branch;
- }
- if (modifiescpsr(r->prog)) {
- j->end = r->s1;
- return Setcond;
- }
- r = r->s1;
- } while (j->len < 4);
- j->end = r;
- return Toolong;
-}
-
-static Flow*
-successor(Flow *r)
-{
- if(r->s1)
- return r->s1;
- else
- return r->s2;
-}
-
-static void
-applypred(Flow *rstart, Joininfo *j, int cond, int branch)
-{
- int pred;
- Flow *r;
-
- if(j->len == 0)
- return;
- if(cond == Truecond)
- pred = predinfo[rstart->prog->as - ABEQ].scond;
- else
- pred = predinfo[rstart->prog->as - ABEQ].notscond;
-
- for(r = j->start;; r = successor(r)) {
- if(r->prog->as == AB) {
- if(r != j->last || branch == Delbranch)
- excise(r);
- else {
- if(cond == Truecond)
- r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
- else
- r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
- }
- }
- else
- if(predicable(r->prog))
- r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
- if(r->s1 != r->link) {
- r->s1 = r->link;
- r->link->p1 = r;
- }
- if(r == j->last)
- break;
- }
-}
-
-void
-predicate(Graph *g)
-{
- Flow *r;
- int t1, t2;
- Joininfo j1, j2;
-
- for(r=g->start; r!=nil; r=r->link) {
- if (isbranch(r->prog)) {
- t1 = joinsplit(r->s1, &j1);
- t2 = joinsplit(r->s2, &j2);
- if(j1.last->link != j2.start)
- continue;
- if(j1.end == j2.end)
- if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
- (t2 == Join && (t1 == Join || t1 == Setcond))) {
- applypred(r, &j1, Falsecond, Delbranch);
- applypred(r, &j2, Truecond, Delbranch);
- excise(r);
- continue;
- }
- if(t1 == End || t1 == Branch) {
- applypred(r, &j1, Falsecond, Keepbranch);
- excise(r);
- continue;
- }
- }
- }
-}
-
-static int
-isdconst(Addr *a)
-{
- return a->type == TYPE_CONST;
-}
-
-static int
-isfloatreg(Addr *a)
-{
- return REG_F0 <= a->reg && a->reg <= REG_F15;
-}
-
-int
-stackaddr(Addr *a)
-{
- return regtyp(a) && a->reg == REGSP;
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
- return reg->type == TYPE_REG && a->type == TYPE_MEM &&
- a->reg == reg->reg &&
- 0 <= a->offset && a->offset < 4096;
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- nopout(p);
-}
diff --git a/src/cmd/new5g/peep.go b/src/cmd/5g/peep.go
index 2fbb1e5285..2fbb1e5285 100644
--- a/src/cmd/new5g/peep.go
+++ b/src/cmd/5g/peep.go
diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c
deleted file mode 100644
index 9d5adefe69..0000000000
--- a/src/cmd/5g/prog.c
+++ /dev/null
@@ -1,160 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-enum
-{
- RightRdwr = RightRead | RightWrite,
-};
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-static ProgInfo progtable[ALAST] = {
- [ATYPE]= {Pseudo | Skip},
- [ATEXT]= {Pseudo},
- [AFUNCDATA]= {Pseudo},
- [APCDATA]= {Pseudo},
- [AUNDEF]= {Break},
- [AUSEFIELD]= {OK},
- [ACHECKNIL]= {LeftRead},
- [AVARDEF]= {Pseudo | RightWrite},
- [AVARKILL]= {Pseudo | RightWrite},
-
- // NOP is an internal no-op that also stands
- // for USED and SET annotations, not the Intel opcode.
- [ANOP]= {LeftRead | RightWrite},
-
- // Integer.
- [AADC]= {SizeL | LeftRead | RegRead | RightWrite},
- [AADD]= {SizeL | LeftRead | RegRead | RightWrite},
- [AAND]= {SizeL | LeftRead | RegRead | RightWrite},
- [ABIC]= {SizeL | LeftRead | RegRead | RightWrite},
- [ACMN]= {SizeL | LeftRead | RightRead},
- [ACMP]= {SizeL | LeftRead | RightRead},
- [ADIVU]= {SizeL | LeftRead | RegRead | RightWrite},
- [ADIV]= {SizeL | LeftRead | RegRead | RightWrite},
- [AEOR]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMODU]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMOD]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMULALU]= {SizeL | LeftRead | RegRead | RightRdwr},
- [AMULAL]= {SizeL | LeftRead | RegRead | RightRdwr},
- [AMULA]= {SizeL | LeftRead | RegRead | RightRdwr},
- [AMULU]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMUL]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMULL]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMULLU]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMVN]= {SizeL | LeftRead | RightWrite},
- [AORR]= {SizeL | LeftRead | RegRead | RightWrite},
- [ARSB]= {SizeL | LeftRead | RegRead | RightWrite},
- [ARSC]= {SizeL | LeftRead | RegRead | RightWrite},
- [ASBC]= {SizeL | LeftRead | RegRead | RightWrite},
- [ASLL]= {SizeL | LeftRead | RegRead | RightWrite},
- [ASRA]= {SizeL | LeftRead | RegRead | RightWrite},
- [ASRL]= {SizeL | LeftRead | RegRead | RightWrite},
- [ASUB]= {SizeL | LeftRead | RegRead | RightWrite},
- [ATEQ]= {SizeL | LeftRead | RightRead},
- [ATST]= {SizeL | LeftRead | RightRead},
-
- // Floating point.
- [AADDD]= {SizeD | LeftRead | RightRdwr},
- [AADDF]= {SizeF | LeftRead | RightRdwr},
- [ACMPD]= {SizeD | LeftRead | RightRead},
- [ACMPF]= {SizeF | LeftRead | RightRead},
- [ADIVD]= {SizeD | LeftRead | RightRdwr},
- [ADIVF]= {SizeF | LeftRead | RightRdwr},
- [AMULD]= {SizeD | LeftRead | RightRdwr},
- [AMULF]= {SizeF | LeftRead | RightRdwr},
- [ASUBD]= {SizeD | LeftRead | RightRdwr},
- [ASUBF]= {SizeF | LeftRead | RightRdwr},
-
- // Conversions.
- [AMOVWD]= {SizeD | LeftRead | RightWrite | Conv},
- [AMOVWF]= {SizeF | LeftRead | RightWrite | Conv},
- [AMOVDF]= {SizeF | LeftRead | RightWrite | Conv},
- [AMOVDW]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVFD]= {SizeD | LeftRead | RightWrite | Conv},
- [AMOVFW]= {SizeL | LeftRead | RightWrite | Conv},
-
- // Moves.
- [AMOVB]= {SizeB | LeftRead | RightWrite | Move},
- [AMOVD]= {SizeD | LeftRead | RightWrite | Move},
- [AMOVF]= {SizeF | LeftRead | RightWrite | Move},
- [AMOVH]= {SizeW | LeftRead | RightWrite | Move},
- [AMOVW]= {SizeL | LeftRead | RightWrite | Move},
- // In addtion, duffzero reads R0,R1 and writes R1. This fact is
- // encoded in peep.c
- [ADUFFZERO]= {Call},
- // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is
- // encoded in peep.c
- [ADUFFCOPY]= {Call},
-
- // These should be split into the two different conversions instead
- // of overloading the one.
- [AMOVBS]= {SizeB | LeftRead | RightWrite | Conv},
- [AMOVBU]= {SizeB | LeftRead | RightWrite | Conv},
- [AMOVHS]= {SizeW | LeftRead | RightWrite | Conv},
- [AMOVHU]= {SizeW | LeftRead | RightWrite | Conv},
-
- // Jumps.
- [AB]= {Jump | Break},
- [ABL]= {Call},
- [ABEQ]= {Cjmp},
- [ABNE]= {Cjmp},
- [ABCS]= {Cjmp},
- [ABHS]= {Cjmp},
- [ABCC]= {Cjmp},
- [ABLO]= {Cjmp},
- [ABMI]= {Cjmp},
- [ABPL]= {Cjmp},
- [ABVS]= {Cjmp},
- [ABVC]= {Cjmp},
- [ABHI]= {Cjmp},
- [ABLS]= {Cjmp},
- [ABGE]= {Cjmp},
- [ABLT]= {Cjmp},
- [ABGT]= {Cjmp},
- [ABLE]= {Cjmp},
- [ARET]= {Break},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
- *info = progtable[p->as];
- if(info->flags == 0)
- fatal("unknown instruction %P", p);
-
- if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) {
- info->flags &= ~LeftRead;
- info->flags |= LeftAddr;
- }
-
- if((info->flags & RegRead) && p->reg == 0) {
- info->flags &= ~RegRead;
- info->flags |= CanRegRead | RightRead;
- }
-
- if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite))
- info->flags |= RightRead;
-
- switch(p->as) {
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- info->regset |= RtoB(REG_R12);
- break;
- }
-}
diff --git a/src/cmd/new5g/prog.go b/src/cmd/5g/prog.go
index 3f7715f1fc..3f7715f1fc 100644
--- a/src/cmd/new5g/prog.go
+++ b/src/cmd/5g/prog.go
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
deleted file mode 100644
index 1216e01bd5..0000000000
--- a/src/cmd/5g/reg.c
+++ /dev/null
@@ -1,146 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.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 "../gc/popt.h"
-
-enum {
- NREGVAR = 32,
-};
-
-static char* regname[] = {
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
-};
-
-char**
-regnames(int *n)
-{
- *n = NREGVAR;
- return regname;
-}
-
-uint64
-excludedregs(void)
-{
- return RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
-}
-
-uint64
-doregbits(int r)
-{
- USED(r);
- return 0;
-}
-
-/*
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 10 R10
- * 12 R12
- *
- * bit reg
- * 18 F2
- * 19 F3
- * ... ...
- * 31 F15
- */
-uint64
-RtoB(int r)
-{
- if(REG_R0 <= r && r <= REG_R15) {
- if(r >= REGTMP-2 && r != REG_R12) // excluded R9 and R10 for m and g, but not R12
- return 0;
- return 1ULL << (r - REG_R0);
- }
-
- if(REG_F0 <= r && r <= REG_F15) {
- if(r < REG_F2 || r > REG_F0+NFREG-1)
- return 0;
- return 1ULL << ((r - REG_F0) + 16);
- }
-
- return 0;
-}
-
-int
-BtoR(uint64 b)
-{
- // TODO Allow R0 and R1, but be careful with a 0 return
- // TODO Allow R9. Only R10 is reserved now (just g, not m).
- b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12
- if(b == 0)
- return 0;
- return bitno(b) + REG_R0;
-}
-
-int
-BtoF(uint64 b)
-{
- b &= 0xfffc0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16 + REG_F0;
-}
diff --git a/src/cmd/new5g/reg.go b/src/cmd/5g/reg.go
index 2afdf12416..2afdf12416 100644
--- a/src/cmd/new5g/reg.go
+++ b/src/cmd/5g/reg.go
diff --git a/src/cmd/new5g/util.go b/src/cmd/5g/util.go
index bb5eedb15a..bb5eedb15a 100644
--- a/src/cmd/new5g/util.go
+++ b/src/cmd/5g/util.go
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
deleted file mode 100644
index 27290ddd71..0000000000
--- a/src/cmd/6a/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
- LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
deleted file mode 100644
index 95c4babdfc..0000000000
--- a/src/cmd/6a/a.h
+++ /dev/null
@@ -1,188 +0,0 @@
-// Inferno utils/6a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
-//
-// 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 <bio.h>
-#include <link.h>
-#include "../6l/6.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef getc
-#undef ungetc
-#undef BUFSIZ
-
-#define getc ccgetc
-#define ungetc ccungetc
-
-typedef struct Sym Sym;
-typedef struct Ref Ref;
-typedef struct Io Io;
-typedef struct Addr2 Addr2;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 500
-#define BUFSIZ 8192
-#define HISTSZ 20
-#ifndef EOF
-#define EOF (-1)
-#endif
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- Ref* ref;
- char* macro;
- vlong value;
- ushort type;
- char *name;
- char* labelname;
- char sym;
-};
-#define S ((Sym*)0)
-
-struct Ref
-{
- int class;
-};
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-struct Addr2
-{
- Addr from;
- Addr to;
-};
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-};
-
-EXTERN int debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN int newflag;
-EXTERN char* hunk;
-EXTERN char** include;
-EXTERN Io* iofree;
-EXTERN Io* ionext;
-EXTERN Io* iostack;
-EXTERN int32 lineno;
-EXTERN int nerrors;
-EXTERN int32 nhunk;
-EXTERN int ninclude;
-EXTERN int32 nsymb;
-EXTERN Addr nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-EXTERN Link* ctxt;
-EXTERN Biobuf bstdout;
-EXTERN Prog* lastpc;
-
-void* alloc(int32);
-void* allocn(void*, int32, int32);
-void ensuresymb(int32);
-void errorexit(void);
-void pushio(void);
-void newio(void);
-void newfile(char*, int);
-Sym* slookup(char*);
-Sym* lookup(void);
-Sym* labellookup(Sym*);
-void settext(LSym*);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void checkscale(int);
-void pinit(char*);
-void cclean(void);
-int isreg(Addr*);
-void outcode(int, Addr2*);
-void outhist(void);
-void zaddr(Addr*, int);
-void zname(char*, int, int);
-int filbuf(void);
-Sym* getsym(void);
-void domacro(void);
-void macund(void);
-void macdef(void);
-void macexpand(Sym*, char*);
-void macinc(void);
-void macprag(void);
-void maclin(void);
-void macif(int);
-void macend(void);
-void dodefine(char*);
-void prfile(int32);
-void linehist(char*, int);
-void gethunk(void);
-void yyerror(char*, ...);
-int yyparse(void);
-void setinclude(char*);
-int assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index df3ca40b2c..bd59a1faba 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -29,20 +29,24 @@
// THE SOFTWARE.
%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
+package main
+
+import (
+ "cmd/internal/asm"
+ "cmd/internal/obj"
+ "cmd/internal/obj/x86"
+)
%}
-%union {
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
+
+%union {
+ sym *asm.Sym
+ lval int64
+ dval float64
+ sval string
+ addr obj.Addr
+ addr2 Addr2
}
+
%left '|'
%left '^'
%left '&'
@@ -58,7 +62,7 @@
%token <sval> LSCONST LSP
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset
-%type <addr> mem imm reg nam rel rem rim rom omem nmem textsize
+%type <addr> mem imm textsize reg nam rel rem rim rom omem nmem
%type <addr2> nonnon nonrel nonrem rimnon rimrem remrim
%type <addr2> spec3 spec4 spec5 spec6 spec7 spec8 spec9
%type <addr2> spec10 spec12 spec13
@@ -66,18 +70,19 @@
prog:
| prog
{
- stmtline = lineno;
+ stmtline = asm.Lineno;
}
line
line:
LNAME ':'
{
- $1 = labellookup($1);
- if($1->type == LLAB && $1->value != pc)
- yyerror("redeclaration of %s (%s)", $1->labelname, $1->name);
- $1->type = LLAB;
- $1->value = pc;
+ $1 = asm.LabelLookup($1);
+ if $1.Type == LLAB && $1.Value != int64(asm.PC) {
+ yyerror("redeclaration of %s (%s)", $1.Labelname, $1.Name);
+ }
+ $1.Type = LLAB;
+ $1.Value = int64(asm.PC)
}
line
| ';'
@@ -87,34 +92,35 @@ line:
inst:
LNAME '=' expr
{
- $1->type = LVAR;
- $1->value = $3;
+ $1.Type = LVAR;
+ $1.Value = $3;
}
| LVAR '=' expr
{
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
- }
-| LTYPE0 nonnon { outcode($1, &$2); }
-| LTYPE1 nonrem { outcode($1, &$2); }
-| LTYPE2 rimnon { outcode($1, &$2); }
-| LTYPE3 rimrem { outcode($1, &$2); }
-| LTYPE4 remrim { outcode($1, &$2); }
-| LTYPER nonrel { outcode($1, &$2); }
+ if $1.Value != $3 {
+ yyerror("redeclaration of %s", $1.Name);
+ }
+ $1.Value = $3;
+ }
+| LTYPE0 nonnon { outcode(int($1), &$2); }
+| LTYPE1 nonrem { outcode(int($1), &$2); }
+| LTYPE2 rimnon { outcode(int($1), &$2); }
+| LTYPE3 rimrem { outcode(int($1), &$2); }
+| LTYPE4 remrim { outcode(int($1), &$2); }
+| LTYPER nonrel { outcode(int($1), &$2); }
| spec1
| spec2
-| LTYPEC spec3 { outcode($1, &$2); }
-| LTYPEN spec4 { outcode($1, &$2); }
-| LTYPES spec5 { outcode($1, &$2); }
-| LTYPEM spec6 { outcode($1, &$2); }
-| LTYPEI spec7 { outcode($1, &$2); }
-| LTYPEXC spec8 { outcode($1, &$2); }
-| LTYPEX spec9 { outcode($1, &$2); }
-| LTYPERT spec10 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode(int($1), &$2); }
+| LTYPEN spec4 { outcode(int($1), &$2); }
+| LTYPES spec5 { outcode(int($1), &$2); }
+| LTYPEM spec6 { outcode(int($1), &$2); }
+| LTYPEI spec7 { outcode(int($1), &$2); }
+| LTYPEXC spec8 { outcode(int($1), &$2); }
+| LTYPEX spec9 { outcode(int($1), &$2); }
+| LTYPERT spec10 { outcode(int($1), &$2); }
| spec11
-| LTYPEPC spec12 { outcode($1, &$2); }
-| LTYPEF spec13 { outcode($1, &$2); }
+| LTYPEPC spec12 { outcode(int($1), &$2); }
+| LTYPEF spec13 { outcode(int($1), &$2); }
nonnon:
{
@@ -185,57 +191,45 @@ nonrel:
spec1: /* DATA */
LTYPED nam '/' con ',' imm
{
- Addr2 a;
- a.from = $2;
- a.to = $6;
- outcode(ADATA, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ var a Addr2
+ a.from = $2
+ a.to = $6
+ outcode(obj.ADATA, &a)
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
spec2: /* TEXT */
LTYPET mem ',' '$' textsize
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $5;
- outcode(ATEXT, &a);
+ asm.Settext($2.Sym);
+ outcode(obj.ATEXT, &Addr2{$2, $5})
}
| LTYPET mem ',' con ',' '$' textsize
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $7;
- outcode(ATEXT, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym);
+ outcode(obj.ATEXT, &Addr2{$2, $7})
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
spec11: /* GLOBL */
LTYPEG mem ',' imm
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $4;
- outcode(AGLOBL, &a);
+ asm.Settext($2.Sym)
+ outcode(obj.AGLOBL, &Addr2{$2, $4})
}
| LTYPEG mem ',' con ',' imm
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $6;
- outcode(AGLOBL, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym)
+ outcode(obj.AGLOBL, &Addr2{$2, $6})
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
@@ -265,9 +259,10 @@ spec5: /* SHL/SHR */
{
$$.from = $1;
$$.to = $3;
- if($$.from.index != TYPE_NONE)
+ if $$.from.Index != obj.TYPE_NONE {
yyerror("dp shift with lhs index");
- $$.from.index = $5;
+ }
+ $$.from.Index = int16($5);
}
spec6: /* MOVW/MOVL */
@@ -280,9 +275,10 @@ spec6: /* MOVW/MOVL */
{
$$.from = $1;
$$.to = $3;
- if($$.to.index != TYPE_NONE)
+ if $$.to.Index != obj.TYPE_NONE {
yyerror("dp move with lhs index");
- $$.to.index = $5;
+ }
+ $$.to.Index = int16($5);
}
spec7:
@@ -307,7 +303,7 @@ spec8: /* CMPPS/CMPPD */
{
$$.from = $1;
$$.to = $3;
- $$.to.offset = $5;
+ $$.to.Offset = $5;
}
spec9: /* shufl */
@@ -315,9 +311,10 @@ spec9: /* shufl */
{
$$.from = $3;
$$.to = $5;
- if($1.type != TYPE_CONST)
+ if $1.Type != obj.TYPE_CONST {
yyerror("illegal constant");
- $$.to.offset = $1.offset;
+ }
+ $$.to.Offset = $1.Offset;
}
spec10: /* RET/RETF */
@@ -331,11 +328,12 @@ spec10: /* RET/RETF */
$$.to = nullgen;
}
-spec12: /* PCDATA */
+spec12: /* asm.PCDATA */
rim ',' rim
{
- if($1.type != TYPE_CONST || $3.type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
+ if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST {
+ yyerror("arguments to asm.PCDATA must be integer constants");
+ }
$$.from = $1;
$$.to = $3;
}
@@ -343,10 +341,12 @@ spec12: /* PCDATA */
spec13: /* FUNCDATA */
rim ',' rim
{
- if($1.type != TYPE_CONST)
+ if $1.Type != obj.TYPE_CONST {
yyerror("index for FUNCDATA must be integer constant");
- if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC))
+ }
+ if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) {
yyerror("value for FUNCDATA must be symbol reference");
+ }
$$.from = $1;
$$.to = $3;
}
@@ -377,109 +377,110 @@ rel:
con '(' LPC ')'
{
$$ = nullgen;
- $$.type = TYPE_BRANCH;
- $$.offset = $1 + pc;
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1 + int64(asm.PC);
}
| LNAME offset
{
- $1 = labellookup($1);
+ $1 = asm.LabelLookup($1);
$$ = nullgen;
- if(pass == 2 && $1->type != LLAB)
- yyerror("undefined label: %s", $1->labelname);
- $$.type = TYPE_BRANCH;
- $$.offset = $1->value + $2;
+ if asm.Pass == 2 && $1.Type != LLAB {
+ yyerror("undefined label: %s", $1.Labelname);
+ }
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1.Value + $2;
}
reg:
LBREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LFREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LLREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LMREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LSP
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = REG_SP;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = x86.REG_SP;
}
| LSREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LXREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
imm:
'$' con
{
$$ = nullgen;
- $$.type = TYPE_CONST;
- $$.offset = $2;
+ $$.Type = obj.TYPE_CONST;
+ $$.Offset = $2;
}
| '$' nam
{
$$ = $2;
- $$.type = TYPE_ADDR;
+ $$.Type = obj.TYPE_ADDR;
/*
- if($2.type == D_AUTO || $2.type == D_PARAM)
+ if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM)
yyerror("constant cannot be automatic: %s",
- $2.sym->name);
+ $2.sym.Name);
*/
}
| '$' LSCONST
{
$$ = nullgen;
- $$.type = TYPE_SCONST;
- memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ $$.Type = obj.TYPE_SCONST;
+ $$.U.Sval = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
}
| '$' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $2;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $3;
}
| '$' '(' '-' LFCONST ')'
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$4;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$4;
}
| '$' '-' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$3;
}
mem:
@@ -490,87 +491,87 @@ omem:
con
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Offset = $1;
}
| con '(' LLREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
}
| con '(' LSP ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_SP;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = x86.REG_SP
+ $$.Offset = $1;
}
| con '(' LSREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
}
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.offset = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Offset = $1;
+ $$.Index = int16($3);
+ $$.Scale = int8($5);
+ checkscale($$.Scale);
}
| con '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
+ $$.Index = int16($6);
+ $$.Scale = int8($8);
+ checkscale($$.Scale);
}
| con '(' LLREG ')' '(' LSREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
+ $$.Index = int16($6);
+ $$.Scale = int8($8);
+ checkscale($$.Scale);
}
| '(' LLREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($2)
}
| '(' LSP ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_SP;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = x86.REG_SP
}
| '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.index = $2;
- $$.scale = $4;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Index = int16($2);
+ $$.Scale = int8($4);
+ checkscale($$.Scale);
}
| '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
- $$.index = $5;
- $$.scale = $7;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($2)
+ $$.Index = int16($5);
+ $$.Scale = int8($7);
+ checkscale($$.Scale);
}
nmem:
@@ -581,27 +582,27 @@ nmem:
| nam '(' LLREG '*' con ')'
{
$$ = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
+ $$.Index = int16($3);
+ $$.Scale = int8($5);
+ checkscale($$.Scale);
}
nam:
LNAME offset '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $4;
- $$.sym = linklookup(ctxt, $1->name, 0);
- $$.offset = $2;
+ $$.Type = obj.TYPE_MEM
+ $$.Name = int8($4)
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
+ $$.Offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = NAME_STATIC;
- $$.sym = linklookup(ctxt, $1->name, 1);
- $$.offset = $4;
+ $$.Type = obj.TYPE_MEM
+ $$.Name = obj.NAME_STATIC
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
+ $$.Offset = $4;
}
offset:
@@ -621,7 +622,7 @@ pointer:
LSB
| LSP
{
- $$ = NAME_AUTO;
+ $$ = obj.NAME_AUTO;
}
| LFP
@@ -629,7 +630,7 @@ con:
LCONST
| LVAR
{
- $$ = $1->value;
+ $$ = $1.Value;
}
| '-' con
{
@@ -641,7 +642,7 @@ con:
}
| '~' con
{
- $$ = ~$2;
+ $$ = ^$2;
}
| '(' expr ')'
{
@@ -652,30 +653,30 @@ textsize:
LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = $1;
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -$2;
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = $3;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = $1;
+ $$.U.Argsize = int32($3);
}
| '-' LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = $4;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -$2;
+ $$.U.Argsize = int32($4);
}
expr:
@@ -702,11 +703,11 @@ expr:
}
| expr '<' '<' expr
{
- $$ = $1 << $4;
+ $$ = $1 << uint($4);
}
| expr '>' '>' expr
{
- $$ = $1 >> $4;
+ $$ = $1 >> uint($4);
}
| expr '&' expr
{
diff --git a/src/cmd/6a/doc.go b/src/cmd/6a/doc.go
deleted file mode 100644
index 9f14cc0d05..0000000000
--- a/src/cmd/6a/doc.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-6a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
- http://golang.org/doc/asm
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package main
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
deleted file mode 100644
index c600796cd0..0000000000
--- a/src/cmd/6a/lex.c
+++ /dev/null
@@ -1,1137 +0,0 @@
-// Inferno utils/6a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.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.
-
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
- return sys&Windows;
-#else
- return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
- if(nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
-}
-
-LinkArch* thelinkarch = &linkamd64;
-
-void
-usage(void)
-{
- print("usage: %ca [options] file.c...\n", thechar);
- flagprint(1);
- errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
-
- thechar = '6';
- thestring = "amd64";
-
- // Allow GOARCH=thestring or GOARCH=thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
- if(strcmp(p, "amd64p32") == 0)
- thelinkarch = &linkamd64p32;
-
- ctxt = linknew(thelinkarch);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- ctxt->enforce_data_order = 1;
- Binit(&bstdout, 1, OWRITE);
- listinit6();
- fmtinstall('L', Lconv);
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
-
- flagfn1("D", "name[=value]: add #define", dodef);
- flagfn1("I", "dir: add dir to include path", setinclude);
- flagcount("S", "print assembly and machine code", &debug['S']);
- flagcount("m", "debug preprocessor macros", &debug['m']);
- flagstr("o", "file: set output file", &outfile);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
-
- if(argc < 1)
- usage();
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
-
- if(assemble(argv[0]))
- errorexit();
- Bflush(&bstdout);
- if(nerrors > 0)
- errorexit();
- exits(0);
-}
-
-int
-assemble(char *file)
-{
- char *ofile, *p;
- int i, of;
-
- ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
- strcpy(ofile, file);
- p = utfrrune(ofile, pathchar());
- if(p) {
- include[0] = ofile;
- *p++ = 0;
- } else
- p = ofile;
- if(outfile == 0) {
- outfile = p;
- if(outfile){
- p = utfrrune(outfile, '.');
- if(p)
- if(p[1] == 's' && p[2] == 0)
- p[0] = 0;
- p = utfrune(outfile, 0);
- p[0] = '.';
- p[1] = thechar;
- p[2] = 0;
- } else
- outfile = "/dev/null";
- }
-
- of = create(outfile, OWRITE, 0664);
- if(of < 0) {
- yyerror("%ca: cannot create %s", thechar, outfile);
- errorexit();
- }
- Binit(&obuf, of, OWRITE);
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- Bprint(&obuf, "!\n");
-
- for(pass = 1; pass <= 2; pass++) {
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- if(nerrors)
- return nerrors;
- }
-
- writeobj(ctxt, &obuf);
- Bflush(&obuf);
- return 0;
-}
-
-struct
-{
- char *name;
- /*
- * type is the lexical type to return. It dictates what kind of
- * operands 6a allows to follow it (in a.y) as the possible operand
- * types are handled by a grammar. How do you know which LTYPE?
- * Either read a.y or think of an instruction that has the same
- * possible operands and look up what it takes.
- */
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, NAME_AUTO,
- "SB", LSB, NAME_EXTERN,
- "FP", LFP, NAME_PARAM,
-
- "PC", LPC, TYPE_BRANCH,
-
- "AL", LBREG, REG_AL,
- "CL", LBREG, REG_CL,
- "DL", LBREG, REG_DL,
- "BL", LBREG, REG_BL,
-/* "SPB", LBREG, REG_SPB, */
- "SIB", LBREG, REG_SIB,
- "DIB", LBREG, REG_DIB,
- "BPB", LBREG, REG_BPB,
- "R8B", LBREG, REG_R8B,
- "R9B", LBREG, REG_R9B,
- "R10B", LBREG, REG_R10B,
- "R11B", LBREG, REG_R11B,
- "R12B", LBREG, REG_R12B,
- "R13B", LBREG, REG_R13B,
- "R14B", LBREG, REG_R14B,
- "R15B", LBREG, REG_R15B,
-
- "AH", LBREG, REG_AH,
- "CH", LBREG, REG_CH,
- "DH", LBREG, REG_DH,
- "BH", LBREG, REG_BH,
-
- "AX", LLREG, REG_AX,
- "CX", LLREG, REG_CX,
- "DX", LLREG, REG_DX,
- "BX", LLREG, REG_BX,
-/* "SP", LLREG, REG_SP, */
- "BP", LLREG, REG_BP,
- "SI", LLREG, REG_SI,
- "DI", LLREG, REG_DI,
- "R8", LLREG, REG_R8,
- "R9", LLREG, REG_R9,
- "R10", LLREG, REG_R10,
- "R11", LLREG, REG_R11,
- "R12", LLREG, REG_R12,
- "R13", LLREG, REG_R13,
- "R14", LLREG, REG_R14,
- "R15", LLREG, REG_R15,
-
- "RARG", LLREG, REGARG,
-
- "F0", LFREG, REG_F0+0,
- "F1", LFREG, REG_F0+1,
- "F2", LFREG, REG_F0+2,
- "F3", LFREG, REG_F0+3,
- "F4", LFREG, REG_F0+4,
- "F5", LFREG, REG_F0+5,
- "F6", LFREG, REG_F0+6,
- "F7", LFREG, REG_F0+7,
-
- "M0", LMREG, REG_M0+0,
- "M1", LMREG, REG_M0+1,
- "M2", LMREG, REG_M0+2,
- "M3", LMREG, REG_M0+3,
- "M4", LMREG, REG_M0+4,
- "M5", LMREG, REG_M0+5,
- "M6", LMREG, REG_M0+6,
- "M7", LMREG, REG_M0+7,
-
- "X0", LXREG, REG_X0+0,
- "X1", LXREG, REG_X0+1,
- "X2", LXREG, REG_X0+2,
- "X3", LXREG, REG_X0+3,
- "X4", LXREG, REG_X0+4,
- "X5", LXREG, REG_X0+5,
- "X6", LXREG, REG_X0+6,
- "X7", LXREG, REG_X0+7,
- "X8", LXREG, REG_X0+8,
- "X9", LXREG, REG_X0+9,
- "X10", LXREG, REG_X0+10,
- "X11", LXREG, REG_X0+11,
- "X12", LXREG, REG_X0+12,
- "X13", LXREG, REG_X0+13,
- "X14", LXREG, REG_X0+14,
- "X15", LXREG, REG_X0+15,
-
- "CS", LSREG, REG_CS,
- "SS", LSREG, REG_SS,
- "DS", LSREG, REG_DS,
- "ES", LSREG, REG_ES,
- "FS", LSREG, REG_FS,
- "GS", LSREG, REG_GS,
-
- "GDTR", LBREG, REG_GDTR,
- "IDTR", LBREG, REG_IDTR,
- "LDTR", LBREG, REG_LDTR,
- "MSW", LBREG, REG_MSW,
- "TASK", LBREG, REG_TASK,
-
- "CR0", LBREG, REG_CR+0,
- "CR1", LBREG, REG_CR+1,
- "CR2", LBREG, REG_CR+2,
- "CR3", LBREG, REG_CR+3,
- "CR4", LBREG, REG_CR+4,
- "CR5", LBREG, REG_CR+5,
- "CR6", LBREG, REG_CR+6,
- "CR7", LBREG, REG_CR+7,
- "CR8", LBREG, REG_CR+8,
- "CR9", LBREG, REG_CR+9,
- "CR10", LBREG, REG_CR+10,
- "CR11", LBREG, REG_CR+11,
- "CR12", LBREG, REG_CR+12,
- "CR13", LBREG, REG_CR+13,
- "CR14", LBREG, REG_CR+14,
- "CR15", LBREG, REG_CR+15,
-
- "DR0", LBREG, REG_DR+0,
- "DR1", LBREG, REG_DR+1,
- "DR2", LBREG, REG_DR+2,
- "DR3", LBREG, REG_DR+3,
- "DR4", LBREG, REG_DR+4,
- "DR5", LBREG, REG_DR+5,
- "DR6", LBREG, REG_DR+6,
- "DR7", LBREG, REG_DR+7,
-
- "TR0", LBREG, REG_TR+0,
- "TR1", LBREG, REG_TR+1,
- "TR2", LBREG, REG_TR+2,
- "TR3", LBREG, REG_TR+3,
- "TR4", LBREG, REG_TR+4,
- "TR5", LBREG, REG_TR+5,
- "TR6", LBREG, REG_TR+6,
- "TR7", LBREG, REG_TR+7,
- "TLS", LSREG, REG_TLS,
-
- "AAA", LTYPE0, AAAA,
- "AAD", LTYPE0, AAAD,
- "AAM", LTYPE0, AAAM,
- "AAS", LTYPE0, AAAS,
- "ADCB", LTYPE3, AADCB,
- "ADCL", LTYPE3, AADCL,
- "ADCQ", LTYPE3, AADCQ,
- "ADCW", LTYPE3, AADCW,
- "ADDB", LTYPE3, AADDB,
- "ADDL", LTYPE3, AADDL,
- "ADDQ", LTYPE3, AADDQ,
- "ADDW", LTYPE3, AADDW,
- "ADJSP", LTYPE2, AADJSP,
- "ANDB", LTYPE3, AANDB,
- "ANDL", LTYPE3, AANDL,
- "ANDQ", LTYPE3, AANDQ,
- "ANDW", LTYPE3, AANDW,
- "ARPL", LTYPE3, AARPL,
- "BOUNDL", LTYPE3, ABOUNDL,
- "BOUNDW", LTYPE3, ABOUNDW,
- "BSFL", LTYPE3, ABSFL,
- "BSFQ", LTYPE3, ABSFQ,
- "BSFW", LTYPE3, ABSFW,
- "BSRL", LTYPE3, ABSRL,
- "BSRQ", LTYPE3, ABSRQ,
- "BSRW", LTYPE3, ABSRW,
- "BSWAPL", LTYPE1, ABSWAPL,
- "BSWAPQ", LTYPE1, ABSWAPQ,
- "BTCL", LTYPE3, ABTCL,
- "BTCQ", LTYPE3, ABTCQ,
- "BTCW", LTYPE3, ABTCW,
- "BTL", LTYPE3, ABTL,
- "BTQ", LTYPE3, ABTQ,
- "BTRL", LTYPE3, ABTRL,
- "BTRQ", LTYPE3, ABTRQ,
- "BTRW", LTYPE3, ABTRW,
- "BTSL", LTYPE3, ABTSL,
- "BTSQ", LTYPE3, ABTSQ,
- "BTSW", LTYPE3, ABTSW,
- "BTW", LTYPE3, ABTW,
- "BYTE", LTYPE2, ABYTE,
- "CALL", LTYPEC, ACALL,
- "CLC", LTYPE0, ACLC,
- "CLD", LTYPE0, ACLD,
- "CLI", LTYPE0, ACLI,
- "CLTS", LTYPE0, ACLTS,
- "CMC", LTYPE0, ACMC,
- "CMPB", LTYPE4, ACMPB,
- "CMPL", LTYPE4, ACMPL,
- "CMPQ", LTYPE4, ACMPQ,
- "CMPW", LTYPE4, ACMPW,
- "CMPSB", LTYPE0, ACMPSB,
- "CMPSL", LTYPE0, ACMPSL,
- "CMPSQ", LTYPE0, ACMPSQ,
- "CMPSW", LTYPE0, ACMPSW,
- "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
- "CMPXCHGB", LTYPE3, ACMPXCHGB, /* LTYPE3? */
- "CMPXCHGL", LTYPE3, ACMPXCHGL,
- "CMPXCHGQ", LTYPE3, ACMPXCHGQ,
- "CMPXCHGW", LTYPE3, ACMPXCHGW,
- "CPUID", LTYPE0, ACPUID,
- "DAA", LTYPE0, ADAA,
- "DAS", LTYPE0, ADAS,
- "DATA", LTYPED, ADATA,
- "DECB", LTYPE1, ADECB,
- "DECL", LTYPE1, ADECL,
- "DECQ", LTYPE1, ADECQ,
- "DECW", LTYPE1, ADECW,
- "DIVB", LTYPE2, ADIVB,
- "DIVL", LTYPE2, ADIVL,
- "DIVQ", LTYPE2, ADIVQ,
- "DIVW", LTYPE2, ADIVW,
- "EMMS", LTYPE0, AEMMS,
- "END", LTYPE0, AEND,
- "ENTER", LTYPE2, AENTER,
- "GLOBL", LTYPEG, AGLOBL,
- "HLT", LTYPE0, AHLT,
- "IDIVB", LTYPE2, AIDIVB,
- "IDIVL", LTYPE2, AIDIVL,
- "IDIVQ", LTYPE2, AIDIVQ,
- "IDIVW", LTYPE2, AIDIVW,
- "IMULB", LTYPEI, AIMULB,
- "IMULL", LTYPEI, AIMULL,
- "IMULQ", LTYPEI, AIMULQ,
- "IMUL3Q", LTYPEX, AIMUL3Q,
- "IMULW", LTYPEI, AIMULW,
- "INB", LTYPE0, AINB,
- "INL", LTYPE0, AINL,
- "INW", LTYPE0, AINW,
- "INCB", LTYPE1, AINCB,
- "INCL", LTYPE1, AINCL,
- "INCQ", LTYPE1, AINCQ,
- "INCW", LTYPE1, AINCW,
- "INSB", LTYPE0, AINSB,
- "INSL", LTYPE0, AINSL,
- "INSW", LTYPE0, AINSW,
- "INT", LTYPE2, AINT,
- "INTO", LTYPE0, AINTO,
- "INVD", LTYPE0, AINVD,
- "INVLPG", LTYPE2, AINVLPG,
- "IRETL", LTYPE0, AIRETL,
- "IRETQ", LTYPE0, AIRETQ,
- "IRETW", LTYPE0, AIRETW,
-
- "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
- "JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
- "JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS, /* carry set (CF = 1) */
- "JB", LTYPER, AJCS, /* alternate */
- "JC", LTYPER, AJCS, /* alternate */
- "JNAE", LTYPER, AJCS, /* alternate */
- "JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
- "JAE", LTYPER, AJCC, /* alternate */
- "JNB", LTYPER, AJCC, /* alternate */
- "JNC", LTYPER, AJCC, /* alternate */
- "JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
- "JE", LTYPER, AJEQ, /* alternate */
- "JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
- "JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
- "JBE", LTYPER, AJLS, /* alternate */
- "JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
- "JA", LTYPER, AJHI, /* alternate */
- "JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
- "JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
- "JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS, /* parity set (PF = 1) */
- "JP", LTYPER, AJPS, /* alternate */
- "JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
- "JNP", LTYPER, AJPC, /* alternate */
- "JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
- "JL", LTYPER, AJLT, /* alternate */
- "JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
- "JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
- "JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
- "JG", LTYPER, AJGT, /* alternate */
- "JNLE", LTYPER, AJGT, /* alternate */
- "JCXZL", LTYPER, AJCXZL,
- "JCXZQ", LTYPER, AJCXZQ,
- "JMP", LTYPEC, AJMP,
- "LAHF", LTYPE0, ALAHF,
- "LARL", LTYPE3, ALARL,
- "LARW", LTYPE3, ALARW,
- "LEAL", LTYPE3, ALEAL,
- "LEAQ", LTYPE3, ALEAQ,
- "LEAW", LTYPE3, ALEAW,
- "LEAVEL", LTYPE0, ALEAVEL,
- "LEAVEQ", LTYPE0, ALEAVEQ,
- "LEAVEW", LTYPE0, ALEAVEW,
- "LFENCE", LTYPE0, ALFENCE,
- "LOCK", LTYPE0, ALOCK,
- "LODSB", LTYPE0, ALODSB,
- "LODSL", LTYPE0, ALODSL,
- "LODSQ", LTYPE0, ALODSQ,
- "LODSW", LTYPE0, ALODSW,
- "LONG", LTYPE2, ALONG,
- "LOOP", LTYPER, ALOOP,
- "LOOPEQ", LTYPER, ALOOPEQ,
- "LOOPNE", LTYPER, ALOOPNE,
- "LSLL", LTYPE3, ALSLL,
- "LSLW", LTYPE3, ALSLW,
- "MFENCE", LTYPE0, AMFENCE,
- "MODE", LTYPE2, AMODE,
- "MOVB", LTYPE3, AMOVB,
- "MOVL", LTYPEM, AMOVL,
- "MOVQ", LTYPEM, AMOVQ,
- "MOVW", LTYPEM, AMOVW,
- "MOVBLSX", LTYPE3, AMOVBLSX,
- "MOVBLZX", LTYPE3, AMOVBLZX,
- "MOVBQSX", LTYPE3, AMOVBQSX,
- "MOVBQZX", LTYPE3, AMOVBQZX,
- "MOVBWSX", LTYPE3, AMOVBWSX,
- "MOVBWZX", LTYPE3, AMOVBWZX,
- "MOVLQSX", LTYPE3, AMOVLQSX,
- "MOVLQZX", LTYPE3, AMOVLQZX,
- "MOVNTIL", LTYPE3, AMOVNTIL,
- "MOVNTIQ", LTYPE3, AMOVNTIQ,
- "MOVQL", LTYPE3, AMOVQL,
- "MOVWLSX", LTYPE3, AMOVWLSX,
- "MOVWLZX", LTYPE3, AMOVWLZX,
- "MOVWQSX", LTYPE3, AMOVWQSX,
- "MOVWQZX", LTYPE3, AMOVWQZX,
- "MOVSB", LTYPE0, AMOVSB,
- "MOVSL", LTYPE0, AMOVSL,
- "MOVSQ", LTYPE0, AMOVSQ,
- "MOVSW", LTYPE0, AMOVSW,
- "MULB", LTYPE2, AMULB,
- "MULL", LTYPE2, AMULL,
- "MULQ", LTYPE2, AMULQ,
- "MULW", LTYPE2, AMULW,
- "NEGB", LTYPE1, ANEGB,
- "NEGL", LTYPE1, ANEGL,
- "NEGQ", LTYPE1, ANEGQ,
- "NEGW", LTYPE1, ANEGW,
- "NOP", LTYPEN, ANOP,
- "NOTB", LTYPE1, ANOTB,
- "NOTL", LTYPE1, ANOTL,
- "NOTQ", LTYPE1, ANOTQ,
- "NOTW", LTYPE1, ANOTW,
- "ORB", LTYPE3, AORB,
- "ORL", LTYPE3, AORL,
- "ORQ", LTYPE3, AORQ,
- "ORW", LTYPE3, AORW,
- "OUTB", LTYPE0, AOUTB,
- "OUTL", LTYPE0, AOUTL,
- "OUTW", LTYPE0, AOUTW,
- "OUTSB", LTYPE0, AOUTSB,
- "OUTSL", LTYPE0, AOUTSL,
- "OUTSW", LTYPE0, AOUTSW,
- "PAUSE", LTYPEN, APAUSE,
- "POPAL", LTYPE0, APOPAL,
- "POPAW", LTYPE0, APOPAW,
- "POPFL", LTYPE0, APOPFL,
- "POPFQ", LTYPE0, APOPFQ,
- "POPFW", LTYPE0, APOPFW,
- "POPL", LTYPE1, APOPL,
- "POPQ", LTYPE1, APOPQ,
- "POPW", LTYPE1, APOPW,
- "PUSHAL", LTYPE0, APUSHAL,
- "PUSHAW", LTYPE0, APUSHAW,
- "PUSHFL", LTYPE0, APUSHFL,
- "PUSHFQ", LTYPE0, APUSHFQ,
- "PUSHFW", LTYPE0, APUSHFW,
- "PUSHL", LTYPE2, APUSHL,
- "PUSHQ", LTYPE2, APUSHQ,
- "PUSHW", LTYPE2, APUSHW,
- "RCLB", LTYPE3, ARCLB,
- "RCLL", LTYPE3, ARCLL,
- "RCLQ", LTYPE3, ARCLQ,
- "RCLW", LTYPE3, ARCLW,
- "RCRB", LTYPE3, ARCRB,
- "RCRL", LTYPE3, ARCRL,
- "RCRQ", LTYPE3, ARCRQ,
- "RCRW", LTYPE3, ARCRW,
- "RDMSR", LTYPE0, ARDMSR,
- "RDPMC", LTYPE0, ARDPMC,
- "RDTSC", LTYPE0, ARDTSC,
- "REP", LTYPE0, AREP,
- "REPN", LTYPE0, AREPN,
- "RET", LTYPE0, ARET,
- "RETFL", LTYPERT,ARETFL,
- "RETFW", LTYPERT,ARETFW,
- "RETFQ", LTYPERT,ARETFQ,
- "ROLB", LTYPE3, AROLB,
- "ROLL", LTYPE3, AROLL,
- "ROLQ", LTYPE3, AROLQ,
- "ROLW", LTYPE3, AROLW,
- "RORB", LTYPE3, ARORB,
- "RORL", LTYPE3, ARORL,
- "RORQ", LTYPE3, ARORQ,
- "RORW", LTYPE3, ARORW,
- "RSM", LTYPE0, ARSM,
- "SAHF", LTYPE0, ASAHF,
- "SALB", LTYPE3, ASALB,
- "SALL", LTYPE3, ASALL,
- "SALQ", LTYPE3, ASALQ,
- "SALW", LTYPE3, ASALW,
- "SARB", LTYPE3, ASARB,
- "SARL", LTYPE3, ASARL,
- "SARQ", LTYPE3, ASARQ,
- "SARW", LTYPE3, ASARW,
- "SBBB", LTYPE3, ASBBB,
- "SBBL", LTYPE3, ASBBL,
- "SBBQ", LTYPE3, ASBBQ,
- "SBBW", LTYPE3, ASBBW,
- "SCASB", LTYPE0, ASCASB,
- "SCASL", LTYPE0, ASCASL,
- "SCASQ", LTYPE0, ASCASQ,
- "SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
- "SETCS", LTYPE1, ASETCS,
- "SETEQ", LTYPE1, ASETEQ,
- "SETGE", LTYPE1, ASETGE,
- "SETGT", LTYPE1, ASETGT,
- "SETHI", LTYPE1, ASETHI,
- "SETLE", LTYPE1, ASETLE,
- "SETLS", LTYPE1, ASETLS,
- "SETLT", LTYPE1, ASETLT,
- "SETMI", LTYPE1, ASETMI,
- "SETNE", LTYPE1, ASETNE,
- "SETOC", LTYPE1, ASETOC,
- "SETOS", LTYPE1, ASETOS,
- "SETPC", LTYPE1, ASETPC,
- "SETPL", LTYPE1, ASETPL,
- "SETPS", LTYPE1, ASETPS,
- "SFENCE", LTYPE0, ASFENCE,
- "CDQ", LTYPE0, ACDQ,
- "CWD", LTYPE0, ACWD,
- "CQO", LTYPE0, ACQO,
- "SHLB", LTYPE3, ASHLB,
- "SHLL", LTYPES, ASHLL,
- "SHLQ", LTYPES, ASHLQ,
- "SHLW", LTYPES, ASHLW,
- "SHRB", LTYPE3, ASHRB,
- "SHRL", LTYPES, ASHRL,
- "SHRQ", LTYPES, ASHRQ,
- "SHRW", LTYPES, ASHRW,
- "STC", LTYPE0, ASTC,
- "STD", LTYPE0, ASTD,
- "STI", LTYPE0, ASTI,
- "STOSB", LTYPE0, ASTOSB,
- "STOSL", LTYPE0, ASTOSL,
- "STOSQ", LTYPE0, ASTOSQ,
- "STOSW", LTYPE0, ASTOSW,
- "SUBB", LTYPE3, ASUBB,
- "SUBL", LTYPE3, ASUBL,
- "SUBQ", LTYPE3, ASUBQ,
- "SUBW", LTYPE3, ASUBW,
- "SYSCALL", LTYPE0, ASYSCALL,
- "SYSRET", LTYPE0, ASYSRET,
- "SWAPGS", LTYPE0, ASWAPGS,
- "TESTB", LTYPE3, ATESTB,
- "TESTL", LTYPE3, ATESTL,
- "TESTQ", LTYPE3, ATESTQ,
- "TESTW", LTYPE3, ATESTW,
- "TEXT", LTYPET, ATEXT,
- "VERR", LTYPE2, AVERR,
- "VERW", LTYPE2, AVERW,
- "QUAD", LTYPE2, AQUAD,
- "WAIT", LTYPE0, AWAIT,
- "WBINVD", LTYPE0, AWBINVD,
- "WRMSR", LTYPE0, AWRMSR,
- "WORD", LTYPE2, AWORD,
- "XADDB", LTYPE3, AXADDB,
- "XADDL", LTYPE3, AXADDL,
- "XADDQ", LTYPE3, AXADDQ,
- "XADDW", LTYPE3, AXADDW,
- "XCHGB", LTYPE3, AXCHGB,
- "XCHGL", LTYPE3, AXCHGL,
- "XCHGQ", LTYPE3, AXCHGQ,
- "XCHGW", LTYPE3, AXCHGW,
- "XLAT", LTYPE2, AXLAT,
- "XORB", LTYPE3, AXORB,
- "XORL", LTYPE3, AXORL,
- "XORQ", LTYPE3, AXORQ,
- "XORW", LTYPE3, AXORW,
-
- "CMOVLCC", LTYPE3, ACMOVLCC,
- "CMOVLCS", LTYPE3, ACMOVLCS,
- "CMOVLEQ", LTYPE3, ACMOVLEQ,
- "CMOVLGE", LTYPE3, ACMOVLGE,
- "CMOVLGT", LTYPE3, ACMOVLGT,
- "CMOVLHI", LTYPE3, ACMOVLHI,
- "CMOVLLE", LTYPE3, ACMOVLLE,
- "CMOVLLS", LTYPE3, ACMOVLLS,
- "CMOVLLT", LTYPE3, ACMOVLLT,
- "CMOVLMI", LTYPE3, ACMOVLMI,
- "CMOVLNE", LTYPE3, ACMOVLNE,
- "CMOVLOC", LTYPE3, ACMOVLOC,
- "CMOVLOS", LTYPE3, ACMOVLOS,
- "CMOVLPC", LTYPE3, ACMOVLPC,
- "CMOVLPL", LTYPE3, ACMOVLPL,
- "CMOVLPS", LTYPE3, ACMOVLPS,
- "CMOVQCC", LTYPE3, ACMOVQCC,
- "CMOVQCS", LTYPE3, ACMOVQCS,
- "CMOVQEQ", LTYPE3, ACMOVQEQ,
- "CMOVQGE", LTYPE3, ACMOVQGE,
- "CMOVQGT", LTYPE3, ACMOVQGT,
- "CMOVQHI", LTYPE3, ACMOVQHI,
- "CMOVQLE", LTYPE3, ACMOVQLE,
- "CMOVQLS", LTYPE3, ACMOVQLS,
- "CMOVQLT", LTYPE3, ACMOVQLT,
- "CMOVQMI", LTYPE3, ACMOVQMI,
- "CMOVQNE", LTYPE3, ACMOVQNE,
- "CMOVQOC", LTYPE3, ACMOVQOC,
- "CMOVQOS", LTYPE3, ACMOVQOS,
- "CMOVQPC", LTYPE3, ACMOVQPC,
- "CMOVQPL", LTYPE3, ACMOVQPL,
- "CMOVQPS", LTYPE3, ACMOVQPS,
- "CMOVWCC", LTYPE3, ACMOVWCC,
- "CMOVWCS", LTYPE3, ACMOVWCS,
- "CMOVWEQ", LTYPE3, ACMOVWEQ,
- "CMOVWGE", LTYPE3, ACMOVWGE,
- "CMOVWGT", LTYPE3, ACMOVWGT,
- "CMOVWHI", LTYPE3, ACMOVWHI,
- "CMOVWLE", LTYPE3, ACMOVWLE,
- "CMOVWLS", LTYPE3, ACMOVWLS,
- "CMOVWLT", LTYPE3, ACMOVWLT,
- "CMOVWMI", LTYPE3, ACMOVWMI,
- "CMOVWNE", LTYPE3, ACMOVWNE,
- "CMOVWOC", LTYPE3, ACMOVWOC,
- "CMOVWOS", LTYPE3, ACMOVWOS,
- "CMOVWPC", LTYPE3, ACMOVWPC,
- "CMOVWPL", LTYPE3, ACMOVWPL,
- "CMOVWPS", LTYPE3, ACMOVWPS,
-
- "FMOVB", LTYPE3, AFMOVB,
- "FMOVBP", LTYPE3, AFMOVBP,
- "FMOVD", LTYPE3, AFMOVD,
- "FMOVDP", LTYPE3, AFMOVDP,
- "FMOVF", LTYPE3, AFMOVF,
- "FMOVFP", LTYPE3, AFMOVFP,
- "FMOVL", LTYPE3, AFMOVL,
- "FMOVLP", LTYPE3, AFMOVLP,
- "FMOVV", LTYPE3, AFMOVV,
- "FMOVVP", LTYPE3, AFMOVVP,
- "FMOVW", LTYPE3, AFMOVW,
- "FMOVWP", LTYPE3, AFMOVWP,
- "FMOVX", LTYPE3, AFMOVX,
- "FMOVXP", LTYPE3, AFMOVXP,
- "FCOMB", LTYPE3, AFCOMB,
- "FCOMBP", LTYPE3, AFCOMBP,
- "FCOMD", LTYPE3, AFCOMD,
- "FCOMDP", LTYPE3, AFCOMDP,
- "FCOMDPP", LTYPE3, AFCOMDPP,
- "FCOMF", LTYPE3, AFCOMF,
- "FCOMFP", LTYPE3, AFCOMFP,
- "FCOML", LTYPE3, AFCOML,
- "FCOMLP", LTYPE3, AFCOMLP,
- "FCOMW", LTYPE3, AFCOMW,
- "FCOMWP", LTYPE3, AFCOMWP,
- "FUCOM", LTYPE3, AFUCOM,
- "FUCOMP", LTYPE3, AFUCOMP,
- "FUCOMPP", LTYPE3, AFUCOMPP,
- "FADDW", LTYPE3, AFADDW,
- "FADDL", LTYPE3, AFADDL,
- "FADDF", LTYPE3, AFADDF,
- "FADDD", LTYPE3, AFADDD,
- "FADDDP", LTYPE3, AFADDDP,
- "FSUBDP", LTYPE3, AFSUBDP,
- "FSUBW", LTYPE3, AFSUBW,
- "FSUBL", LTYPE3, AFSUBL,
- "FSUBF", LTYPE3, AFSUBF,
- "FSUBD", LTYPE3, AFSUBD,
- "FSUBRDP", LTYPE3, AFSUBRDP,
- "FSUBRW", LTYPE3, AFSUBRW,
- "FSUBRL", LTYPE3, AFSUBRL,
- "FSUBRF", LTYPE3, AFSUBRF,
- "FSUBRD", LTYPE3, AFSUBRD,
- "FMULDP", LTYPE3, AFMULDP,
- "FMULW", LTYPE3, AFMULW,
- "FMULL", LTYPE3, AFMULL,
- "FMULF", LTYPE3, AFMULF,
- "FMULD", LTYPE3, AFMULD,
- "FDIVDP", LTYPE3, AFDIVDP,
- "FDIVW", LTYPE3, AFDIVW,
- "FDIVL", LTYPE3, AFDIVL,
- "FDIVF", LTYPE3, AFDIVF,
- "FDIVD", LTYPE3, AFDIVD,
- "FDIVRDP", LTYPE3, AFDIVRDP,
- "FDIVRW", LTYPE3, AFDIVRW,
- "FDIVRL", LTYPE3, AFDIVRL,
- "FDIVRF", LTYPE3, AFDIVRF,
- "FDIVRD", LTYPE3, AFDIVRD,
- "FXCHD", LTYPE3, AFXCHD,
- "FFREE", LTYPE1, AFFREE,
- "FLDCW", LTYPE2, AFLDCW,
- "FLDENV", LTYPE1, AFLDENV,
- "FRSTOR", LTYPE2, AFRSTOR,
- "FSAVE", LTYPE1, AFSAVE,
- "FSTCW", LTYPE1, AFSTCW,
- "FSTENV", LTYPE1, AFSTENV,
- "FSTSW", LTYPE1, AFSTSW,
- "F2XM1", LTYPE0, AF2XM1,
- "FABS", LTYPE0, AFABS,
- "FCHS", LTYPE0, AFCHS,
- "FCLEX", LTYPE0, AFCLEX,
- "FCOS", LTYPE0, AFCOS,
- "FDECSTP", LTYPE0, AFDECSTP,
- "FINCSTP", LTYPE0, AFINCSTP,
- "FINIT", LTYPE0, AFINIT,
- "FLD1", LTYPE0, AFLD1,
- "FLDL2E", LTYPE0, AFLDL2E,
- "FLDL2T", LTYPE0, AFLDL2T,
- "FLDLG2", LTYPE0, AFLDLG2,
- "FLDLN2", LTYPE0, AFLDLN2,
- "FLDPI", LTYPE0, AFLDPI,
- "FLDZ", LTYPE0, AFLDZ,
- "FNOP", LTYPE0, AFNOP,
- "FPATAN", LTYPE0, AFPATAN,
- "FPREM", LTYPE0, AFPREM,
- "FPREM1", LTYPE0, AFPREM1,
- "FPTAN", LTYPE0, AFPTAN,
- "FRNDINT", LTYPE0, AFRNDINT,
- "FSCALE", LTYPE0, AFSCALE,
- "FSIN", LTYPE0, AFSIN,
- "FSINCOS", LTYPE0, AFSINCOS,
- "FSQRT", LTYPE0, AFSQRT,
- "FTST", LTYPE0, AFTST,
- "FXAM", LTYPE0, AFXAM,
- "FXTRACT", LTYPE0, AFXTRACT,
- "FYL2X", LTYPE0, AFYL2X,
- "FYL2XP1", LTYPE0, AFYL2XP1,
-
- "ADDPD", LTYPE3, AADDPD,
- "ADDPS", LTYPE3, AADDPS,
- "ADDSD", LTYPE3, AADDSD,
- "ADDSS", LTYPE3, AADDSS,
- "ANDNPD", LTYPE3, AANDNPD,
- "ANDNPS", LTYPE3, AANDNPS,
- "ANDPD", LTYPE3, AANDPD,
- "ANDPS", LTYPE3, AANDPS,
- "CMPPD", LTYPEXC,ACMPPD,
- "CMPPS", LTYPEXC,ACMPPS,
- "CMPSD", LTYPEXC,ACMPSD,
- "CMPSS", LTYPEXC,ACMPSS,
- "COMISD", LTYPE3, ACOMISD,
- "COMISS", LTYPE3, ACOMISS,
- "CVTPL2PD", LTYPE3, ACVTPL2PD,
- "CVTPL2PS", LTYPE3, ACVTPL2PS,
- "CVTPD2PL", LTYPE3, ACVTPD2PL,
- "CVTPD2PS", LTYPE3, ACVTPD2PS,
- "CVTPS2PL", LTYPE3, ACVTPS2PL,
- "PF2IW", LTYPE3, APF2IW,
- "PF2IL", LTYPE3, APF2IL,
- "PF2ID", LTYPE3, APF2IL, /* syn */
- "PI2FL", LTYPE3, API2FL,
- "PI2FD", LTYPE3, API2FL, /* syn */
- "PI2FW", LTYPE3, API2FW,
- "CVTPS2PD", LTYPE3, ACVTPS2PD,
- "CVTSD2SL", LTYPE3, ACVTSD2SL,
- "CVTSD2SQ", LTYPE3, ACVTSD2SQ,
- "CVTSD2SS", LTYPE3, ACVTSD2SS,
- "CVTSL2SD", LTYPE3, ACVTSL2SD,
- "CVTSQ2SD", LTYPE3, ACVTSQ2SD,
- "CVTSL2SS", LTYPE3, ACVTSL2SS,
- "CVTSQ2SS", LTYPE3, ACVTSQ2SS,
- "CVTSS2SD", LTYPE3, ACVTSS2SD,
- "CVTSS2SL", LTYPE3, ACVTSS2SL,
- "CVTSS2SQ", LTYPE3, ACVTSS2SQ,
- "CVTTPD2PL", LTYPE3, ACVTTPD2PL,
- "CVTTPS2PL", LTYPE3, ACVTTPS2PL,
- "CVTTSD2SL", LTYPE3, ACVTTSD2SL,
- "CVTTSD2SQ", LTYPE3, ACVTTSD2SQ,
- "CVTTSS2SL", LTYPE3, ACVTTSS2SL,
- "CVTTSS2SQ", LTYPE3, ACVTTSS2SQ,
- "DIVPD", LTYPE3, ADIVPD,
- "DIVPS", LTYPE3, ADIVPS,
- "DIVSD", LTYPE3, ADIVSD,
- "DIVSS", LTYPE3, ADIVSS,
- "FXRSTOR", LTYPE2, AFXRSTOR,
- "FXRSTOR64", LTYPE2, AFXRSTOR64,
- "FXSAVE", LTYPE1, AFXSAVE,
- "FXSAVE64", LTYPE1, AFXSAVE64,
- "LDMXCSR", LTYPE2, ALDMXCSR,
- "MASKMOVOU", LTYPE3, AMASKMOVOU,
- "MASKMOVDQU", LTYPE3, AMASKMOVOU, /* syn */
- "MASKMOVQ", LTYPE3, AMASKMOVQ,
- "MAXPD", LTYPE3, AMAXPD,
- "MAXPS", LTYPE3, AMAXPS,
- "MAXSD", LTYPE3, AMAXSD,
- "MAXSS", LTYPE3, AMAXSS,
- "MINPD", LTYPE3, AMINPD,
- "MINPS", LTYPE3, AMINPS,
- "MINSD", LTYPE3, AMINSD,
- "MINSS", LTYPE3, AMINSS,
- "MOVAPD", LTYPE3, AMOVAPD,
- "MOVAPS", LTYPE3, AMOVAPS,
- "MOVD", LTYPE3, AMOVQ, /* syn */
- "MOVDQ2Q", LTYPE3, AMOVQ, /* syn */
- "MOVO", LTYPE3, AMOVO,
- "MOVOA", LTYPE3, AMOVO, /* syn */
- "MOVOU", LTYPE3, AMOVOU,
- "MOVHLPS", LTYPE3, AMOVHLPS,
- "MOVHPD", LTYPE3, AMOVHPD,
- "MOVHPS", LTYPE3, AMOVHPS,
- "MOVLHPS", LTYPE3, AMOVLHPS,
- "MOVLPD", LTYPE3, AMOVLPD,
- "MOVLPS", LTYPE3, AMOVLPS,
- "MOVMSKPD", LTYPE3, AMOVMSKPD,
- "MOVMSKPS", LTYPE3, AMOVMSKPS,
- "MOVNTO", LTYPE3, AMOVNTO,
- "MOVNTDQ", LTYPE3, AMOVNTO, /* syn */
- "MOVNTPD", LTYPE3, AMOVNTPD,
- "MOVNTPS", LTYPE3, AMOVNTPS,
- "MOVNTQ", LTYPE3, AMOVNTQ,
- "MOVQOZX", LTYPE3, AMOVQOZX,
- "MOVSD", LTYPE3, AMOVSD,
- "MOVSS", LTYPE3, AMOVSS,
- "MOVUPD", LTYPE3, AMOVUPD,
- "MOVUPS", LTYPE3, AMOVUPS,
- "MULPD", LTYPE3, AMULPD,
- "MULPS", LTYPE3, AMULPS,
- "MULSD", LTYPE3, AMULSD,
- "MULSS", LTYPE3, AMULSS,
- "ORPD", LTYPE3, AORPD,
- "ORPS", LTYPE3, AORPS,
- "PACKSSLW", LTYPE3, APACKSSLW,
- "PACKSSWB", LTYPE3, APACKSSWB,
- "PACKUSWB", LTYPE3, APACKUSWB,
- "PADDB", LTYPE3, APADDB,
- "PADDL", LTYPE3, APADDL,
- "PADDQ", LTYPE3, APADDQ,
- "PADDSB", LTYPE3, APADDSB,
- "PADDSW", LTYPE3, APADDSW,
- "PADDUSB", LTYPE3, APADDUSB,
- "PADDUSW", LTYPE3, APADDUSW,
- "PADDW", LTYPE3, APADDW,
- "PAND", LTYPE3, APAND,
- "PANDB", LTYPE3, APANDB,
- "PANDL", LTYPE3, APANDL,
- "PANDSB", LTYPE3, APANDSB,
- "PANDSW", LTYPE3, APANDSW,
- "PANDUSB", LTYPE3, APANDUSB,
- "PANDUSW", LTYPE3, APANDUSW,
- "PANDW", LTYPE3, APANDW,
- "PANDN", LTYPE3, APANDN,
- "PAVGB", LTYPE3, APAVGB,
- "PAVGW", LTYPE3, APAVGW,
- "PCMPEQB", LTYPE3, APCMPEQB,
- "PCMPEQL", LTYPE3, APCMPEQL,
- "PCMPEQW", LTYPE3, APCMPEQW,
- "PCMPGTB", LTYPE3, APCMPGTB,
- "PCMPGTL", LTYPE3, APCMPGTL,
- "PCMPGTW", LTYPE3, APCMPGTW,
- "PEXTRW", LTYPEX, APEXTRW,
- "PINSRW", LTYPEX, APINSRW,
- "PINSRD", LTYPEX, APINSRD,
- "PINSRQ", LTYPEX, APINSRQ,
- "PMADDWL", LTYPE3, APMADDWL,
- "PMAXSW", LTYPE3, APMAXSW,
- "PMAXUB", LTYPE3, APMAXUB,
- "PMINSW", LTYPE3, APMINSW,
- "PMINUB", LTYPE3, APMINUB,
- "PMOVMSKB", LTYPE3, APMOVMSKB,
- "PMULHRW", LTYPE3, APMULHRW,
- "PMULHUW", LTYPE3, APMULHUW,
- "PMULHW", LTYPE3, APMULHW,
- "PMULLW", LTYPE3, APMULLW,
- "PMULULQ", LTYPE3, APMULULQ,
- "POR", LTYPE3, APOR,
- "PSADBW", LTYPE3, APSADBW,
- "PSHUFHW", LTYPEX, APSHUFHW,
- "PSHUFL", LTYPEX, APSHUFL,
- "PSHUFLW", LTYPEX, APSHUFLW,
- "PSHUFW", LTYPEX, APSHUFW,
- "PSHUFB", LTYPEM, APSHUFB,
- "PSLLO", LTYPE3, APSLLO,
- "PSLLDQ", LTYPE3, APSLLO, /* syn */
- "PSLLL", LTYPE3, APSLLL,
- "PSLLQ", LTYPE3, APSLLQ,
- "PSLLW", LTYPE3, APSLLW,
- "PSRAL", LTYPE3, APSRAL,
- "PSRAW", LTYPE3, APSRAW,
- "PSRLO", LTYPE3, APSRLO,
- "PSRLDQ", LTYPE3, APSRLO, /* syn */
- "PSRLL", LTYPE3, APSRLL,
- "PSRLQ", LTYPE3, APSRLQ,
- "PSRLW", LTYPE3, APSRLW,
- "PSUBB", LTYPE3, APSUBB,
- "PSUBL", LTYPE3, APSUBL,
- "PSUBQ", LTYPE3, APSUBQ,
- "PSUBSB", LTYPE3, APSUBSB,
- "PSUBSW", LTYPE3, APSUBSW,
- "PSUBUSB", LTYPE3, APSUBUSB,
- "PSUBUSW", LTYPE3, APSUBUSW,
- "PSUBW", LTYPE3, APSUBW,
- "PUNPCKHBW", LTYPE3, APUNPCKHBW,
- "PUNPCKHLQ", LTYPE3, APUNPCKHLQ,
- "PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
- "PUNPCKHWL", LTYPE3, APUNPCKHWL,
- "PUNPCKLBW", LTYPE3, APUNPCKLBW,
- "PUNPCKLLQ", LTYPE3, APUNPCKLLQ,
- "PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
- "PUNPCKLWL", LTYPE3, APUNPCKLWL,
- "PXOR", LTYPE3, APXOR,
- "RCPPS", LTYPE3, ARCPPS,
- "RCPSS", LTYPE3, ARCPSS,
- "RSQRTPS", LTYPE3, ARSQRTPS,
- "RSQRTSS", LTYPE3, ARSQRTSS,
- "SHUFPD", LTYPEX, ASHUFPD,
- "SHUFPS", LTYPEX, ASHUFPS,
- "SQRTPD", LTYPE3, ASQRTPD,
- "SQRTPS", LTYPE3, ASQRTPS,
- "SQRTSD", LTYPE3, ASQRTSD,
- "SQRTSS", LTYPE3, ASQRTSS,
- "STMXCSR", LTYPE1, ASTMXCSR,
- "SUBPD", LTYPE3, ASUBPD,
- "SUBPS", LTYPE3, ASUBPS,
- "SUBSD", LTYPE3, ASUBSD,
- "SUBSS", LTYPE3, ASUBSS,
- "UCOMISD", LTYPE3, AUCOMISD,
- "UCOMISS", LTYPE3, AUCOMISS,
- "UNPCKHPD", LTYPE3, AUNPCKHPD,
- "UNPCKHPS", LTYPE3, AUNPCKHPS,
- "UNPCKLPD", LTYPE3, AUNPCKLPD,
- "UNPCKLPS", LTYPE3, AUNPCKLPS,
- "XORPD", LTYPE3, AXORPD,
- "XORPS", LTYPE3, AXORPS,
- "CRC32B", LTYPE4, ACRC32B,
- "CRC32Q", LTYPE4, ACRC32Q,
- "PREFETCHT0", LTYPE2, APREFETCHT0,
- "PREFETCHT1", LTYPE2, APREFETCHT1,
- "PREFETCHT2", LTYPE2, APREFETCHT2,
- "PREFETCHNTA", LTYPE2, APREFETCHNTA,
- "UNDEF", LTYPE0, AUNDEF,
- "AESENC", LTYPE3, AAESENC,
- "AESENCLAST", LTYPE3, AAESENCLAST,
- "AESDEC", LTYPE3, AAESDEC,
- "AESDECLAST", LTYPE3, AAESDECLAST,
- "AESIMC", LTYPE3, AAESIMC,
- "AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST,
- "PSHUFD", LTYPEX, APSHUFD,
- "USEFIELD", LTYPEN, AUSEFIELD,
- "PCLMULQDQ", LTYPEX, APCLMULQDQ,
- "PCDATA", LTYPEPC, APCDATA,
- "FUNCDATA", LTYPEF, AFUNCDATA,
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.type = TYPE_NONE;
- nullgen.index = TYPE_NONE;
-
- nerrors = 0;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- if(s->type != LNAME)
- yyerror("double initialization %s", itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-}
-
-void
-checkscale(int scale)
-{
-
- switch(scale) {
- case 1:
- case 2:
- case 4:
- case 8:
- return;
- }
- yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-void
-cclean(void)
-{
- Addr2 g2;
-
- g2.from = nullgen;
- g2.to = nullgen;
- outcode(AEND, &g2);
-}
-
-void
-outcode(int a, Addr2 *g2)
-{
- Prog *p;
- Plist *pl;
-
- if(pass == 1)
- goto out;
-
- p = malloc(sizeof *p);
- memset(p, 0, sizeof *p);
- p->as = a;
- p->lineno = stmtline;
- p->from = g2->from;
- p->to = g2->to;
- p->pc = pc;
-
- if(lastpc == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastpc->link = p;
- lastpc = p;
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/new6a/lex.go b/src/cmd/6a/lex.go
index db4247f045..db4247f045 100644
--- a/src/cmd/new6a/lex.go
+++ b/src/cmd/6a/lex.go
diff --git a/src/cmd/new6a/y.go b/src/cmd/6a/y.go
index 0b78d2e1e2..0b78d2e1e2 100644
--- a/src/cmd/new6a/y.go
+++ b/src/cmd/6a/y.go
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
deleted file mode 100644
index a3ee581d69..0000000000
--- a/src/cmd/6a/y.tab.c
+++ /dev/null
@@ -1,2800 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE0 = 258,
- LTYPE1 = 259,
- LTYPE2 = 260,
- LTYPE3 = 261,
- LTYPE4 = 262,
- LTYPEC = 263,
- LTYPED = 264,
- LTYPEN = 265,
- LTYPER = 266,
- LTYPET = 267,
- LTYPEG = 268,
- LTYPEPC = 269,
- LTYPES = 270,
- LTYPEM = 271,
- LTYPEI = 272,
- LTYPEXC = 273,
- LTYPEX = 274,
- LTYPERT = 275,
- LTYPEF = 276,
- LCONST = 277,
- LFP = 278,
- LPC = 279,
- LSB = 280,
- LBREG = 281,
- LLREG = 282,
- LSREG = 283,
- LFREG = 284,
- LMREG = 285,
- LXREG = 286,
- LFCONST = 287,
- LSCONST = 288,
- LSP = 289,
- LNAME = 290,
- LLAB = 291,
- LVAR = 292
- };
-#endif
-/* Tokens. */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPEG 268
-#define LTYPEPC 269
-#define LTYPES 270
-#define LTYPEM 271
-#define LTYPEI 272
-#define LTYPEXC 273
-#define LTYPEX 274
-#define LTYPERT 275
-#define LTYPEF 276
-#define LCONST 277
-#define LFP 278
-#define LPC 279
-#define LSB 280
-#define LBREG 281
-#define LLREG 282
-#define LSREG 283
-#define LFREG 284
-#define LMREG 285
-#define LXREG 286
-#define LFCONST 287
-#define LSCONST 288
-#define LSP 289
-#define LNAME 290
-#define LLAB 291
-#define LVAR 292
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
-}
-/* Line 193 of yacc.c. */
-#line 187 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 200 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 524
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 56
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 40
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 133
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 271
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 292
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 52, 12, 5, 2,
- 53, 54, 10, 8, 51, 9, 2, 11, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 48, 49,
- 6, 50, 7, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 2, 55, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 5, 9, 10, 15, 17, 20,
- 23, 27, 31, 34, 37, 40, 43, 46, 49, 51,
- 53, 56, 59, 62, 65, 68, 71, 74, 77, 79,
- 82, 85, 86, 88, 92, 96, 99, 101, 104, 106,
- 109, 111, 115, 122, 128, 136, 141, 148, 151, 153,
- 155, 157, 161, 167, 171, 177, 180, 182, 186, 192,
- 198, 199, 201, 205, 209, 211, 213, 215, 217, 220,
- 223, 225, 227, 229, 231, 236, 239, 241, 243, 245,
- 247, 249, 251, 253, 256, 259, 262, 265, 270, 276,
- 280, 282, 284, 286, 291, 296, 301, 308, 318, 328,
- 332, 336, 342, 351, 353, 360, 366, 374, 375, 378,
- 381, 383, 385, 387, 389, 391, 394, 397, 400, 404,
- 406, 409, 413, 418, 420, 424, 428, 432, 436, 440,
- 445, 450, 454, 458
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 57, 0, -1, -1, -1, 57, 58, 59, -1, -1,
- 45, 48, 60, 59, -1, 49, -1, 61, 49, -1,
- 1, 49, -1, 45, 50, 95, -1, 47, 50, 95,
- -1, 13, 62, -1, 14, 66, -1, 15, 65, -1,
- 16, 63, -1, 17, 64, -1, 21, 67, -1, 68,
- -1, 69, -1, 18, 71, -1, 20, 72, -1, 25,
- 73, -1, 26, 74, -1, 27, 75, -1, 28, 76,
- -1, 29, 77, -1, 30, 78, -1, 70, -1, 24,
- 79, -1, 31, 80, -1, -1, 51, -1, 83, 51,
- 81, -1, 81, 51, 83, -1, 83, 51, -1, 83,
- -1, 51, 81, -1, 81, -1, 51, 84, -1, 84,
- -1, 86, 51, 84, -1, 19, 90, 11, 93, 51,
- 86, -1, 22, 87, 51, 52, 94, -1, 22, 87,
- 51, 93, 51, 52, 94, -1, 23, 87, 51, 86,
- -1, 23, 87, 51, 93, 51, 86, -1, 51, 82,
- -1, 82, -1, 62, -1, 66, -1, 83, 51, 81,
- -1, 83, 51, 81, 48, 37, -1, 83, 51, 81,
- -1, 83, 51, 81, 48, 38, -1, 83, 51, -1,
- 83, -1, 83, 51, 81, -1, 85, 51, 81, 51,
- 93, -1, 86, 51, 81, 51, 85, -1, -1, 86,
- -1, 83, 51, 83, -1, 83, 51, 83, -1, 85,
- -1, 87, -1, 84, -1, 89, -1, 10, 85, -1,
- 10, 88, -1, 85, -1, 88, -1, 81, -1, 86,
- -1, 93, 53, 34, 54, -1, 45, 91, -1, 36,
- -1, 39, -1, 37, -1, 40, -1, 44, -1, 38,
- -1, 41, -1, 52, 93, -1, 52, 90, -1, 52,
- 43, -1, 52, 42, -1, 52, 53, 42, 54, -1,
- 52, 53, 9, 42, 54, -1, 52, 9, 42, -1,
- 88, -1, 89, -1, 93, -1, 93, 53, 37, 54,
- -1, 93, 53, 44, 54, -1, 93, 53, 38, 54,
- -1, 93, 53, 37, 10, 93, 54, -1, 93, 53,
- 37, 54, 53, 37, 10, 93, 54, -1, 93, 53,
- 37, 54, 53, 38, 10, 93, 54, -1, 53, 37,
- 54, -1, 53, 44, 54, -1, 53, 37, 10, 93,
- 54, -1, 53, 37, 54, 53, 37, 10, 93, 54,
- -1, 90, -1, 90, 53, 37, 10, 93, 54, -1,
- 45, 91, 53, 92, 54, -1, 45, 6, 7, 91,
- 53, 35, 54, -1, -1, 8, 93, -1, 9, 93,
- -1, 35, -1, 44, -1, 33, -1, 32, -1, 47,
- -1, 9, 93, -1, 8, 93, -1, 55, 93, -1,
- 53, 95, 54, -1, 32, -1, 9, 32, -1, 32,
- 9, 32, -1, 9, 32, 9, 32, -1, 93, -1,
- 95, 8, 95, -1, 95, 9, 95, -1, 95, 10,
- 95, -1, 95, 11, 95, -1, 95, 12, 95, -1,
- 95, 6, 6, 95, -1, 95, 7, 7, 95, -1,
- 95, 5, 95, -1, 95, 4, 95, -1, 95, 3,
- 95, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 66, 66, 68, 67, 75, 74, 83, 84, 85,
- 88, 93, 99, 100, 101, 102, 103, 104, 105, 106,
- 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
- 117, 120, 124, 131, 138, 145, 150, 157, 162, 169,
- 174, 179, 186, 199, 207, 221, 229, 243, 248, 255,
- 256, 259, 264, 274, 279, 289, 294, 299, 306, 314,
- 324, 328, 335, 344, 355, 356, 359, 360, 361, 365,
- 369, 370, 373, 374, 377, 383, 394, 400, 406, 412,
- 418, 424, 430, 438, 444, 454, 460, 466, 472, 478,
- 486, 487, 490, 496, 503, 510, 517, 526, 536, 546,
- 552, 558, 566, 577, 581, 590, 598, 608, 611, 615,
- 621, 622, 626, 629, 630, 634, 638, 642, 646, 652,
- 659, 666, 673, 682, 683, 687, 691, 695, 699, 703,
- 707, 711, 715, 719
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
- "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
- "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPEG",
- "LTYPEPC", "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT",
- "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG",
- "LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
- "LVAR", "':'", "';'", "'='", "','", "'$'", "'('", "')'", "'~'",
- "$accept", "prog", "@1", "line", "@2", "inst", "nonnon", "rimrem",
- "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec11",
- "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10",
- "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm", "mem",
- "omem", "nmem", "nam", "offset", "pointer", "con", "textsize", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
- 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 58, 59,
- 61, 44, 36, 40, 41, 126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 56, 57, 58, 57, 60, 59, 59, 59, 59,
- 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 62, 62, 63, 64, 65, 65, 66, 66, 67,
- 67, 67, 68, 69, 69, 70, 70, 71, 71, 72,
- 72, 73, 73, 74, 74, 75, 75, 75, 76, 77,
- 78, 78, 79, 80, 81, 81, 82, 82, 82, 82,
- 82, 82, 83, 83, 84, 84, 85, 85, 85, 85,
- 85, 85, 85, 86, 86, 86, 86, 86, 86, 86,
- 87, 87, 88, 88, 88, 88, 88, 88, 88, 88,
- 88, 88, 88, 89, 89, 90, 90, 91, 91, 91,
- 92, 92, 92, 93, 93, 93, 93, 93, 93, 94,
- 94, 94, 94, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 0, 3, 0, 4, 1, 2, 2,
- 3, 3, 2, 2, 2, 2, 2, 2, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
- 2, 0, 1, 3, 3, 2, 1, 2, 1, 2,
- 1, 3, 6, 5, 7, 4, 6, 2, 1, 1,
- 1, 3, 5, 3, 5, 2, 1, 3, 5, 5,
- 0, 1, 3, 3, 1, 1, 1, 1, 2, 2,
- 1, 1, 1, 1, 4, 2, 1, 1, 1, 1,
- 1, 1, 1, 2, 2, 2, 2, 4, 5, 3,
- 1, 1, 1, 4, 4, 4, 6, 9, 9, 3,
- 3, 5, 8, 1, 6, 5, 7, 0, 2, 2,
- 1, 1, 1, 1, 1, 2, 2, 2, 3, 1,
- 2, 3, 4, 1, 3, 3, 3, 3, 3, 4,
- 4, 3, 3, 3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 3, 1, 0, 0, 31, 0, 0, 0, 0,
- 0, 0, 31, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 60, 0, 0, 0, 7, 4, 0, 18,
- 19, 28, 9, 32, 12, 0, 0, 113, 76, 78,
- 81, 77, 79, 82, 80, 107, 114, 0, 0, 0,
- 13, 38, 64, 65, 90, 91, 103, 92, 0, 14,
- 72, 36, 73, 15, 0, 16, 0, 0, 107, 0,
- 20, 48, 66, 70, 71, 67, 92, 0, 32, 49,
- 50, 21, 107, 0, 0, 17, 40, 0, 0, 0,
- 0, 29, 0, 22, 0, 23, 0, 24, 56, 25,
- 0, 26, 0, 27, 61, 30, 0, 5, 0, 0,
- 8, 116, 115, 0, 0, 0, 0, 37, 0, 0,
- 123, 0, 117, 0, 0, 0, 86, 85, 0, 84,
- 83, 35, 0, 0, 68, 69, 75, 47, 0, 0,
- 75, 39, 0, 0, 0, 0, 0, 0, 0, 55,
- 0, 0, 0, 0, 10, 11, 107, 108, 109, 0,
- 0, 99, 100, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 118, 0, 0, 0, 0, 89, 0,
- 0, 33, 34, 0, 0, 41, 0, 0, 45, 0,
- 62, 51, 53, 57, 0, 0, 63, 6, 0, 112,
- 110, 111, 0, 0, 0, 133, 132, 131, 0, 0,
- 124, 125, 126, 127, 128, 0, 0, 93, 95, 94,
- 0, 87, 74, 0, 0, 119, 43, 0, 0, 0,
- 0, 0, 0, 0, 105, 101, 0, 129, 130, 0,
- 0, 0, 88, 42, 120, 0, 0, 46, 52, 54,
- 58, 59, 0, 0, 104, 96, 0, 0, 0, 121,
- 44, 106, 0, 0, 0, 122, 102, 0, 0, 97,
- 98
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 3, 27, 153, 28, 34, 63, 65, 59,
- 50, 85, 29, 30, 31, 70, 81, 93, 95, 97,
- 99, 101, 103, 91, 105, 60, 71, 61, 72, 52,
- 62, 53, 54, 55, 56, 116, 202, 57, 226, 121
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -87
-static const yytype_int16 yypact[] =
-{
- -87, 24, -87, 211, 20, -5, 236, 256, 256, 330,
- 156, 25, 290, 55, 364, 364, 256, 256, 256, 256,
- 145, 29, 29, 256, 17, 46, -87, -87, 26, -87,
- -87, -87, -87, -87, -87, 451, 451, -87, -87, -87,
- -87, -87, -87, -87, -87, 27, -87, 330, 270, 451,
- -87, -87, -87, -87, -87, -87, 39, 44, 48, -87,
- -87, 65, -87, -87, 66, -87, 68, 350, 27, 310,
- -87, -87, -87, -87, -87, -87, 71, 110, 330, -87,
- -87, -87, 23, 384, 451, -87, -87, 75, 72, 77,
- 82, -87, 85, -87, 87, -87, 88, -87, 89, -87,
- 90, -87, 91, -87, -87, -87, 92, -87, 451, 451,
- -87, -87, -87, 120, 451, 451, 98, -87, 7, 113,
- -87, 168, -87, 115, 5, 391, -87, -87, 398, -87,
- -87, -87, 330, 256, -87, -87, 98, -87, 3, 451,
- -87, -87, 384, 122, 416, 426, 256, 330, 330, 330,
- 330, 330, 256, 211, 504, 504, 23, -87, -87, 76,
- 451, 117, -87, 451, 451, 451, 162, 180, 451, 451,
- 451, 451, 451, -87, 181, 8, 136, 148, -87, 433,
- 150, -87, -87, 154, 159, -87, 12, 163, -87, 165,
- -87, 169, 170, -87, 204, 206, -87, -87, 160, -87,
- -87, -87, 205, 207, 182, 485, 512, 240, 451, 451,
- 102, 102, -87, -87, -87, 451, 451, 209, -87, -87,
- 212, -87, -87, 29, 231, 258, -87, 217, 29, 233,
- 244, 451, 145, 249, -87, -87, 261, 42, 42, 232,
- 250, -22, -87, -87, 276, 273, 12, -87, -87, -87,
- -87, -87, 252, 451, -87, -87, 280, 300, 281, -87,
- -87, -87, 262, 451, 451, -87, -87, 267, 278, -87,
- -87
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -87, -87, -87, 171, -87, -87, 303, -87, -87, -87,
- 321, -87, -87, -87, -87, -87, -87, -87, -87, -87,
- -87, -87, -87, -87, -87, -2, 243, 11, -11, -9,
- -8, 74, -1, 2, -3, -62, -87, -10, 94, -86
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -1
-static const yytype_uint16 yytable[] =
-{
- 76, 73, 86, 88, 51, 87, 136, 66, 77, 74,
- 51, 100, 75, 102, 104, 256, 257, 160, 216, 64,
- 140, 224, 154, 155, 2, 111, 112, 92, 94, 96,
- 98, 114, 115, 113, 106, 114, 115, 183, 120, 122,
- 175, 176, 175, 176, 225, 117, 33, 177, 130, 177,
- 168, 169, 170, 171, 172, 129, 35, 125, 134, 76,
- 73, 161, 217, 35, 36, 107, 135, 108, 74, 32,
- 45, 75, 141, 88, 120, 110, 117, 205, 206, 207,
- 37, 58, 210, 211, 212, 213, 214, 37, 89, 90,
- 126, 127, 123, 45, 198, 46, 109, 124, 120, 120,
- 82, 128, 46, 49, 157, 158, 83, 58, 84, 199,
- 49, 200, 170, 171, 172, 112, 131, 132, 120, 133,
- 201, 139, 237, 238, 138, 143, 142, 156, 144, 184,
- 181, 185, 88, 145, 187, 189, 146, 188, 147, 148,
- 149, 150, 151, 152, 182, 191, 192, 193, 194, 195,
- 203, 159, 174, 120, 120, 120, 183, 190, 120, 120,
- 120, 120, 120, 196, 35, 36, 67, 162, 208, 112,
- 204, 163, 164, 165, 166, 167, 168, 169, 170, 171,
- 172, 38, 39, 40, 41, 42, 43, 209, 37, 44,
- 218, 215, 38, 39, 40, 41, 42, 43, 120, 120,
- 44, 68, 219, 46, 221, 239, 240, 69, 222, 48,
- 223, 49, 4, 233, 227, 243, 228, 229, 230, 236,
- 247, 250, 173, 251, 5, 6, 7, 8, 9, 10,
- 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 262, 35, 36, 166, 167, 168, 169,
- 170, 171, 172, 267, 268, 231, 24, 232, 25, 234,
- 26, 235, 241, 244, 35, 36, 242, 245, 37, 246,
- 248, 253, 38, 39, 40, 41, 42, 43, 35, 36,
- 44, 45, 249, 46, 252, 258, 254, 47, 37, 48,
- 263, 49, 38, 39, 40, 41, 42, 43, 35, 36,
- 44, 45, 37, 46, 255, 259, 261, 118, 58, 48,
- 264, 49, 137, 265, 119, 79, 266, 46, 35, 36,
- 67, 269, 37, 84, 197, 49, 38, 39, 40, 41,
- 42, 43, 270, 80, 44, 45, 0, 46, 35, 36,
- 260, 78, 37, 48, 0, 49, 38, 39, 40, 41,
- 42, 43, 0, 0, 44, 68, 0, 46, 35, 36,
- 0, 0, 37, 48, 0, 49, 38, 39, 40, 41,
- 42, 43, 35, 36, 44, 45, 0, 46, 0, 0,
- 0, 0, 37, 48, 0, 49, 38, 39, 40, 41,
- 42, 43, 35, 36, 44, 0, 37, 46, 0, 35,
- 36, 0, 0, 48, 0, 49, 35, 179, 0, 45,
- 0, 46, 0, 0, 0, 0, 37, 48, 0, 49,
- 0, 0, 0, 37, 35, 36, 0, 0, 0, 82,
- 37, 46, 0, 178, 35, 36, 0, 84, 46, 49,
- 180, 35, 36, 0, 84, 46, 49, 0, 37, 0,
- 0, 84, 0, 49, 0, 0, 0, 0, 37, 35,
- 36, 0, 0, 46, 0, 37, 0, 0, 186, 84,
- 0, 49, 0, 46, 0, 220, 0, 0, 58, 84,
- 46, 49, 0, 37, 0, 0, 84, 0, 49, 164,
- 165, 166, 167, 168, 169, 170, 171, 172, 46, 0,
- 0, 0, 0, 0, 84, 0, 49, 163, 164, 165,
- 166, 167, 168, 169, 170, 171, 172, 165, 166, 167,
- 168, 169, 170, 171, 172
-};
-
-static const yytype_int16 yycheck[] =
-{
- 10, 10, 13, 13, 6, 13, 68, 9, 11, 10,
- 12, 20, 10, 21, 22, 37, 38, 10, 10, 8,
- 82, 9, 108, 109, 0, 35, 36, 16, 17, 18,
- 19, 8, 9, 6, 23, 8, 9, 34, 48, 49,
- 37, 38, 37, 38, 32, 47, 51, 44, 58, 44,
- 8, 9, 10, 11, 12, 58, 8, 9, 67, 69,
- 69, 54, 54, 8, 9, 48, 67, 50, 69, 49,
- 45, 69, 83, 83, 84, 49, 78, 163, 164, 165,
- 32, 52, 168, 169, 170, 171, 172, 32, 14, 15,
- 42, 43, 53, 45, 156, 47, 50, 53, 108, 109,
- 45, 53, 47, 55, 114, 115, 51, 52, 53, 33,
- 55, 35, 10, 11, 12, 125, 51, 51, 128, 51,
- 44, 11, 208, 209, 53, 53, 51, 7, 51, 139,
- 132, 142, 142, 51, 144, 145, 51, 145, 51, 51,
- 51, 51, 51, 51, 133, 147, 148, 149, 150, 151,
- 160, 53, 37, 163, 164, 165, 34, 146, 168, 169,
- 170, 171, 172, 152, 8, 9, 10, 54, 6, 179,
- 53, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 36, 37, 38, 39, 40, 41, 7, 32, 44,
- 54, 10, 36, 37, 38, 39, 40, 41, 208, 209,
- 44, 45, 54, 47, 54, 215, 216, 51, 54, 53,
- 51, 55, 1, 53, 51, 223, 51, 48, 48, 37,
- 228, 231, 54, 232, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
- 29, 30, 31, 253, 8, 9, 6, 7, 8, 9,
- 10, 11, 12, 263, 264, 51, 45, 51, 47, 54,
- 49, 54, 53, 32, 8, 9, 54, 9, 32, 52,
- 37, 10, 36, 37, 38, 39, 40, 41, 8, 9,
- 44, 45, 38, 47, 35, 9, 54, 51, 32, 53,
- 10, 55, 36, 37, 38, 39, 40, 41, 8, 9,
- 44, 45, 32, 47, 54, 32, 54, 37, 52, 53,
- 10, 55, 69, 32, 44, 12, 54, 47, 8, 9,
- 10, 54, 32, 53, 153, 55, 36, 37, 38, 39,
- 40, 41, 54, 12, 44, 45, -1, 47, 8, 9,
- 246, 51, 32, 53, -1, 55, 36, 37, 38, 39,
- 40, 41, -1, -1, 44, 45, -1, 47, 8, 9,
- -1, -1, 32, 53, -1, 55, 36, 37, 38, 39,
- 40, 41, 8, 9, 44, 45, -1, 47, -1, -1,
- -1, -1, 32, 53, -1, 55, 36, 37, 38, 39,
- 40, 41, 8, 9, 44, -1, 32, 47, -1, 8,
- 9, -1, -1, 53, -1, 55, 8, 9, -1, 45,
- -1, 47, -1, -1, -1, -1, 32, 53, -1, 55,
- -1, -1, -1, 32, 8, 9, -1, -1, -1, 45,
- 32, 47, -1, 42, 8, 9, -1, 53, 47, 55,
- 42, 8, 9, -1, 53, 47, 55, -1, 32, -1,
- -1, 53, -1, 55, -1, -1, -1, -1, 32, 8,
- 9, -1, -1, 47, -1, 32, -1, -1, 52, 53,
- -1, 55, -1, 47, -1, 42, -1, -1, 52, 53,
- 47, 55, -1, 32, -1, -1, 53, -1, 55, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 47, -1,
- -1, -1, -1, -1, 53, -1, 55, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 5, 6, 7,
- 8, 9, 10, 11, 12
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 57, 0, 58, 1, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 45, 47, 49, 59, 61, 68,
- 69, 70, 49, 51, 62, 8, 9, 32, 36, 37,
- 38, 39, 40, 41, 44, 45, 47, 51, 53, 55,
- 66, 81, 85, 87, 88, 89, 90, 93, 52, 65,
- 81, 83, 86, 63, 83, 64, 81, 10, 45, 51,
- 71, 82, 84, 85, 88, 89, 93, 90, 51, 62,
- 66, 72, 45, 51, 53, 67, 84, 86, 93, 87,
- 87, 79, 83, 73, 83, 74, 83, 75, 83, 76,
- 85, 77, 86, 78, 86, 80, 83, 48, 50, 50,
- 49, 93, 93, 6, 8, 9, 91, 81, 37, 44,
- 93, 95, 93, 53, 53, 9, 42, 43, 53, 90,
- 93, 51, 51, 51, 85, 88, 91, 82, 53, 11,
- 91, 84, 51, 53, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 60, 95, 95, 7, 93, 93, 53,
- 10, 54, 54, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 54, 37, 37, 38, 44, 42, 9,
- 42, 81, 83, 34, 93, 84, 52, 93, 86, 93,
- 83, 81, 81, 81, 81, 81, 83, 59, 91, 33,
- 35, 44, 92, 93, 53, 95, 95, 95, 6, 7,
- 95, 95, 95, 95, 95, 10, 10, 54, 54, 54,
- 42, 54, 54, 51, 9, 32, 94, 51, 51, 48,
- 48, 51, 51, 53, 54, 54, 37, 95, 95, 93,
- 93, 53, 54, 86, 32, 9, 52, 86, 37, 38,
- 93, 85, 35, 10, 54, 54, 37, 38, 9, 32,
- 94, 54, 93, 10, 10, 32, 54, 93, 93, 54,
- 54
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 3:
-#line 68 "a.y"
- {
- stmtline = lineno;
- }
- break;
-
- case 5:
-#line 75 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s (%s)", (yyvsp[(1) - (2)].sym)->labelname, (yyvsp[(1) - (2)].sym)->name);
- (yyvsp[(1) - (2)].sym)->type = LLAB;
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 10:
-#line 89 "a.y"
- {
- (yyvsp[(1) - (3)].sym)->type = LVAR;
- (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 11:
-#line 94 "a.y"
- {
- if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
- yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
- (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 12:
-#line 99 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 13:
-#line 100 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 14:
-#line 101 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 15:
-#line 102 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 16:
-#line 103 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 17:
-#line 104 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 20:
-#line 107 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 21:
-#line 108 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 22:
-#line 109 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 23:
-#line 110 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 24:
-#line 111 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 25:
-#line 112 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 26:
-#line 113 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 27:
-#line 114 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 29:
-#line 116 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 30:
-#line 117 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 31:
-#line 120 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 32:
-#line 125 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 33:
-#line 132 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 34:
-#line 139 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 35:
-#line 146 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 36:
-#line 151 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 37:
-#line 158 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 38:
-#line 163 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 39:
-#line 170 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 40:
-#line 175 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 41:
-#line 180 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 42:
-#line 187 "a.y"
- {
- Addr2 a;
- a.from = (yyvsp[(2) - (6)].addr);
- a.to = (yyvsp[(6) - (6)].addr);
- outcode(ADATA, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 43:
-#line 200 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (5)].addr).sym);
- a.from = (yyvsp[(2) - (5)].addr);
- a.to = (yyvsp[(5) - (5)].addr);
- outcode(ATEXT, &a);
- }
- break;
-
- case 44:
-#line 208 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (7)].addr).sym);
- a.from = (yyvsp[(2) - (7)].addr);
- a.to = (yyvsp[(7) - (7)].addr);
- outcode(ATEXT, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
- }
- }
- break;
-
- case 45:
-#line 222 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (4)].addr).sym);
- a.from = (yyvsp[(2) - (4)].addr);
- a.to = (yyvsp[(4) - (4)].addr);
- outcode(AGLOBL, &a);
- }
- break;
-
- case 46:
-#line 230 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (6)].addr).sym);
- a.from = (yyvsp[(2) - (6)].addr);
- a.to = (yyvsp[(6) - (6)].addr);
- outcode(AGLOBL, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 47:
-#line 244 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 48:
-#line 249 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 51:
-#line 260 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 52:
-#line 265 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- if((yyval.addr2).from.index != TYPE_NONE)
- yyerror("dp shift with lhs index");
- (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 53:
-#line 275 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 54:
-#line 280 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- if((yyval.addr2).to.index != TYPE_NONE)
- yyerror("dp move with lhs index");
- (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 55:
-#line 290 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 56:
-#line 295 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 57:
-#line 300 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 58:
-#line 307 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 59:
-#line 315 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
- if((yyvsp[(1) - (5)].addr).type != TYPE_CONST)
- yyerror("illegal constant");
- (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
- }
- break;
-
- case 60:
-#line 324 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 61:
-#line 329 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 62:
-#line 336 "a.y"
- {
- if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 63:
-#line 345 "a.y"
- {
- if((yyvsp[(1) - (3)].addr).type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC))
- yyerror("value for FUNCDATA must be symbol reference");
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 68:
-#line 362 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 69:
-#line 366 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 74:
-#line 378 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
- }
- break;
-
- case 75:
-#line 384 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- (yyval.addr) = nullgen;
- if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 76:
-#line 395 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 77:
-#line 401 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 78:
-#line 407 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 79:
-#line 413 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 80:
-#line 419 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = REG_SP;
- }
- break;
-
- case 81:
-#line 425 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 82:
-#line 431 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 83:
-#line 439 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 84:
-#line 445 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- (yyval.addr).type = TYPE_ADDR;
- /*
- if($2.type == D_AUTO || $2.type == D_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.sym->name);
- */
- }
- break;
-
- case 85:
-#line 455 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SCONST;
- memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
- }
- break;
-
- case 86:
-#line 461 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
- }
- break;
-
- case 87:
-#line 467 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
- }
- break;
-
- case 88:
-#line 473 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
- }
- break;
-
- case 89:
-#line 479 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
- }
- break;
-
- case 92:
-#line 491 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 93:
-#line 497 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 94:
-#line 504 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_SP;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 95:
-#line 511 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 96:
-#line 518 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
- (yyval.addr).index = (yyvsp[(3) - (6)].lval);
- (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 97:
-#line 527 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
- (yyval.addr).index = (yyvsp[(6) - (9)].lval);
- (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 98:
-#line 537 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
- (yyval.addr).index = (yyvsp[(6) - (9)].lval);
- (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 99:
-#line 547 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 100:
-#line 553 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_SP;
- }
- break;
-
- case 101:
-#line 559 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).index = (yyvsp[(2) - (5)].lval);
- (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 102:
-#line 567 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (8)].lval);
- (yyval.addr).index = (yyvsp[(5) - (8)].lval);
- (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 103:
-#line 578 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 104:
-#line 582 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (6)].addr);
- (yyval.addr).index = (yyvsp[(3) - (6)].lval);
- (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 105:
-#line 591 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(4) - (5)].lval);
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
- (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
- }
- break;
-
- case 106:
-#line 599 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = NAME_STATIC;
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
- (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
- }
- break;
-
- case 107:
-#line 608 "a.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 108:
-#line 612 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 109:
-#line 616 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 111:
-#line 623 "a.y"
- {
- (yyval.lval) = NAME_AUTO;
- }
- break;
-
- case 114:
-#line 631 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
- }
- break;
-
- case 115:
-#line 635 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 116:
-#line 639 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 117:
-#line 643 "a.y"
- {
- (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 118:
-#line 647 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 119:
-#line 653 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 120:
-#line 660 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 121:
-#line 667 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
- (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 122:
-#line 674 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
- (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 124:
-#line 684 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 125:
-#line 688 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 126:
-#line 692 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 127:
-#line 696 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 128:
-#line 700 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 129:
-#line 704 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 130:
-#line 708 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 131:
-#line 712 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 132:
-#line 716 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 133:
-#line 720 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 2587 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h
deleted file mode 100644
index e0eb5e12cf..0000000000
--- a/src/cmd/6a/y.tab.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE0 = 258,
- LTYPE1 = 259,
- LTYPE2 = 260,
- LTYPE3 = 261,
- LTYPE4 = 262,
- LTYPEC = 263,
- LTYPED = 264,
- LTYPEN = 265,
- LTYPER = 266,
- LTYPET = 267,
- LTYPEG = 268,
- LTYPEPC = 269,
- LTYPES = 270,
- LTYPEM = 271,
- LTYPEI = 272,
- LTYPEXC = 273,
- LTYPEX = 274,
- LTYPERT = 275,
- LTYPEF = 276,
- LCONST = 277,
- LFP = 278,
- LPC = 279,
- LSB = 280,
- LBREG = 281,
- LLREG = 282,
- LSREG = 283,
- LFREG = 284,
- LMREG = 285,
- LXREG = 286,
- LFCONST = 287,
- LSCONST = 288,
- LSP = 289,
- LNAME = 290,
- LLAB = 291,
- LVAR = 292
- };
-#endif
-/* Tokens. */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPEG 268
-#define LTYPEPC 269
-#define LTYPES 270
-#define LTYPEM 271
-#define LTYPEI 272
-#define LTYPEXC 273
-#define LTYPEX 274
-#define LTYPERT 275
-#define LTYPEF 276
-#define LCONST 277
-#define LFP 278
-#define LPC 279
-#define LSB 280
-#define LBREG 281
-#define LLREG 282
-#define LSREG 283
-#define LFREG 284
-#define LMREG 285
-#define LXREG 286
-#define LFCONST 287
-#define LSCONST 288
-#define LSP 289
-#define LNAME 290
-#define LLAB 291
-#define LVAR 292
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
-}
-/* Line 1529 of yacc.c. */
-#line 132 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
deleted file mode 100644
index 3f528d7517..0000000000
--- a/src/cmd/6g/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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.
-
-include ../../Make.dist
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
deleted file mode 100644
index 77ab2d2167..0000000000
--- a/src/cmd/6g/cgen.c
+++ /dev/null
@@ -1,1745 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2;
- int a, f;
- Prog *p1, *p2, *p3;
- Addr addr;
-
- if(debug['g']) {
- dump("\ncgen-n", n);
- dump("cgen-res", res);
- }
- if(n == N || n->type == T)
- goto ret;
-
- if(res == N || res->type == T)
- fatal("cgen: res nil");
-
- 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(n->addable) {
- gmove(n, res);
- 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;
- }
- }
-
- 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(AJMP, T, 0);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AJMP, 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);
- if(a == AIMULB) {
- cgen_bmul(n->op, nl, nr, res);
- break;
- }
- 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(ALEAQ, 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;
- }
- *
- */
-
- 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);
- 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, n5, tmp, tmp2, nlen;
- Prog *p1;
- Type *t;
- uint64 w;
- uint64 v;
- int freelen;
-
- if(debug['g']) {
- dump("\nagenr-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:
- freelen = 0;
- w = n->type->width;
- // Generate the non-addressable child first.
- if(nr->addable)
- goto irad;
- if(nl->addable) {
- cgenr(nr, &n1, N);
- if(!isconst(nl, CTSTR)) {
- if(isfixedarray(nl->type)) {
- agenr(nl, &n3, res);
- } else {
- igen(nl, &nlen, res);
- freelen = 1;
- nlen.type = types[tptr];
- nlen.xoffset += Array_array;
- regalloc(&n3, types[tptr], res);
- gmove(&nlen, &n3);
- nlen.type = types[simtype[TUINT]];
- nlen.xoffset += Array_nel-Array_array;
- }
- }
- goto index;
- }
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- nr = &tmp;
- irad:
- if(!isconst(nl, CTSTR)) {
- if(isfixedarray(nl->type)) {
- agenr(nl, &n3, res);
- } else {
- if(!nl->addable) {
- // igen will need an addressable node.
- tempname(&tmp2, nl->type);
- cgen(nl, &tmp2);
- nl = &tmp2;
- }
- igen(nl, &nlen, res);
- freelen = 1;
- nlen.type = types[tptr];
- nlen.xoffset += Array_array;
- regalloc(&n3, types[tptr], res);
- gmove(&nlen, &n3);
- nlen.type = types[simtype[TUINT]];
- nlen.xoffset += Array_nel-Array_array;
- }
- }
- if(!isconst(nr, CTINT)) {
- cgenr(nr, &n1, N);
- }
- goto index;
-
- index:
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // len(a) is in nlen (if needed)
- // w is width
-
- // constant index
- if(isconst(nr, CTINT)) {
- if(isconst(nl, CTSTR))
- fatal("constant string constant index"); // front end should handle
- v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->bounded) {
- nodconst(&n2, types[simtype[TUINT]], v);
- if(smallintconst(nr)) {
- gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2);
- } else {
- regalloc(&tmp, types[simtype[TUINT]], N);
- gmove(&n2, &tmp);
- gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp);
- regfree(&tmp);
- }
- p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
- regfree(&nlen);
- }
-
- if (v*w != 0)
- ginscon(optoas(OADD, types[tptr]), v*w, &n3);
- *a = n3;
- break;
- }
-
- // type of the index
- t = types[TUINT64];
- if(issigned[n1.type->etype])
- t = types[TINT64];
-
- regalloc(&n2, t, &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->bounded) {
- // check bounds
- t = types[simtype[TUINT]];
- if(is64(nr->type))
- t = types[TUINT64];
- if(isconst(nl, CTSTR)) {
- nodconst(&nlen, t, nl->val.u.sval->len);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(is64(nr->type)) {
- regalloc(&n5, t, N);
- gmove(&nlen, &n5);
- regfree(&nlen);
- nlen = n5;
- }
- } else {
- nodconst(&nlen, t, nl->type->bound);
- if(!smallintconst(&nlen)) {
- regalloc(&n5, t, N);
- gmove(&nlen, &n5);
- nlen = n5;
- freelen = 1;
- }
- }
- gins(optoas(OCMP, t), &n2, &nlen);
- p1 = gbranch(optoas(OLT, t), T, +1);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(ALEAQ, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- gins(AADDQ, &n2, &n3);
- goto indexdone;
- }
-
- if(w == 0) {
- // nothing to do
- } else if(w == 1 || w == 2 || w == 4 || w == 8) {
- p1 = gins(ALEAQ, &n2, &n3);
- p1->from.type = TYPE_MEM;
- p1->from.scale = w;
- p1->from.index = p1->from.reg;
- p1->from.reg = p1->to.reg;
- } else {
- ginscon(optoas(OMUL, t), w, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- }
-
- indexdone:
- *a = n3;
- regfree(&n2);
- if(freelen)
- regfree(&nlen);
- break;
-
- default:
- regalloc(a, types[tptr], res);
- agen(n, a);
- break;
- }
-}
-
-/*
- * generate:
- * res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
- Node *nl;
- Node n1, n2;
-
- 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);
- gins(ALEAQ, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- goto ret;
- }
-
- if(n->addable) {
- regalloc(&n1, types[tptr], res);
- gins(ALEAQ, n, &n1);
- gmove(&n1, res);
- regfree(&n1);
- goto ret;
- }
-
- nl = n->left;
-
- switch(n->op) {
- default:
- fatal("agen: unknown op %+hN", n);
- break;
-
- case OCALLMETH:
- 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)
- ginscon(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)
- ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
- break;
-
- case ODOTPTR:
- cgen(nl, res);
- cgen_checknil(res);
- if(n->xoffset != 0)
- ginscon(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 != REG_SP)
- 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 = REG_SP;
- a->addable = 1;
- a->xoffset = fp->width;
- 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:
- goto def;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T, likely), to);
- goto ret;
-
- case ONAME:
- if(n->addable == 0)
- goto def;
- nodconst(&n1, n->type, 0);
- gins(optoas(OCMP, n->type), n, &n1);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- goto ret;
-
- case OANDAND:
- case OOROR:
- if((n->op == OANDAND) == true) {
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- } else {
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
- }
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- goto ret;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- goto ret;
- 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(AJMP, T, 0);
- p2 = gbranch(AJMP, 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(AJMP, 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);
- gins(optoas(OCMP, types[tptr]), &n1, &tmp);
- 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);
- gins(optoas(OCMP, types[tptr]), &n1, &tmp);
- 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);
-
- 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:
- // only < and <= work right with NaN; reverse if needed
- l = &n1;
- r = &n2;
- if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
- l = &n2;
- r = &n1;
- a = brrev(a);
- }
-
- gins(optoas(OCMP, nr->type), l, r);
-
- if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
- if(n->op == OEQ) {
- // neither NE nor P
- p1 = gbranch(AJNE, T, -likely);
- p2 = gbranch(AJPS, T, -likely);
- patch(gbranch(AJMP, T, 0), to);
- patch(p1, pc);
- patch(p2, pc);
- } else {
- // either NE or P
- patch(gbranch(AJNE, T, likely), to);
- patch(gbranch(AJPS, T, likely), to);
- }
- } else
- patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
- regfree(&n1);
- regfree(&n2);
- break;
- }
- goto ret;
-
-def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- regfree(&n1);
- 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;
- 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 nodl, nodr, nodsi, noddi, cx, oldcx, tmp;
- vlong c, q, odst, osrc;
- NodeList *l;
- Prog *p;
-
- 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(&nodr, types[tptr], N);
- agen(ns, &nodr);
- agen(n, &nodr);
- regfree(&nodr);
- return;
- }
-
- // offset on the stack
- osrc = stkof(n);
- odst = stkof(ns);
-
- 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, ns, w);
- return;
- }
-
- nodreg(&noddi, types[tptr], REG_DI);
- nodreg(&nodsi, types[tptr], REG_SI);
-
- if(n->ullman >= ns->ullman) {
- agenr(n, &nodr, &nodsi);
- if(ns->op == ONAME)
- gvardef(ns);
- agenr(ns, &nodl, &noddi);
- } else {
- if(ns->op == ONAME)
- gvardef(ns);
- agenr(ns, &nodl, &noddi);
- agenr(n, &nodr, &nodsi);
- }
-
- if(nodl.val.u.reg != REG_DI)
- gmove(&nodl, &noddi);
- if(nodr.val.u.reg != REG_SI)
- gmove(&nodr, &nodsi);
- regfree(&nodl);
- regfree(&nodr);
-
- c = w % 8; // bytes
- q = w / 8; // quads
-
- savex(REG_CX, &cx, &oldcx, N, types[TINT64]);
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if(osrc < odst && odst < osrc+w) {
- // reverse direction
- gins(ASTD, N, N); // set direction flag
- if(c > 0) {
- gconreg(addptr, w-1, REG_SI);
- gconreg(addptr, w-1, REG_DI);
-
- gconreg(movptr, c, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
- }
-
- if(q > 0) {
- if(c > 0) {
- gconreg(addptr, -7, REG_SI);
- gconreg(addptr, -7, REG_DI);
- } else {
- gconreg(addptr, w-8, REG_SI);
- gconreg(addptr, w-8, REG_DI);
- }
- gconreg(movptr, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
- }
- // we leave with the flag clear
- gins(ACLD, N, N);
- } else {
- // normal direction
- if(q > 128 || (nacl && q >= 4)) {
- gconreg(movptr, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
- } else if (q >= 4) {
- p = gins(ADUFFCOPY, N, N);
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
- // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s
- p->to.offset = 14*(128-q);
- } else if(!nacl && c == 0) {
- // We don't need the MOVSQ side-effect of updating SI and DI,
- // and issuing a sequence of MOVQs directly is faster.
- nodsi.op = OINDREG;
- noddi.op = OINDREG;
- while(q > 0) {
- gmove(&nodsi, &cx); // MOVQ x+(SI),CX
- gmove(&cx, &noddi); // MOVQ CX,x+(DI)
- nodsi.xoffset += 8;
- noddi.xoffset += 8;
- q--;
- }
- } else
- while(q > 0) {
- gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
- q--;
- }
- // copy the remaining c bytes
- if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) {
- while(c > 0) {
- gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
- c--;
- }
- } else if(w < 8 || c <= 4) {
- nodsi.op = OINDREG;
- noddi.op = OINDREG;
- cx.type = types[TINT32];
- nodsi.type = types[TINT32];
- noddi.type = types[TINT32];
- if(c > 4) {
- nodsi.xoffset = 0;
- noddi.xoffset = 0;
- gmove(&nodsi, &cx);
- gmove(&cx, &noddi);
- }
- nodsi.xoffset = c-4;
- noddi.xoffset = c-4;
- gmove(&nodsi, &cx);
- gmove(&cx, &noddi);
- } else {
- nodsi.op = OINDREG;
- noddi.op = OINDREG;
- cx.type = types[TINT64];
- nodsi.type = types[TINT64];
- noddi.type = types[TINT64];
- nodsi.xoffset = c-8;
- noddi.xoffset = c-8;
- gmove(&nodsi, &cx);
- gmove(&cx, &noddi);
- }
- }
-
- restx(&cx, &oldcx);
-}
-
-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, tmp;
- Type *t;
- int freel, freer;
- vlong fldcount;
- vlong loffset, roffset;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- t = nl->type;
-
- // Slices are ok.
- if(isslice(t))
- break;
- // Small arrays are ok.
- if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
- break;
-
- goto no;
-
- case TSTRUCT:
- // Small structs with non-fat types are ok.
- // Zero-sized structs are treated separately elsewhere.
- fldcount = 0;
- for(t=nl->type->type; t; t=t->down) {
- if(isfat(t->type))
- goto no;
- if(t->etype != TFIELD)
- fatal("componentgen: not a TFIELD: %lT", t);
- fldcount++;
- }
- if(fldcount == 0 || fldcount > 4)
- goto no;
-
- break;
-
- case TSTRING:
- case TINTER:
- break;
- }
-
- nodl = *nl;
- if(!cadable(nl)) {
- if(nr != N && !cadable(nr))
- goto no;
- igen(nl, &nodl, N);
- freel = 1;
- }
-
- if(nr != N) {
- nodr = *nr;
- if(!cadable(nr)) {
- igen(nr, &nodr, N);
- freer = 1;
- }
- } else {
- // When zeroing, prepare a register containing zero.
- nodconst(&tmp, nl->type, 0);
- regalloc(&nodr, types[TUINT], N);
- gmove(&tmp, &nodr);
- freer = 1;
- }
-
- // nl and nr are 'cadable' which basically means they are names (variables) now.
- // If they are the same variable, don't generate any code, because the
- // VARDEF we generate will mark the old value as dead incorrectly.
- // (And also the assignments are useless.)
- if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
- goto yes;
-
- switch(nl->type->etype) {
- case TARRAY:
- // componentgen for arrays.
- if(nl->op == ONAME)
- gvardef(nl);
- t = nl->type;
- if(!isslice(t)) {
- nodl.type = t->type;
- nodr.type = nodl.type;
- for(fldcount=0; fldcount < t->bound; fldcount++) {
- if(nr == N)
- clearslim(&nodl);
- else
- gmove(&nodr, &nodl);
- nodl.xoffset += t->type->width;
- nodr.xoffset += t->type->width;
- }
- goto yes;
- }
-
- // componentgen for slices.
- nodl.xoffset += Array_array;
- nodl.type = ptrto(nl->type->type);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_cap-Array_nel;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRING:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TINTER:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRUCT:
- if(nl->op == ONAME)
- gvardef(nl);
- loffset = nodl.xoffset;
- roffset = nodr.xoffset;
- // funarg structs may not begin at offset zero.
- if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
- loffset -= nl->type->type->width;
- if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
- roffset -= nr->type->type->width;
-
- for(t=nl->type->type; t; t=t->down) {
- nodl.xoffset = loffset + t->width;
- nodl.type = t->type;
-
- if(nr == N)
- clearslim(&nodl);
- else {
- nodr.xoffset = roffset + t->width;
- nodr.type = nodl.type;
- gmove(&nodr, &nodl);
- }
- }
- goto yes;
- }
-
-no:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 0;
-
-yes:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 1;
-}
diff --git a/src/cmd/new6g/cgen.go b/src/cmd/6g/cgen.go
index 36fa62c469..36fa62c469 100644
--- a/src/cmd/new6g/cgen.go
+++ b/src/cmd/6g/cgen.go
diff --git a/src/cmd/6g/doc.go b/src/cmd/6g/doc.go
deleted file mode 100644
index 07b2818da4..0000000000
--- a/src/cmd/6g/doc.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-6g is the version of the gc compiler for the x86-64.
-The $GOARCH for these tools is amd64.
-
-It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
deleted file mode 100644
index fa9998b0ee..0000000000
--- a/src/cmd/6g/galign.c
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int thechar = '6';
-char* thestring = "amd64";
-LinkArch* thelinkarch = &linkamd64;
-
-void
-linkarchinit(void)
-{
- if(strcmp(getgoarch(), "amd64p32") == 0) {
- thelinkarch = &linkamd64p32;
- thearch.thelinkarch = thelinkarch;
- thestring = "amd64p32";
- thearch.thestring = "amd64p32";
- }
-}
-
-vlong MAXWIDTH = 1LL<<50;
-
-int addptr = AADDQ;
-int movptr = AMOVQ;
-int leaptr = ALEAQ;
-int cmpptr = ACMPQ;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- {"int", TINT, TINT64},
- {"uint", TUINT, TUINT64},
- {"uintptr", TUINTPTR, TUINT64},
- {0}
-};
-
-void
-betypeinit(void)
-{
- widthptr = 8;
- widthint = 8;
- widthreg = 8;
- if(strcmp(getgoarch(), "amd64p32") == 0) {
- widthptr = 4;
- widthint = 4;
- addptr = AADDL;
- movptr = AMOVL;
- leaptr = ALEAL;
- cmpptr = ACMPL;
- typedefs[0].sameas = TINT32;
- typedefs[1].sameas = TUINT32;
- typedefs[2].sameas = TUINT32;
-
- }
-
- listinit6();
-}
-
-void
-main(int argc, char **argv)
-{
- thearch.thechar = thechar;
- thearch.thestring = thestring;
- thearch.thelinkarch = thelinkarch;
- thearch.typedefs = typedefs;
- thearch.REGSP = REGSP;
- thearch.REGCTXT = REGCTXT;
- thearch.MAXWIDTH = MAXWIDTH;
- thearch.anyregalloc = anyregalloc;
- thearch.betypeinit = betypeinit;
- thearch.bgen = bgen;
- thearch.cgen = cgen;
- thearch.cgen_call = cgen_call;
- thearch.cgen_callinter = cgen_callinter;
- thearch.cgen_ret = cgen_ret;
- thearch.clearfat = clearfat;
- thearch.defframe = defframe;
- thearch.excise = excise;
- thearch.expandchecks = expandchecks;
- thearch.gclean = gclean;
- thearch.ginit = ginit;
- thearch.gins = gins;
- thearch.ginscall = ginscall;
- thearch.igen = igen;
- thearch.linkarchinit = linkarchinit;
- thearch.peep = peep;
- thearch.proginfo = proginfo;
- thearch.regalloc = regalloc;
- thearch.regfree = regfree;
- thearch.regtyp = regtyp;
- thearch.sameaddr = sameaddr;
- thearch.smallindir = smallindir;
- thearch.stackaddr = stackaddr;
- thearch.excludedregs = excludedregs;
- thearch.RtoB = RtoB;
- thearch.FtoB = FtoB;
- thearch.BtoR = BtoR;
- thearch.BtoF = BtoF;
- thearch.optoas = optoas;
- thearch.doregbits = doregbits;
- thearch.regnames = regnames;
-
- gcmain(argc, argv);
-}
diff --git a/src/cmd/new6g/galign.go b/src/cmd/6g/galign.go
index bdd8a3c226..bdd8a3c226 100644
--- a/src/cmd/new6g/galign.go
+++ b/src/cmd/6g/galign.go
diff --git a/src/cmd/new6g/gg.go b/src/cmd/6g/gg.go
index 2deed5deb9..2deed5deb9 100644
--- a/src/cmd/new6g/gg.go
+++ b/src/cmd/6g/gg.go
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
deleted file mode 100644
index a6dfad9c8e..0000000000
--- a/src/cmd/6g/gg.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#include "../gc/go.h"
-#include "../6l/6.out.h"
-
-EXTERN uchar reg[MAXREG];
-EXTERN Node* panicdiv;
-extern vlong unmappedzero;
-extern int addptr;
-extern int cmpptr;
-extern int movptr;
-extern int leaptr;
-
-/*
- * 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_bmul(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*);
-int samaddr(Node*, Node*);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-void restx(Node*, Node*);
-void savex(int, Node*, Node*, Node*, Type*);
-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 gconreg(int, vlong, int);
-void ginscon(int, vlong, Node*);
-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 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);
-
-void afunclit(Addr*, Node*);
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node*, int, int, Prog*);
-void cgen(Node*, Node*);
-void cgen_call(Node*, int);
-void cgen_callinter(Node*, Node*, int);
-void cgen_ret(Node*);
-void clearfat(Node*);
-void clearp(Prog*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int, char*);
-int dgostrlitptr(Sym*, int, Strlit*);
-int dsname(Sym*, int, char*, int);
-int dsymptr(Sym*, int, Sym*, int);
-void dumpdata(void);
-void dumpit(char*, Flow*, int);
-void excise(Flow*);
-void expandchecks(Prog*);
-void fixautoused(Prog*);
-void gclean(void);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void ggloblnod(Node *nam);
-void ggloblsym(Sym *s, int32 width, int8 flags);
-void ginit(void);
-Prog* gins(int, Node*, Node*);
-void ginscall(Node*, int);
-Prog* gjmp(Prog*);
-void gtrack(Sym*);
-void gused(Node*);
-void igen(Node*, Node*, Node*);
-int isfat(Type*);
-void linkarchinit(void);
-void markautoused(Prog*);
-void naddr(Node*, Addr*, int);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void patch(Prog*, Prog*);
-void proginfo(ProgInfo*, Prog*);
-void regalloc(Node*, Type*, Node*);
-void regfree(Node*);
-void regopt(Prog*);
-int regtyp(Addr*);
-int sameaddr(Addr*, Addr*);
-int smallindir(Addr*, Addr*);
-int stackaddr(Addr*);
-Prog* unpatch(Prog*);
-
-/*
- * reg.c
- */
-uint64 excludedregs(void);
-uint64 RtoB(int);
-uint64 FtoB(int);
-int BtoR(uint64);
-int BtoF(uint64);
-uint64 doregbits(int);
-char** regnames(int*);
-
-/*
- * peep.c
- */
-void peep(Prog*);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
deleted file mode 100644
index 72104589a3..0000000000
--- a/src/cmd/6g/ggen.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#undef EXTERN
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
-
-void
-defframe(Prog *ptxt)
-{
- uint32 frame, ax;
- Prog *p;
- vlong hi, lo;
- NodeList *l;
- Node *n;
-
- // fill in argument size, stack size
- ptxt->to.type = TYPE_TEXTSIZE;
- ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
- frame = rnd(stksize+maxarg, widthreg);
- ptxt->to.offset = frame;
-
- // insert code to zero ambiguously live variables
- // so that the garbage collector only sees initialized values
- // when it looks for pointers.
- p = ptxt;
- lo = hi = 0;
- ax = 0;
- // iterate through declarations - they are sorted in decreasing xoffset order.
- for(l=curfn->dcl; l != nil; l = l->next) {
- n = l->n;
- if(!n->needzero)
- continue;
- if(n->class != PAUTO)
- fatal("needzero class %d", n->class);
- if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
- fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
-
- if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
- // merge with range we already have
- lo = n->xoffset;
- continue;
- }
- // zero old range
- p = zerorange(p, frame, lo, hi, &ax);
-
- // set new range
- hi = n->xoffset + n->type->width;
- lo = n->xoffset;
- }
- // zero final range
- zerorange(p, frame, lo, hi, &ax);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
-{
- vlong cnt, i;
-
- cnt = hi - lo;
- if(cnt == 0)
- return p;
- if(*ax == 0) {
- p = appendpp(p, AMOVQ, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0);
- *ax = 1;
- }
- if(cnt % widthreg != 0) {
- // should only happen with nacl
- if(cnt % widthptr != 0)
- fatal("zerorange count not a multiple of widthptr %d", cnt);
- p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo);
- lo += widthptr;
- cnt -= widthptr;
- }
- if(cnt <= 4*widthreg) {
- for(i = 0; i < cnt; i += widthreg) {
- p = appendpp(p, AMOVQ, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i);
- }
- } else if(!nacl && (cnt <= 128*widthreg)) {
- p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
- p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 2*(128-cnt/widthreg));
- p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
- } else {
- p = appendpp(p, AMOVQ, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0);
- p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
- p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
- p = appendpp(p, ASTOSQ, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
- }
- return p;
-}
-
-static Prog*
-appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset)
-{
- Prog *q;
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.reg = freg;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.reg = treg;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-/*
- * generate:
- * call f
- * proc=-1 normal call but no return
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- * proc=3 normal call to C pointer (not Go func value)
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node reg, stk;
- Node r1;
- int32 extra;
-
- if(f->type != T) {
- extra = 0;
- if(proc == 1 || proc == 2)
- extra = 2 * widthptr;
- setmaxarg(f->type, extra);
- }
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- case -1: // normal call but no return
- if(f->op == ONAME && f->class == PFUNC) {
- if(f == deferreturn) {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an x86 NOP that we will have the right line number.
- // x86 NOP 0x90 is really XCHG AX, AX; use that description
- // because the NOP pseudo-instruction would be removed by
- // the linker.
- nodreg(&reg, types[TINT], REG_AX);
- gins(AXCHGL, &reg, &reg);
- }
- p = gins(ACALL, N, f);
- afunclit(&p->to, f);
- if(proc == -1 || noreturn(p))
- gins(AUNDEF, N, N);
- break;
- }
- nodreg(&reg, types[tptr], REG_DX);
- nodreg(&r1, types[tptr], REG_BX);
- gmove(f, &reg);
- reg.op = OINDREG;
- gmove(&reg, &r1);
- reg.op = OREGISTER;
- gins(ACALL, &reg, &r1);
- break;
-
- case 3: // normal call of c function pointer
- gins(ACALL, N, f);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- memset(&stk, 0, sizeof(stk));
- stk.op = OINDREG;
- stk.val.u.reg = REG_SP;
- stk.xoffset = 0;
-
- if(widthptr == 8) {
- // size of arguments at 0(SP)
- ginscon(AMOVQ, argsize(f->type), &stk);
-
- // FuncVal* at 8(SP)
- stk.xoffset = widthptr;
- nodreg(&reg, types[TINT64], REG_AX);
- gmove(f, &reg);
- gins(AMOVQ, &reg, &stk);
- } else {
- // size of arguments at 0(SP)
- ginscon(AMOVL, argsize(f->type), &stk);
-
- // FuncVal* at 4(SP)
- stk.xoffset = widthptr;
- nodreg(&reg, types[TINT32], REG_AX);
- gmove(f, &reg);
- gins(AMOVL, &reg, &stk);
- }
-
- if(proc == 1)
- ginscall(newproc, 0);
- else {
- if(!hasdefer)
- fatal("hasdefer=0 but has defer");
- ginscall(deferproc, 0);
- }
- if(proc == 2) {
- nodreg(&reg, types[TINT32], REG_AX);
- gins(ATESTL, &reg, &reg);
- p = gbranch(AJEQ, T, +1);
- cgen_ret(N);
- patch(p, pc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- Node *i, *f;
- Node tmpi, nodi, nodo, nodr, nodsp;
-
- i = n->left;
- if(i->op != ODOTINTER)
- fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
- f = i->right; // field
- if(f->op != ONAME)
- fatal("cgen_callinter: not ONAME %O", f->op);
-
- i = i->left; // interface
-
- if(!i->addable) {
- tempname(&tmpi, i->type);
- cgen(i, &tmpi);
- i = &tmpi;
- }
-
- genlist(n->list); // assign the args
-
- // i is now addable, prepare an indirected
- // register to hold its address.
- igen(i, &nodi, res); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], REG_SP);
- nodsp.xoffset = 0;
- if(proc != 0)
- nodsp.xoffset += 2 * widthptr; // leave room for size & fn
- nodi.type = types[tptr];
- nodi.xoffset += widthptr;
- cgen(&nodi, &nodsp); // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
-
- regalloc(&nodo, types[tptr], res);
- nodi.type = types[tptr];
- nodi.xoffset -= widthptr;
- cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab
- regfree(&nodi);
-
- regalloc(&nodr, types[tptr], &nodo);
- if(n->left->xoffset == BADWIDTH)
- fatal("cgen_callinter: badwidth");
- cgen_checknil(&nodo); // in case offset is huge
- nodo.op = OINDREG;
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- if(proc == 0) {
- // plain call: use direct c function pointer - more efficient
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
- proc = 3;
- } else {
- // go/defer. generate go func value.
- gins(ALEAQ, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.tab->fun[f]
- }
-
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-}
-
-/*
- * generate function call;
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_call(Node *n, int proc)
-{
- Type *t;
- Node nod, afun;
-
- if(n == N)
- return;
-
- if(n->left->ullman >= UINF) {
- // if name involves a fn call
- // precompute the address of the fn
- tempname(&afun, types[tptr]);
- cgen(n->left, &afun);
- }
-
- genlist(n->list); // assign the args
- t = n->left->type;
-
- // call tempname pointer
- if(n->left->ullman >= UINF) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, &afun);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call pointer
- if(n->left->op != ONAME || n->left->class != PFUNC) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, n->left);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = return value from call.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
- Node nod;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(t->etype == TPTR32 || t->etype == TPTR64)
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_callret: nil");
-
- memset(&nod, 0, sizeof(nod));
- nod.op = OINDREG;
- nod.val.u.reg = REG_SP;
- nod.addable = 1;
-
- nod.xoffset = fp->width;
- nod.type = fp->type;
- cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
- Node nod1, nod2;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_aret: nil");
-
- memset(&nod1, 0, sizeof(nod1));
- nod1.op = OINDREG;
- nod1.val.u.reg = REG_SP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width;
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- gins(leaptr, &nod1, &nod2);
- gins(movptr, &nod2, res);
- regfree(&nod2);
- } else
- gins(leaptr, &nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- Prog *p;
-
- if(n != N)
- genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- genlist(curfn->exit);
- p = gins(ARET, N, N);
- if(n != N && n->op == ORETJMP) {
- p->to.type = TYPE_MEM;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(n->left->sym);
- }
-}
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res)
-{
- int a, check;
- Node n3, n4;
- Type *t, *t0;
- Node ax, dx, ax1, n31, oldax, olddx;
- Prog *p1, *p2;
-
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will trap.
- // Also the byte divide instruction needs AH,
- // which we otherwise don't have to deal with.
- // Easiest way to avoid for int8, int16: use int32.
- // For int32 and int64, use explicit test.
- // Could use int64 hw for int32.
- t = nl->type;
- t0 = t;
- check = 0;
- if(issigned[t->etype]) {
- check = 1;
- if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1)))
- check = 0;
- else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
- check = 0;
- }
- if(t->width < 4) {
- if(issigned[t->etype])
- t = types[TINT32];
- else
- t = types[TUINT32];
- check = 0;
- }
- a = optoas(op, t);
-
- regalloc(&n3, t0, N);
- if(nl->ullman >= nr->ullman) {
- savex(REG_AX, &ax, &oldax, res, t0);
- cgen(nl, &ax);
- regalloc(&ax, t0, &ax); // mark ax live during cgen
- cgen(nr, &n3);
- regfree(&ax);
- } else {
- cgen(nr, &n3);
- savex(REG_AX, &ax, &oldax, res, t0);
- cgen(nl, &ax);
- }
- if(t != t0) {
- // Convert
- ax1 = ax;
- n31 = n3;
- ax.type = t;
- n3.type = t;
- gmove(&ax1, &ax);
- gmove(&n31, &n3);
- }
-
- p2 = P;
- if(nacl) {
- // Native Client does not relay the divide-by-zero trap
- // to the executing program, so we must insert a check
- // for ourselves.
- nodconst(&n4, t, 0);
- gins(optoas(OCMP, t), &n3, &n4);
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(panicdiv == N)
- panicdiv = sysfunc("panicdivide");
- ginscall(panicdiv, -1);
- patch(p1, pc);
- }
- if(check) {
- nodconst(&n4, t, -1);
- gins(optoas(OCMP, t), &n3, &n4);
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(op == ODIV) {
- // a / (-1) is -a.
- gins(optoas(OMINUS, t), N, &ax);
- gmove(&ax, res);
- } else {
- // a % (-1) is 0.
- nodconst(&n4, t, 0);
- gmove(&n4, res);
- }
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- }
- savex(REG_DX, &dx, &olddx, res, t);
- if(!issigned[t->etype]) {
- nodconst(&n4, t, 0);
- gmove(&n4, &dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
- gins(a, &n3, N);
- regfree(&n3);
- if(op == ODIV)
- gmove(&ax, res);
- else
- gmove(&dx, res);
- restx(&dx, &olddx);
- if(check)
- patch(p2, pc);
- restx(&ax, &oldax);
-}
-
-/*
- * register dr is one of the special ones (AX, CX, DI, SI, etc.).
- * we need to use it. if it is already allocated as a temporary
- * (r > 1; can only happen if a routine like sgen passed a
- * special as cgen's res and then cgen used regalloc to reuse
- * it as its own temporary), then move it for now to another
- * register. caller must call restx to move it back.
- * the move is not necessary if dr == res, because res is
- * known to be dead.
- */
-void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
- int r;
-
- r = reg[dr];
-
- // save current ax and dx if they are live
- // and not the destination
- memset(oldx, 0, sizeof *oldx);
- nodreg(x, t, dr);
- if(r > 1 && !samereg(x, res)) {
- regalloc(oldx, types[TINT64], N);
- x->type = types[TINT64];
- gmove(x, oldx);
- x->type = t;
- oldx->ostk = r; // squirrel away old r value
- reg[dr] = 1;
- }
-}
-
-void
-restx(Node *x, Node *oldx)
-{
- if(oldx->op != 0) {
- x->type = types[TINT64];
- reg[x->val.u.reg] = oldx->ostk;
- gmove(oldx, x);
- regfree(oldx);
- }
-}
-
-/*
- * generate division according to op, one of:
- * res = nl / nr
- * res = nl % nr
- */
-void
-cgen_div(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3;
- int w, a;
- Magic m;
-
- if(nr->op != OLITERAL)
- goto longdiv;
- w = nl->type->width*8;
-
- // Front end handled 32-bit division. We only need to handle 64-bit.
- // try to do division by multiply by (2^w)/d
- // see hacker's delight chapter 10
- switch(simtype[nl->type->etype]) {
- default:
- goto longdiv;
-
- case TUINT64:
- m.w = w;
- m.ud = mpgetfix(nr->val.u.xval);
- umagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- cgenr(nl, &n1, N);
- nodconst(&n2, nl->type, m.um);
- regalloc(&n3, nl->type, res);
- cgen_hmul(&n1, &n2, &n3);
-
- if(m.ua) {
- // need to add numerator accounting for overflow
- gins(optoas(OADD, nl->type), &n1, &n3);
- nodconst(&n2, nl->type, 1);
- gins(optoas(ORROTC, nl->type), &n2, &n3);
- nodconst(&n2, nl->type, m.s-1);
- gins(optoas(ORSH, nl->type), &n2, &n3);
- } else {
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &n3); // shift dx
- }
-
- gmove(&n3, res);
- regfree(&n1);
- regfree(&n3);
- return;
-
- case TINT64:
- m.w = w;
- m.sd = mpgetfix(nr->val.u.xval);
- smagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- cgenr(nl, &n1, res);
- nodconst(&n2, nl->type, m.sm);
- regalloc(&n3, nl->type, N);
- cgen_hmul(&n1, &n2, &n3);
-
- if(m.sm < 0) {
- // need to add numerator
- gins(optoas(OADD, nl->type), &n1, &n3);
- }
-
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &n3); // shift n3
-
- nodconst(&n2, nl->type, w-1);
- gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg
- gins(optoas(OSUB, nl->type), &n1, &n3); // added
-
- if(m.sd < 0) {
- // this could probably be removed
- // by factoring it into the multiplier
- gins(optoas(OMINUS, nl->type), N, &n3);
- }
-
- gmove(&n3, res);
- regfree(&n1);
- regfree(&n3);
- return;
- }
- goto longdiv;
-
-longdiv:
- // division and mod using (slow) hardware instruction
- dodiv(op, nl, nr, res);
- return;
-
-longmod:
- // mod using formula A%B = A-(A/B*B) but
- // we know that there is a fast algorithm for A/B
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- regalloc(&n2, nl->type, N);
- cgen_div(ODIV, &n1, nr, &n2);
- a = optoas(OMUL, nl->type);
- if(w == 8) {
- // use 2-operand 16-bit multiply
- // because there is no 2-operand 8-bit multiply
- a = AIMULW;
- }
- if(!smallintconst(nr)) {
- regalloc(&n3, nl->type, N);
- cgen(nr, &n3);
- gins(a, &n3, &n2);
- regfree(&n3);
- } else
- gins(a, nr, &n2);
- gins(optoas(OSUB, nl->type), &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
- Type *t;
- int a;
- Node n1, n2, ax, dx, *tmp;
-
- t = nl->type;
- a = optoas(OHMUL, t);
- if(nl->ullman < nr->ullman) {
- tmp = nl;
- nl = nr;
- nr = tmp;
- }
- cgenr(nl, &n1, res);
- cgenr(nr, &n2, N);
- nodreg(&ax, t, REG_AX);
- gmove(&n1, &ax);
- gins(a, &n2, N);
- regfree(&n2);
- regfree(&n1);
-
- if(t->width == 1) {
- // byte multiply behaves differently.
- nodreg(&ax, t, REG_AH);
- nodreg(&dx, t, REG_DX);
- gmove(&ax, &dx);
- }
- nodreg(&dx, t, REG_DX);
- gmove(&dx, res);
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, cx, oldcx;
- int a, rcx;
- Prog *p1;
- uvlong sc;
- Type *tcount;
-
- a = optoas(op, nl->type);
-
- if(nr->op == OLITERAL) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc >= nl->type->width*8) {
- // large shift gets 2 shifts by width-1
- nodconst(&n3, types[TUINT32], nl->type->width*8-1);
- gins(a, &n3, &n1);
- gins(a, &n3, &n1);
- } else
- gins(a, nr, &n1);
- gmove(&n1, res);
- regfree(&n1);
- goto ret;
- }
-
- if(nl->ullman >= UINF) {
- tempname(&n4, nl->type);
- cgen(nl, &n4);
- nl = &n4;
- }
- if(nr->ullman >= UINF) {
- tempname(&n5, nr->type);
- cgen(nr, &n5);
- nr = &n5;
- }
-
- rcx = reg[REG_CX];
- nodreg(&n1, types[TUINT32], REG_CX);
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount = types[simtype[nr->type->etype]];
- if(tcount->etype < TUINT32)
- tcount = types[TUINT32];
-
- regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
- regalloc(&n3, tcount, &n1); // to clear high bits of CX
-
- nodreg(&cx, types[TUINT64], REG_CX);
- memset(&oldcx, 0, sizeof oldcx);
- if(rcx > 0 && !samereg(&cx, res)) {
- regalloc(&oldcx, types[TUINT64], N);
- gmove(&cx, &oldcx);
- }
- cx.type = tcount;
-
- if(samereg(&cx, res))
- regalloc(&n2, nl->type, N);
- else
- regalloc(&n2, nl->type, res);
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &n2);
- cgen(nr, &n1);
- gmove(&n1, &n3);
- } else {
- cgen(nr, &n1);
- gmove(&n1, &n3);
- cgen(nl, &n2);
- }
- regfree(&n3);
-
- // test and fix up large shifts
- if(!bounded) {
- nodconst(&n3, tcount, nl->type->width*8);
- gins(optoas(OCMP, tcount), &n1, &n3);
- p1 = gbranch(optoas(OLT, tcount), T, +1);
- if(op == ORSH && issigned[nl->type->etype]) {
- nodconst(&n3, types[TUINT32], nl->type->width*8-1);
- gins(a, &n3, &n2);
- } else {
- nodconst(&n3, nl->type, 0);
- gmove(&n3, &n2);
- }
- patch(p1, pc);
- }
-
- gins(a, &n1, &n2);
-
- if(oldcx.op != 0) {
- cx.type = types[TUINT64];
- gmove(&oldcx, &cx);
- regfree(&oldcx);
- }
-
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-
-ret:
- ;
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n1b, n2b, *tmp;
- Type *t;
- int a;
-
- // largest ullman on left.
- if(nl->ullman < nr->ullman) {
- tmp = nl;
- nl = nr;
- nr = tmp;
- }
-
- // generate operands in "8-bit" registers.
- regalloc(&n1b, nl->type, res);
- cgen(nl, &n1b);
- regalloc(&n2b, nr->type, N);
- cgen(nr, &n2b);
-
- // perform full-width multiplication.
- t = types[TUINT64];
- if(issigned[nl->type->etype])
- t = types[TINT64];
- nodreg(&n1, t, n1b.val.u.reg);
- nodreg(&n2, t, n2b.val.u.reg);
- a = optoas(op, t);
- gins(a, &n2, &n1);
-
- // truncate.
- gmove(&n1, res);
- regfree(&n1b);
- regfree(&n2b);
-}
-
-void
-clearfat(Node *nl)
-{
- int64 w, c, q;
- Node n1, oldn1, ax, oldax, di, z;
- Prog *p;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
- w = nl->type->width;
- // Avoid taking the address for simple enough types.
- if(componentgen(N, nl))
- return;
-
- c = w % 8; // bytes
- q = w / 8; // quads
-
- if(q < 4) {
- // Write sequence of MOV 0, off(base) instead of using STOSQ.
- // The hope is that although the code will be slightly longer,
- // the MOVs will have no dependencies and pipeline better
- // than the unrolled STOSQ loop.
- // NOTE: Must use agen, not igen, so that optimizer sees address
- // being taken. We are not writing on field boundaries.
- agenr(nl, &n1, N);
- n1.op = OINDREG;
- nodconst(&z, types[TUINT64], 0);
- while(q-- > 0) {
- n1.type = z.type;
- gins(AMOVQ, &z, &n1);
- n1.xoffset += 8;
- }
- if(c >= 4) {
- nodconst(&z, types[TUINT32], 0);
- n1.type = z.type;
- gins(AMOVL, &z, &n1);
- n1.xoffset += 4;
- c -= 4;
- }
- nodconst(&z, types[TUINT8], 0);
- while(c-- > 0) {
- n1.type = z.type;
- gins(AMOVB, &z, &n1);
- n1.xoffset++;
- }
- regfree(&n1);
- return;
- }
-
- savex(REG_DI, &n1, &oldn1, N, types[tptr]);
- agen(nl, &n1);
-
- savex(REG_AX, &ax, &oldax, N, types[tptr]);
- gconreg(AMOVL, 0, REG_AX);
-
- if(q > 128 || nacl) {
- gconreg(movptr, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
- } else {
- p = gins(ADUFFZERO, N, N);
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
- // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
- p->to.offset = 2*(128-q);
- }
-
- z = ax;
- di = n1;
- if(w >= 8 && c >= 4) {
- di.op = OINDREG;
- di.type = z.type = types[TINT64];
- p = gins(AMOVQ, &z, &di);
- p->to.scale = 1;
- p->to.offset = c-8;
- } else if(c >= 4) {
- di.op = OINDREG;
- di.type = z.type = types[TINT32];
- p = gins(AMOVL, &z, &di);
- if(c > 4) {
- p = gins(AMOVL, &z, &di);
- p->to.scale = 1;
- p->to.offset = c-4;
- }
- } else
- while(c > 0) {
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- c--;
- }
-
- restx(&n1, &oldn1);
- restx(&ax, &oldax);
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
- Prog *p, *p1, *p2;
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as != ACHECKNIL)
- continue;
- if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
- warnl(p->lineno, "generated nil check");
- // check is
- // CMP arg, $0
- // JNE 2(PC) (likely)
- // MOV AX, 0
- p1 = mal(sizeof *p1);
- p2 = mal(sizeof *p2);
- clearp(p1);
- clearp(p2);
- p1->link = p2;
- p2->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
- p2->lineno = p->lineno;
- p1->pc = 9999;
- p2->pc = 9999;
- p->as = cmpptr;
- p->to.type = TYPE_CONST;
- p->to.offset = 0;
- p1->as = AJNE;
- p1->from.type = TYPE_CONST;
- p1->from.offset = 1; // likely
- p1->to.type = TYPE_BRANCH;
- p1->to.u.branch = p2->link;
- // crash by write to memory address 0.
- // if possible, since we know arg is 0, use 0(arg),
- // which will be shorter to encode than plain 0.
- p2->as = AMOVL;
- p2->from.type = TYPE_REG;
- p2->from.reg = REG_AX;
- if(regtyp(&p->from)) {
- p2->to.type = TYPE_MEM;
- p2->to.reg = p->from.reg;
- } else {
- p2->to.type = TYPE_MEM;
- p2->to.reg = REG_NONE;
- }
- p2->to.offset = 0;
- }
-}
diff --git a/src/cmd/new6g/ggen.go b/src/cmd/6g/ggen.go
index be6ff2152e..be6ff2152e 100644
--- a/src/cmd/new6g/ggen.go
+++ b/src/cmd/6g/ggen.go
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
deleted file mode 100644
index 55d3425081..0000000000
--- a/src/cmd/6g/gsubr.c
+++ /dev/null
@@ -1,1737 +0,0 @@
-// 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 "../../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 ../../runtime/stack.h.
-vlong unmappedzero = 4096;
-static int resvd[] =
-{
- REG_DI, // for movstring
- REG_SI, // for movstring
-
- REG_AX, // for divide
- REG_CX, // for shift
- REG_DX, // for divide
- REG_SP, // for stack
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 1;
- for(i=REG_AX; i<=REG_R15; i++)
- reg[i] = 0;
- for(i=REG_X0; i<=REG_X15; i++)
- reg[i] = 0;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-
- if(nacl) {
- reg[REG_BP]++;
- reg[REG_R15]++;
- } else if(framepointer_enabled) {
- // BP is part of the calling convention of framepointer_enabled.
- reg[REG_BP]++;
- }
-}
-
-void
-gclean(void)
-{
- int i;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]--;
- if(nacl) {
- reg[REG_BP]--;
- reg[REG_R15]--;
- } else if(framepointer_enabled) {
- reg[REG_BP]--;
- }
-
-
- for(i=REG_AX; i<=REG_R15; i++)
- if(reg[i])
- yyerror("reg %R left allocated\n", i);
- for(i=REG_X0; i<=REG_X15; i++)
- if(reg[i])
- yyerror("reg %R left allocated\n", i);
-}
-
-int
-anyregalloc(void)
-{
- int i, j;
-
- for(i=REG_AX; i<=REG_R15; 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;
-}
-
-static uintptr regpc[REG_R15+1 - REG_AX];
-
-/*
- * 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;
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
-
- 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 >= REG_AX && i <= REG_R15)
- goto out;
- }
- for(i=REG_AX; i<=REG_R15; i++)
- if(reg[i] == 0) {
- regpc[i-REG_AX] = (uintptr)getcallerpc(&n);
- goto out;
- }
-
- flusherrors();
- for(i=0; i+REG_AX<=REG_R15; i++)
- print("%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 >= REG_X0 && i <= REG_X15)
- goto out;
- }
- for(i=REG_X0; i<=REG_X15; i++)
- if(reg[i] == 0)
- goto out;
- 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 == REG_SP)
- 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 && REG_AX <= i && i <= REG_R15)
- regpc[i - REG_AX] = 0;
-}
-
-/*
- * generate
- * as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
- Node nr;
-
- switch(as) {
- case AADDL:
- case AMOVL:
- case ALEAL:
- nodreg(&nr, types[TINT32], reg);
- break;
- default:
- nodreg(&nr, types[TINT64], reg);
- }
-
- ginscon(as, c, &nr);
-}
-
-/*
- * generate
- * as $c, n
- */
-void
-ginscon(int as, vlong c, Node *n2)
-{
- Node n1, ntmp;
-
- switch(as) {
- case AADDL:
- case AMOVL:
- case ALEAL:
- nodconst(&n1, types[TINT32], c);
- break;
- default:
- nodconst(&n1, types[TINT64], c);
- }
-
- if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) {
- // cannot have 64-bit immediate in ADD, etc.
- // instead, MOV into register first.
- regalloc(&ntmp, types[TINT64], N);
- gins(AMOVQ, &n1, &ntmp);
- gins(as, &ntmp, n2);
- regfree(&ntmp);
- return;
- }
- gins(as, &n1, n2);
-}
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int); */
-
-/*
- * 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, r4, zero, one, 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) {
- convconst(&con, t->type, &f->val);
- f = &con;
- ft = tt; // so big switch will choose a simple mov
-
- // some constants can't move directly to memory.
- if(ismem(t)) {
- // float constants come from memory.
- if(isfloat[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(TINT8, TUINT8):
- case CASE(TUINT8, TINT8):
- case CASE(TUINT8, TUINT8):
- 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):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(TINT16, TINT16): // same size
- case CASE(TINT16, TUINT16):
- case CASE(TUINT16, TINT16):
- case CASE(TUINT16, TUINT16):
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- case CASE(TINT64, TINT16):
- case CASE(TUINT64, TINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- a = AMOVL;
- break;
-
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- a = AMOVQL;
- break;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- a = AMOVQ;
- break;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- a = AMOVBWSX;
- goto rdst;
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVBLSX;
- goto rdst;
- case CASE(TINT8, TINT64):
- case CASE(TINT8, TUINT64):
- a = AMOVBQSX;
- goto rdst;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- a = AMOVBWZX;
- goto rdst;
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBLZX;
- goto rdst;
- case CASE(TUINT8, TINT64):
- case CASE(TUINT8, TUINT64):
- a = AMOVBQZX;
- goto rdst;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVWLSX;
- goto rdst;
- case CASE(TINT16, TINT64):
- case CASE(TINT16, TUINT64):
- a = AMOVWQSX;
- goto rdst;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVWLZX;
- goto rdst;
- case CASE(TUINT16, TINT64):
- case CASE(TUINT16, TUINT64):
- a = AMOVWQZX;
- goto rdst;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- a = AMOVLQSX;
- goto rdst;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- // AMOVL into a register zeros the top of the register,
- // so this is not always necessary, but if we rely on AMOVL
- // the optimizer is almost certain to screw with us.
- a = AMOVLQZX;
- goto rdst;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT32):
- a = ACVTTSS2SL;
- goto rdst;
-
- case CASE(TFLOAT64, TINT32):
- a = ACVTTSD2SL;
- goto rdst;
-
- case CASE(TFLOAT32, TINT64):
- a = ACVTTSS2SQ;
- goto rdst;
-
- case CASE(TFLOAT64, TINT64):
- a = ACVTTSD2SQ;
- goto rdst;
-
- 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):
- // convert via int32.
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TFLOAT32, TUINT32):
- case CASE(TFLOAT64, TUINT32):
- // convert via int64.
- cvt = types[TINT64];
- goto hard;
-
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- // algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
- a = ACVTTSS2SQ;
- if(ft == TFLOAT64)
- a = ACVTTSD2SQ;
- bignodes();
- regalloc(&r1, types[ft], N);
- regalloc(&r2, types[tt], t);
- regalloc(&r3, types[ft], N);
- regalloc(&r4, types[tt], N);
- gins(optoas(OAS, f->type), f, &r1);
- gins(optoas(OCMP, f->type), &bigf, &r1);
- p1 = gbranch(optoas(OLE, f->type), T, +1);
- gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- gins(optoas(OAS, f->type), &bigf, &r3);
- gins(optoas(OSUB, f->type), &r3, &r1);
- gins(a, &r1, &r2);
- gins(AMOVQ, &bigi, &r4);
- gins(AXORQ, &r4, &r2);
- patch(p2, pc);
- gmove(&r2, t);
- regfree(&r4);
- regfree(&r3);
- regfree(&r2);
- regfree(&r1);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT32, TFLOAT32):
- a = ACVTSL2SS;
- goto rdst;
-
-
- case CASE(TINT32, TFLOAT64):
- a = ACVTSL2SD;
- goto rdst;
-
- case CASE(TINT64, TFLOAT32):
- a = ACVTSQ2SS;
- goto rdst;
-
- case CASE(TINT64, TFLOAT64):
- a = ACVTSQ2SD;
- goto rdst;
-
- 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):
- // convert via int32
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT64):
- // convert via int64.
- cvt = types[TINT64];
- goto hard;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- // algorithm is:
- // if small enough, use native int64 -> uint64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- a = ACVTSQ2SS;
- if(tt == TFLOAT64)
- a = ACVTSQ2SD;
- nodconst(&zero, types[TUINT64], 0);
- nodconst(&one, types[TUINT64], 1);
- regalloc(&r1, f->type, f);
- regalloc(&r2, t->type, t);
- regalloc(&r3, f->type, N);
- regalloc(&r4, f->type, N);
- gmove(f, &r1);
- gins(ACMPQ, &r1, &zero);
- p1 = gbranch(AJLT, T, +1);
- gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- gmove(&r1, &r3);
- gins(ASHRQ, &one, &r3);
- gmove(&r1, &r4);
- gins(AANDL, &one, &r4);
- gins(AORQ, &r4, &r3);
- gins(a, &r3, &r2);
- gins(optoas(OADD, t->type), &r2, &r2);
- patch(p2, pc);
- gmove(&r2, t);
- regfree(&r4);
- regfree(&r3);
- regfree(&r2);
- regfree(&r1);
- return;
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(TFLOAT64, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- a = ACVTSS2SD;
- goto rdst;
-
- case CASE(TFLOAT64, TFLOAT32):
- a = ACVTSD2SS;
- 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;
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-// Node nod;
- int32 w;
- Prog *p;
- Addr af, at;
-
-// if(f != N && f->op == OINDEX) {
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(f->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
-// }
-// if(t != N && t->op == OINDEX) {
-// regalloc(&nod, &regnode, Z);
-// v = constnode.vconst;
-// cgen(t->right, &nod);
-// constnode.vconst = v;
-// idx.reg = nod.reg;
-// regfree(&nod);
-// }
-
- switch(as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(f != N && t != N && samaddr(f, t))
- return nil;
- break;
-
- case ALEAQ:
- if(f != N && isconst(f, CTNIL)) {
- fatal("gins LEAQ nil %T", f->type);
- }
- break;
- }
-
- 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(debug['g'])
- print("%P\n", p);
-
- w = 0;
- switch(as) {
- case AMOVB:
- w = 1;
- break;
- case AMOVW:
- w = 2;
- break;
- case AMOVL:
- w = 4;
- break;
- case AMOVQ:
- 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);
- }
- if(p->to.type == TYPE_ADDR && w > 0)
- fatal("bad use of addr: %P", p);
-
- return p;
-}
-
-void
-fixlargeoffset(Node *n)
-{
- Node a;
-
- if(n == N)
- return;
- if(n->op != OINDREG)
- return;
- if(n->val.u.reg == REG_SP) // stack offset cannot be large
- return;
- if(n->xoffset != (int32)n->xoffset) {
- // offset too large, add to register instead.
- 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;
- }
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
- int a;
-
- if(t == T)
- fatal("optoas: t is nil");
-
- a = AXXX;
- switch(CASE(op, simtype[t->etype])) {
- default:
- fatal("optoas: no entry %O-%T", op, t);
- break;
-
- case CASE(OADDR, TPTR32):
- a = ALEAL;
- break;
-
- case CASE(OADDR, TPTR64):
- a = ALEAQ;
- 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 = AJEQ;
- 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 = AJNE;
- break;
-
- case CASE(OLT, TINT8):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- a = AJLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = AJCS;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- a = AJLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = AJLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- a = AJGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = AJHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- a = AJGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = AJCC;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- a = ACMPB;
- break;
-
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- a = ACMPW;
- break;
-
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMPL;
- break;
-
- case CASE(OCMP, TINT64):
- case CASE(OCMP, TUINT64):
- case CASE(OCMP, TPTR64):
- a = ACMPQ;
- break;
-
- case CASE(OCMP, TFLOAT32):
- a = AUCOMISS;
- break;
-
- case CASE(OCMP, TFLOAT64):
- a = AUCOMISD;
- break;
-
- case CASE(OAS, TBOOL):
- case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVL;
- break;
-
- case CASE(OAS, TINT64):
- case CASE(OAS, TUINT64):
- case CASE(OAS, TPTR64):
- a = AMOVQ;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(OADD, TINT8):
- case CASE(OADD, TUINT8):
- a = AADDB;
- break;
-
- case CASE(OADD, TINT16):
- case CASE(OADD, TUINT16):
- a = AADDW;
- break;
-
- case CASE(OADD, TINT32):
- case CASE(OADD, TUINT32):
- case CASE(OADD, TPTR32):
- a = AADDL;
- break;
-
- case CASE(OADD, TINT64):
- case CASE(OADD, TUINT64):
- case CASE(OADD, TPTR64):
- a = AADDQ;
- break;
-
- case CASE(OADD, TFLOAT32):
- a = AADDSS;
- break;
-
- case CASE(OADD, TFLOAT64):
- a = AADDSD;
- break;
-
- case CASE(OSUB, TINT8):
- case CASE(OSUB, TUINT8):
- a = ASUBB;
- break;
-
- case CASE(OSUB, TINT16):
- case CASE(OSUB, TUINT16):
- a = ASUBW;
- break;
-
- case CASE(OSUB, TINT32):
- case CASE(OSUB, TUINT32):
- case CASE(OSUB, TPTR32):
- a = ASUBL;
- break;
-
- case CASE(OSUB, TINT64):
- case CASE(OSUB, TUINT64):
- case CASE(OSUB, TPTR64):
- a = ASUBQ;
- break;
-
- case CASE(OSUB, TFLOAT32):
- a = ASUBSS;
- break;
-
- case CASE(OSUB, TFLOAT64):
- a = ASUBSD;
- break;
-
- case CASE(OINC, TINT8):
- case CASE(OINC, TUINT8):
- a = AINCB;
- break;
-
- case CASE(OINC, TINT16):
- case CASE(OINC, TUINT16):
- a = AINCW;
- break;
-
- case CASE(OINC, TINT32):
- case CASE(OINC, TUINT32):
- case CASE(OINC, TPTR32):
- a = AINCL;
- break;
-
- case CASE(OINC, TINT64):
- case CASE(OINC, TUINT64):
- case CASE(OINC, TPTR64):
- a = AINCQ;
- break;
-
- case CASE(ODEC, TINT8):
- case CASE(ODEC, TUINT8):
- a = ADECB;
- break;
-
- case CASE(ODEC, TINT16):
- case CASE(ODEC, TUINT16):
- a = ADECW;
- break;
-
- case CASE(ODEC, TINT32):
- case CASE(ODEC, TUINT32):
- case CASE(ODEC, TPTR32):
- a = ADECL;
- break;
-
- case CASE(ODEC, TINT64):
- case CASE(ODEC, TUINT64):
- case CASE(ODEC, TPTR64):
- a = ADECQ;
- break;
-
- case CASE(OMINUS, TINT8):
- case CASE(OMINUS, TUINT8):
- a = ANEGB;
- break;
-
- case CASE(OMINUS, TINT16):
- case CASE(OMINUS, TUINT16):
- a = ANEGW;
- break;
-
- case CASE(OMINUS, TINT32):
- case CASE(OMINUS, TUINT32):
- case CASE(OMINUS, TPTR32):
- a = ANEGL;
- break;
-
- case CASE(OMINUS, TINT64):
- case CASE(OMINUS, TUINT64):
- case CASE(OMINUS, TPTR64):
- a = ANEGQ;
- break;
-
- case CASE(OAND, TINT8):
- case CASE(OAND, TUINT8):
- a = AANDB;
- break;
-
- case CASE(OAND, TINT16):
- case CASE(OAND, TUINT16):
- a = AANDW;
- break;
-
- case CASE(OAND, TINT32):
- case CASE(OAND, TUINT32):
- case CASE(OAND, TPTR32):
- a = AANDL;
- break;
-
- case CASE(OAND, TINT64):
- case CASE(OAND, TUINT64):
- case CASE(OAND, TPTR64):
- a = AANDQ;
- break;
-
- case CASE(OOR, TINT8):
- case CASE(OOR, TUINT8):
- a = AORB;
- break;
-
- case CASE(OOR, TINT16):
- case CASE(OOR, TUINT16):
- a = AORW;
- break;
-
- case CASE(OOR, TINT32):
- case CASE(OOR, TUINT32):
- case CASE(OOR, TPTR32):
- a = AORL;
- break;
-
- case CASE(OOR, TINT64):
- case CASE(OOR, TUINT64):
- case CASE(OOR, TPTR64):
- a = AORQ;
- break;
-
- case CASE(OXOR, TINT8):
- case CASE(OXOR, TUINT8):
- a = AXORB;
- break;
-
- case CASE(OXOR, TINT16):
- case CASE(OXOR, TUINT16):
- a = AXORW;
- break;
-
- case CASE(OXOR, TINT32):
- case CASE(OXOR, TUINT32):
- case CASE(OXOR, TPTR32):
- a = AXORL;
- break;
-
- case CASE(OXOR, TINT64):
- case CASE(OXOR, TUINT64):
- case CASE(OXOR, TPTR64):
- a = AXORQ;
- break;
-
- case CASE(OLROT, TINT8):
- case CASE(OLROT, TUINT8):
- a = AROLB;
- break;
-
- case CASE(OLROT, TINT16):
- case CASE(OLROT, TUINT16):
- a = AROLW;
- break;
-
- case CASE(OLROT, TINT32):
- case CASE(OLROT, TUINT32):
- case CASE(OLROT, TPTR32):
- a = AROLL;
- break;
-
- case CASE(OLROT, TINT64):
- case CASE(OLROT, TUINT64):
- case CASE(OLROT, TPTR64):
- a = AROLQ;
- break;
-
- case CASE(OLSH, TINT8):
- case CASE(OLSH, TUINT8):
- a = ASHLB;
- break;
-
- case CASE(OLSH, TINT16):
- case CASE(OLSH, TUINT16):
- a = ASHLW;
- break;
-
- case CASE(OLSH, TINT32):
- case CASE(OLSH, TUINT32):
- case CASE(OLSH, TPTR32):
- a = ASHLL;
- break;
-
- case CASE(OLSH, TINT64):
- case CASE(OLSH, TUINT64):
- case CASE(OLSH, TPTR64):
- a = ASHLQ;
- break;
-
- case CASE(ORSH, TUINT8):
- a = ASHRB;
- break;
-
- case CASE(ORSH, TUINT16):
- a = ASHRW;
- break;
-
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASHRL;
- break;
-
- case CASE(ORSH, TUINT64):
- case CASE(ORSH, TPTR64):
- a = ASHRQ;
- break;
-
- case CASE(ORSH, TINT8):
- a = ASARB;
- break;
-
- case CASE(ORSH, TINT16):
- a = ASARW;
- break;
-
- case CASE(ORSH, TINT32):
- a = ASARL;
- break;
-
- case CASE(ORSH, TINT64):
- a = ASARQ;
- break;
-
- case CASE(ORROTC, TINT8):
- case CASE(ORROTC, TUINT8):
- a = ARCRB;
- break;
-
- case CASE(ORROTC, TINT16):
- case CASE(ORROTC, TUINT16):
- a = ARCRW;
- break;
-
- case CASE(ORROTC, TINT32):
- case CASE(ORROTC, TUINT32):
- a = ARCRL;
- break;
-
- case CASE(ORROTC, TINT64):
- case CASE(ORROTC, TUINT64):
- a = ARCRQ;
- break;
-
- case CASE(OHMUL, TINT8):
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TUINT8):
- a = AIMULB;
- break;
-
- case CASE(OHMUL, TINT16):
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TUINT16):
- a = AIMULW;
- break;
-
- case CASE(OHMUL, TINT32):
- case CASE(OMUL, TINT32):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AIMULL;
- break;
-
- case CASE(OHMUL, TINT64):
- case CASE(OMUL, TINT64):
- case CASE(OMUL, TUINT64):
- case CASE(OMUL, TPTR64):
- a = AIMULQ;
- break;
-
- case CASE(OHMUL, TUINT8):
- a = AMULB;
- break;
-
- case CASE(OHMUL, TUINT16):
- a = AMULW;
- break;
-
- case CASE(OHMUL, TUINT32):
- case CASE(OHMUL, TPTR32):
- a = AMULL;
- break;
-
- case CASE(OHMUL, TUINT64):
- case CASE(OHMUL, TPTR64):
- a = AMULQ;
- break;
-
- case CASE(OMUL, TFLOAT32):
- a = AMULSS;
- break;
-
- case CASE(OMUL, TFLOAT64):
- a = AMULSD;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(OMOD, TINT8):
- a = AIDIVB;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(OMOD, TUINT8):
- a = ADIVB;
- break;
-
- case CASE(ODIV, TINT16):
- case CASE(OMOD, TINT16):
- a = AIDIVW;
- break;
-
- case CASE(ODIV, TUINT16):
- case CASE(OMOD, TUINT16):
- a = ADIVW;
- break;
-
- case CASE(ODIV, TINT32):
- case CASE(OMOD, TINT32):
- a = AIDIVL;
- break;
-
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = ADIVL;
- break;
-
- case CASE(ODIV, TINT64):
- case CASE(OMOD, TINT64):
- a = AIDIVQ;
- break;
-
- case CASE(ODIV, TUINT64):
- case CASE(ODIV, TPTR64):
- case CASE(OMOD, TUINT64):
- case CASE(OMOD, TPTR64):
- a = ADIVQ;
- break;
-
- case CASE(OEXTEND, TINT16):
- a = ACWD;
- break;
-
- case CASE(OEXTEND, TINT32):
- a = ACDQ;
- break;
-
- case CASE(OEXTEND, TINT64):
- a = ACQO;
- break;
-
- case CASE(ODIV, TFLOAT32):
- a = ADIVSS;
- break;
-
- case CASE(ODIV, TFLOAT64):
- a = ADIVSD;
- break;
-
- }
- return a;
-}
-
-enum
-{
- ODynam = 1<<0,
- OAddable = 1<<1,
-};
-
-static Node clean[20];
-static int cleani = 0;
-
-int
-xgen(Node *n, Node *a, int o)
-{
- regalloc(a, types[tptr], N);
-
- if(o & ODynam)
- if(n->addable)
- if(n->op != OINDREG)
- if(n->op != OREGISTER)
- return 1;
-
- agen(n, a);
- return 0;
-}
-
-void
-sudoclean(void)
-{
- if(clean[cleani-1].op != OEMPTY)
- regfree(&clean[cleani-1]);
- if(clean[cleani-2].op != OEMPTY)
- regfree(&clean[cleani-2]);
- cleani -= 2;
-}
-
-/*
- * 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)
-{
- int o, i;
- int64 oary[10];
- int64 v, w;
- Node n1, n2, n3, n4, *nn, *l, *r;
- Node *reg, *reg1;
- Prog *p1;
- Type *t;
-
- if(n->type == T)
- return 0;
-
- memset(a, 0, sizeof *a);
-
- switch(n->op) {
- case OLITERAL:
- if(!isconst(n, CTINT))
- break;
- v = mpgetfix(n->val.u.xval);
- if(v >= 32000 || v <= -32000)
- break;
- goto lit;
-
- case ODOT:
- case ODOTPTR:
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- goto odot;
-
- case OINDEX:
- return 0;
- // disabled: OINDEX case is now covered by agenr
- // for a more suitable register allocation pattern.
- if(n->left->type->etype == TSTRING)
- return 0;
- goto oindex;
- }
- return 0;
-
-lit:
- switch(as) {
- default:
- return 0;
- case AADDB: case AADDW: case AADDL: case AADDQ:
- case ASUBB: case ASUBW: case ASUBL: case ASUBQ:
- case AANDB: case AANDW: case AANDL: case AANDQ:
- case AORB: case AORW: case AORL: case AORQ:
- case AXORB: case AXORW: case AXORL: case AXORQ:
- case AINCB: case AINCW: case AINCL: case AINCQ:
- case ADECB: case ADECW: case ADECL: case ADECQ:
- case AMOVB: case AMOVW: case AMOVL: case AMOVQ:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
- naddr(n, a, 1);
- goto yes;
-
-odot:
- o = dotoffset(n, oary, &nn);
- if(nn == N)
- goto no;
-
- if(nn->addable && o == 1 && oary[0] >= 0) {
- // directly addressable set of DOTs
- n1 = *nn;
- n1.type = n->type;
- n1.xoffset += oary[0];
- naddr(&n1, a, 1);
- goto yes;
- }
-
- regalloc(reg, types[tptr], N);
- n1 = *reg;
- n1.op = OINDREG;
- if(oary[0] >= 0) {
- agen(nn, reg);
- n1.xoffset = oary[0];
- } else {
- cgen(nn, reg);
- cgen_checknil(reg);
- n1.xoffset = -(oary[0]+1);
- }
-
- for(i=1; i<o; i++) {
- if(oary[i] >= 0)
- fatal("can't happen");
- gins(movptr, &n1, reg);
- cgen_checknil(reg);
- n1.xoffset = -(oary[i]+1);
- }
-
- a->type = TYPE_NONE;
- a->index = TYPE_NONE;
- fixlargeoffset(&n1);
- naddr(&n1, a, 1);
- goto yes;
-
-oindex:
- l = n->left;
- r = n->right;
- if(l->ullman >= UINF && r->ullman >= UINF)
- return 0;
-
- // set o to type of array
- o = 0;
- if(isptr[l->type->etype])
- fatal("ptr ary");
- if(l->type->etype != TARRAY)
- fatal("not ary");
- if(l->type->bound < 0)
- o |= ODynam;
-
- w = n->type->width;
- if(isconst(r, CTINT))
- goto oindex_const;
-
- switch(w) {
- default:
- return 0;
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- }
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
-
- // load the array (reg)
- if(l->ullman > r->ullman) {
- if(xgen(l, reg, o))
- o |= OAddable;
- }
-
- // load the index (reg1)
- t = types[TUINT64];
- if(issigned[r->type->etype])
- t = types[TINT64];
- regalloc(reg1, t, N);
- regalloc(&n3, r->type, reg1);
- cgen(r, &n3);
- gmove(&n3, reg1);
- regfree(&n3);
-
- // load the array (reg)
- if(l->ullman <= r->ullman) {
- if(xgen(l, reg, o))
- o |= OAddable;
- }
-
- // check bounds
- if(!debug['B'] && !n->bounded) {
- // check bounds
- n4.op = OXXX;
- t = types[simtype[TUINT]];
- if(o & ODynam) {
- if(o & OAddable) {
- n2 = *l;
- n2.xoffset += Array_nel;
- n2.type = types[simtype[TUINT]];
- } else {
- n2 = *reg;
- n2.xoffset = Array_nel;
- n2.op = OINDREG;
- n2.type = types[simtype[TUINT]];
- }
- } else {
- if(is64(r->type))
- t = types[TUINT64];
- nodconst(&n2, types[TUINT64], l->type->bound);
- }
- gins(optoas(OCMP, t), reg1, &n2);
- p1 = gbranch(optoas(OLT, t), T, +1);
- if(n4.op != OXXX)
- regfree(&n4);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
-
- if(o & ODynam) {
- if(o & OAddable) {
- n2 = *l;
- n2.xoffset += Array_array;
- n2.type = types[tptr];
- gmove(&n2, reg);
- } else {
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = Array_array;
- n2.type = types[tptr];
- gmove(&n2, reg);
- }
- }
-
- if(o & OAddable) {
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->reg;
- a->type = TYPE_MEM;
- a->reg = reg->val.u.reg;
- } else {
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->reg;
- a->type = TYPE_MEM;
- a->reg = reg->val.u.reg;
- }
-
- goto yes;
-
-oindex_const:
- // index is constant
- // can check statically and
- // can multiply by width statically
-
- v = mpgetfix(r->val.u.xval);
-
- if(sudoaddable(as, l, a))
- goto oindex_const_sudo;
-
- cleani += 2;
- reg = &clean[cleani-1];
- reg1 = &clean[cleani-2];
- reg->op = OEMPTY;
- reg1->op = OEMPTY;
-
- if(o & ODynam) {
- regalloc(reg, types[tptr], N);
- agen(l, reg);
-
- if(!debug['B'] && !n->bounded) {
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT64], v);
- gins(optoas(OCMP, types[simtype[TUINT]]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
-
- n1 = *reg;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, reg);
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v*w;
- fixlargeoffset(&n2);
- a->type = TYPE_NONE;
- a->index = TYPE_NONE;
- naddr(&n2, a, 1);
- goto yes;
- }
-
- igen(l, &n1, N);
- if(n1.op == OINDREG) {
- *reg = n1;
- reg->op = OREGISTER;
- }
- n1.xoffset += v*w;
- fixlargeoffset(&n1);
- a->type = TYPE_NONE;
- a->index= TYPE_NONE;
- naddr(&n1, a, 1);
- goto yes;
-
-oindex_const_sudo:
- if((o & ODynam) == 0) {
- // array indexed by a constant
- a->offset += v*w;
- goto yes;
- }
-
- // slice indexed by a constant
- if(!debug['B'] && !n->bounded) {
- a->offset += Array_nel;
- nodconst(&n2, types[TUINT64], v);
- p1 = gins(optoas(OCMP, types[simtype[TUINT]]), N, &n2);
- p1->from = *a;
- p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
- ginscall(panicindex, -1);
- patch(p1, pc);
- a->offset -= Array_nel;
- }
-
- a->offset += Array_array;
- reg = &clean[cleani-1];
- if(reg->op == OEMPTY)
- regalloc(reg, types[tptr], N);
-
- p1 = gins(movptr, N, reg);
- p1->from = *a;
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v*w;
- fixlargeoffset(&n2);
- a->type = TYPE_NONE;
- a->index = TYPE_NONE;
- naddr(&n2, a, 1);
- goto yes;
-
-yes:
- return 1;
-
-no:
- sudoclean();
- return 0;
-}
diff --git a/src/cmd/new6g/gsubr.go b/src/cmd/6g/gsubr.go
index c440f8c5f7..c440f8c5f7 100644
--- a/src/cmd/new6g/gsubr.go
+++ b/src/cmd/6g/gsubr.go
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
deleted file mode 100644
index 261cb6e0a1..0000000000
--- a/src/cmd/6g/peep.c
+++ /dev/null
@@ -1,988 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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 "../gc/popt.h"
-
-static void conprop(Flow *r);
-static void elimshortmov(Graph *g);
-static int prevl(Flow *r, int reg);
-static void pushback(Flow *r);
-static int regconsttyp(Adr*);
-static int subprop(Flow*);
-static int copyprop(Graph*, Flow*);
-static int copy1(Adr*, Adr*, Flow*, int);
-static int copyas(Adr*, Adr*);
-static int copyau(Adr*, Adr*);
-static int copysub(Adr*, Adr*, Adr*, int);
-static int copyu(Prog*, Adr*, Adr*);
-
-static uint32 gactive;
-
-enum
-{
- exregoffset = REG_R15,
-};
-
-// do we need the carry bit
-static int
-needc(Prog *p)
-{
- ProgInfo info;
-
- while(p != P) {
- proginfo(&info, p);
- if(info.flags & UseCarry)
- return 1;
- if(info.flags & (SetCarry|KillCarry))
- return 0;
- p = p->link;
- }
- return 0;
-}
-
-static Flow*
-rnops(Flow *r)
-{
- Prog *p;
- Flow *r1;
-
- if(r != nil)
- for(;;) {
- p = r->prog;
- if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE)
- break;
- r1 = uniqs(r);
- if(r1 == nil)
- break;
- r = r1;
- }
- return r;
-}
-
-void
-peep(Prog *firstp)
-{
- Flow *r, *r1;
- Graph *g;
- Prog *p, *p1;
- int t;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
- gactive = 0;
-
- // byte, word arithmetic elimination.
- elimshortmov(g);
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ALEAL:
- case ALEAQ:
- if(regtyp(&p->to))
- if(p->from.sym != nil)
- if(p->from.index == REG_NONE)
- conprop(r);
- break;
-
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST)
- conprop(r);
- break;
- }
- }
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", g->start, 0);
-
- t = 0;
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVL:
- case AMOVQ:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(regtyp(&p->from)) {
- if(copyprop(g, r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(g, r)) {
- excise(r);
- t++;
- }
- }
- break;
-
- case AMOVBLZX:
- case AMOVWLZX:
- case AMOVBLSX:
- case AMOVWLSX:
- if(regtyp(&p->to)) {
- r1 = rnops(uniqs(r));
- if(r1 != nil) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
- p1->as = AMOVL;
- t++;
- }
- }
- }
- break;
-
- case AMOVBQSX:
- case AMOVBQZX:
- case AMOVWQSX:
- case AMOVWQZX:
- case AMOVLQSX:
- case AMOVLQZX:
- case AMOVQL:
- if(regtyp(&p->to)) {
- r1 = rnops(uniqs(r));
- if(r1 != nil) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
- p1->as = AMOVQ;
- t++;
- }
- }
- }
- break;
-
- case AADDL:
- case AADDQ:
- case AADDW:
- if(p->from.type != TYPE_CONST || needc(p->link))
- break;
- if(p->from.offset == -1){
- if(p->as == AADDQ)
- p->as = ADECQ;
- else
- if(p->as == AADDL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == AADDQ)
- p->as = AINCQ;
- else if(p->as == AADDL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- break;
- }
- break;
-
- case ASUBL:
- case ASUBQ:
- case ASUBW:
- if(p->from.type != TYPE_CONST || needc(p->link))
- break;
- if(p->from.offset == -1) {
- if(p->as == ASUBQ)
- p->as = AINCQ;
- else
- if(p->as == ASUBL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == ASUBQ)
- p->as = ADECQ;
- else
- if(p->as == ASUBL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- break;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-
- // MOVLQZX removal.
- // The MOVLQZX exists to avoid being confused for a
- // MOVL that is just copying 32-bit data around during
- // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2
- // if it is dominated by an earlier ADDL/MOVL/etc into R1 that
- // will have already cleared the high bits.
- //
- // MOVSD removal.
- // We never use packed registers, so a MOVSD between registers
- // can be replaced by MOVAPD, which moves the pair of float64s
- // instead of just the lower one. We only use the lower one, but
- // the processor can do better if we do moves using both.
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- if(p->as == AMOVLQZX)
- if(regtyp(&p->from))
- if(p->from.type == p->to.type && p->from.reg == p->to.reg)
- if(prevl(r, p->from.reg))
- excise(r);
-
- if(p->as == AMOVSD)
- if(regtyp(&p->from))
- if(regtyp(&p->to))
- p->as = AMOVAPD;
- }
-
- // load pipelining
- // push any load from memory as early as possible
- // to give it time to complete before use.
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVQ:
- case AMOVLQZX:
- if(regtyp(&p->to) && !regconsttyp(&p->from))
- pushback(r);
- }
- }
-
- flowend(g);
-}
-
-static void
-pushback(Flow *r0)
-{
- Flow *r, *b;
- Prog *p0, *p, t;
-
- b = nil;
- p0 = r0->prog;
- for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) {
- p = r->prog;
- if(p->as != ANOP) {
- if(!regconsttyp(&p->from) || !regtyp(&p->to))
- break;
- if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil))
- break;
- }
- if(p->as == ACALL)
- break;
- b = r;
- }
-
- if(b == nil) {
- if(debug['v']) {
- print("no pushback: %P\n", r0->prog);
- if(r)
- print("\t%P [%d]\n", r->prog, uniqs(r)!=nil);
- }
- return;
- }
-
- if(debug['v']) {
- print("pushback\n");
- for(r=b;; r=r->link) {
- print("\t%P\n", r->prog);
- if(r == r0)
- break;
- }
- }
-
- t = *r0->prog;
- for(r=uniqp(r0);; r=uniqp(r)) {
- p0 = r->link->prog;
- p = r->prog;
- p0->as = p->as;
- p0->lineno = p->lineno;
- p0->from = p->from;
- p0->to = p->to;
-
- if(r == b)
- break;
- }
- p0 = r->prog;
- p0->as = t.as;
- p0->lineno = t.lineno;
- p0->from = t.from;
- p0->to = t.to;
-
- if(debug['v']) {
- print("\tafter\n");
- for(r=b;; r=r->link) {
- print("\t%P\n", r->prog);
- if(r == r0)
- break;
- }
- }
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
-
- nopout(p);
-
- ostats.ndelmov++;
-}
-
-int
-regtyp(Adr *a)
-{
- return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_R15 || REG_X0 <= a->reg && a->reg <= REG_X15);
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible. a movb into a register
-// can smash the entire 32-bit register without
-// causing any trouble.
-//
-// TODO: Using the Q forms here instead of the L forms
-// seems unnecessary, and it makes the instructions longer.
-static void
-elimshortmov(Graph *g)
-{
- Prog *p;
- Flow *r;
-
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- if(regtyp(&p->to)) {
- switch(p->as) {
- case AINCB:
- case AINCW:
- p->as = AINCQ;
- break;
- case ADECB:
- case ADECW:
- p->as = ADECQ;
- break;
- case ANEGB:
- case ANEGW:
- p->as = ANEGQ;
- break;
- case ANOTB:
- case ANOTW:
- p->as = ANOTQ;
- break;
- }
- if(regtyp(&p->from) || p->from.type == TYPE_CONST) {
- // move or artihmetic into partial register.
- // from another register or constant can be movl.
- // we don't switch to 64-bit arithmetic if it can
- // change how the carry bit is set (and the carry bit is needed).
- switch(p->as) {
- case AMOVB:
- case AMOVW:
- p->as = AMOVQ;
- break;
- case AADDB:
- case AADDW:
- if(!needc(p->link))
- p->as = AADDQ;
- break;
- case ASUBB:
- case ASUBW:
- if(!needc(p->link))
- p->as = ASUBQ;
- break;
- case AMULB:
- case AMULW:
- p->as = AMULQ;
- break;
- case AIMULB:
- case AIMULW:
- p->as = AIMULQ;
- break;
- case AANDB:
- case AANDW:
- p->as = AANDQ;
- break;
- case AORB:
- case AORW:
- p->as = AORQ;
- break;
- case AXORB:
- case AXORW:
- p->as = AXORQ;
- break;
- case ASHLB:
- case ASHLW:
- p->as = ASHLQ;
- break;
- }
- } else if(p->from.type != TYPE_REG) {
- // explicit zero extension, but don't
- // do that if source is a byte register
- // (only AH can occur and it's forbidden).
- switch(p->as) {
- case AMOVB:
- p->as = AMOVBQZX;
- break;
- case AMOVW:
- p->as = AMOVWQZX;
- break;
- }
- }
- }
- }
-}
-
-// is 'a' a register or constant?
-static int
-regconsttyp(Adr *a)
-{
- if(regtyp(a))
- return 1;
- switch(a->type) {
- case TYPE_CONST:
- case TYPE_FCONST:
- case TYPE_SCONST:
- case TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
- return 1;
- }
- return 0;
-}
-
-// is reg guaranteed to be truncated by a previous L instruction?
-static int
-prevl(Flow *r0, int reg)
-{
- Prog *p;
- Flow *r;
- ProgInfo info;
-
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- p = r->prog;
- if(p->to.type == TYPE_REG && p->to.reg == reg) {
- proginfo(&info, p);
- if(info.flags & RightWrite) {
- if(info.flags & SizeL)
- return 1;
- return 0;
- }
- }
- }
- return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
- Prog *p;
- ProgInfo info;
- Adr *v1, *v2;
- Flow *r;
- int t;
-
- if(debug['P'] && debug['v'])
- print("subprop %P\n", r0->prog);
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1)) {
- if(debug['P'] && debug['v'])
- print("\tnot regtype %D; return 0\n", v1);
- return 0;
- }
- v2 = &p->to;
- if(!regtyp(v2)) {
- if(debug['P'] && debug['v'])
- print("\tnot regtype %D; return 0\n", v2);
- return 0;
- }
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- if(debug['P'] && debug['v'])
- print("\t? %P\n", r->prog);
- if(uniqs(r) == nil) {
- if(debug['P'] && debug['v'])
- print("\tno unique successor\n");
- break;
- }
- p = r->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
- if(info.flags & Call) {
- if(debug['P'] && debug['v'])
- print("\tfound %P; return 0\n", p);
- return 0;
- }
-
- if(info.reguse | info.regset) {
- if(debug['P'] && debug['v'])
- print("\tfound %P; return 0\n", p);
- return 0;
- }
-
- if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg)
- goto gotit;
-
- if(copyau(&p->from, v2) ||
- copyau(&p->to, v2)) {
- if(debug['P'] && debug['v'])
- print("\tcopyau %D failed\n", v2);
- break;
- }
- if(copysub(&p->from, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0)) {
- if(debug['P'] && debug['v'])
- print("\tcopysub failed\n");
- break;
- }
- }
- if(debug['P'] && debug['v'])
- print("\tran off end; return 0\n");
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type && p->from.reg == v2->reg)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
- Prog *p;
- Adr *v1, *v2;
-
- USED(g);
- if(debug['P'] && debug['v'])
- print("copyprop %P\n", r0->prog);
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- gactive++;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active == gactive) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = gactive;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == nil) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub %D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, nil);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %D set and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-static int
-copyu(Prog *p, Adr *v, Adr *s)
-{
- ProgInfo info;
-
- switch(p->as) {
- case AJMP:
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET:
- if(s != nil)
- return 1;
- return 3;
-
- case ACALL:
- if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
- return 2;
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
- return 2;
- if(v->type == p->from.type && v->reg == p->from.reg)
- return 2;
-
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ATEXT:
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
- return 3;
- return 0;
- }
-
- if(p->as == AVARDEF || p->as == AVARKILL)
- return 0;
- proginfo(&info, p);
-
- if((info.reguse|info.regset) & RtoB(v->reg))
- return 2;
-
- if(info.flags & LeftAddr)
- if(copyas(&p->from, v))
- return 2;
-
- if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
- if(copyas(&p->to, v))
- return 2;
-
- if(info.flags & RightWrite) {
- if(copyas(&p->to, v)) {
- if(s != nil)
- return copysub(&p->from, v, s, 1);
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- }
-
- if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- }
-
- return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
- if(REG_AL <= a->reg && a->reg <= REG_R15B)
- fatal("use of byte register");
- if(REG_AL <= v->reg && v->reg <= REG_R15B)
- fatal("use of byte register");
-
- if(a->type != v->type || a->name != v->name || a->reg != v->reg)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
- if(a->type != v->type || a->name != v->name || a->reg != v->reg)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
- if(copyas(a, v)) {
- if(debug['P'] && debug['v'])
- print("\tcopyau: copyas returned 1\n");
- return 1;
- }
- if(regtyp(v)) {
- if(a->type == TYPE_MEM && a->reg == v->reg) {
- if(debug['P'] && debug['v'])
- print("\tcopyau: found indir use - return 1\n");
- return 1;
- }
- if(a->index == v->reg) {
- if(debug['P'] && debug['v'])
- print("\tcopyau: found index use - return 1\n");
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
- int reg;
-
- if(copyas(a, v)) {
- reg = s->reg;
- if(reg >= REG_AX && reg <= REG_R15 || reg >= REG_X0 && reg <= REG_X0+15) {
- if(f)
- a->reg = reg;
- }
- return 0;
- }
- if(regtyp(v)) {
- reg = v->reg;
- if(a->type == TYPE_MEM && a->reg == reg) {
- if((s->reg == REG_BP || s->reg == REG_R13) && a->index != REG_NONE)
- return 1; /* can't use BP-base with index */
- if(f)
- a->reg = s->reg;
-// return 0;
- }
- if(a->index == reg) {
- if(f)
- a->index = s->reg;
- return 0;
- }
- return 0;
- }
- return 0;
-}
-
-static void
-conprop(Flow *r0)
-{
- Flow *r;
- Prog *p, *p0;
- int t;
- Adr *v0;
-
- p0 = r0->prog;
- v0 = &p0->to;
- r = r0;
-
-loop:
- r = uniqs(r);
- if(r == nil || r == r0)
- return;
- if(uniqp(r) == nil)
- return;
-
- p = r->prog;
- t = copyu(p, v0, nil);
- switch(t) {
- case 0: // miss
- case 1: // use
- goto loop;
-
- case 2: // rar
- case 4: // use and set
- break;
-
- case 3: // set
- if(p->as == p0->as)
- if(p->from.type == p0->from.type)
- if(p->from.reg == p0->from.reg)
- if(p->from.node == p0->from.node)
- if(p->from.offset == p0->from.offset)
- if(p->from.scale == p0->from.scale)
- if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval)
- if(p->from.index == p0->from.index) {
- excise(r);
- goto loop;
- }
- break;
- }
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
- return regtyp(reg) &&
- a->type == TYPE_MEM && a->reg == reg->reg &&
- a->index == REG_NONE &&
- 0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
- return a->type == TYPE_REG && a->reg == REG_SP;
-}
diff --git a/src/cmd/new6g/peep.go b/src/cmd/6g/peep.go
index 9870ca5e4e..9870ca5e4e 100644
--- a/src/cmd/new6g/peep.go
+++ b/src/cmd/6g/peep.go
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
deleted file mode 100644
index 79b7911e5b..0000000000
--- a/src/cmd/6g/prog.c
+++ /dev/null
@@ -1,318 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-// Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-REG_AX))
-
-enum {
- AX = RtoB(REG_AX),
- BX = RtoB(REG_BX),
- CX = RtoB(REG_CX),
- DX = RtoB(REG_DX),
- DI = RtoB(REG_DI),
- SI = RtoB(REG_SI),
-
- LeftRdwr = LeftRead | LeftWrite,
- RightRdwr = RightRead | RightWrite,
-};
-
-#undef RtoB
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-static ProgInfo progtable[ALAST] = {
- [ATYPE]= {Pseudo | Skip},
- [ATEXT]= {Pseudo},
- [AFUNCDATA]= {Pseudo},
- [APCDATA]= {Pseudo},
- [AUNDEF]= {Break},
- [AUSEFIELD]= {OK},
- [ACHECKNIL]= {LeftRead},
- [AVARDEF]= {Pseudo | RightWrite},
- [AVARKILL]= {Pseudo | RightWrite},
-
- // NOP is an internal no-op that also stands
- // for USED and SET annotations, not the Intel opcode.
- [ANOP]= {LeftRead | RightWrite},
-
- [AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
- [AADCQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
- [AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
- [AADDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AADDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AADDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
- [AADDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
-
- [AADDSD]= {SizeD | LeftRead | RightRdwr},
- [AADDSS]= {SizeF | LeftRead | RightRdwr},
-
- [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AANDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
- [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [ACALL]= {RightAddr | Call | KillCarry},
-
- [ACDQ]= {OK, AX, AX | DX},
- [ACQO]= {OK, AX, AX | DX},
- [ACWD]= {OK, AX, AX | DX},
-
- [ACLD]= {OK},
- [ASTD]= {OK},
-
- [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry},
- [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry},
- [ACMPQ]= {SizeQ | LeftRead | RightRead | SetCarry},
- [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry},
-
- [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry},
- [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry},
-
- [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
- [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv},
- [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv},
- [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv},
- [ACVTSQ2SD]= {SizeD | LeftRead | RightWrite | Conv},
- [ACVTSQ2SS]= {SizeF | LeftRead | RightWrite | Conv},
- [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv},
- [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
- [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
- [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
-
- [ADECB]= {SizeB | RightRdwr},
- [ADECL]= {SizeL | RightRdwr},
- [ADECQ]= {SizeQ | RightRdwr},
- [ADECW]= {SizeW | RightRdwr},
-
- [ADIVB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [ADIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
- [ADIVQ]= {SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
- [ADIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
- [ADIVSD]= {SizeD | LeftRead | RightRdwr},
- [ADIVSS]= {SizeF | LeftRead | RightRdwr},
-
- [AIDIVB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AIDIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
- [AIDIVQ]= {SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
- [AIDIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
- [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry},
- [AIMULQ]= {SizeQ | LeftRead | ImulAXDX | SetCarry},
- [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry},
-
- [AINCB]= {SizeB | RightRdwr},
- [AINCL]= {SizeL | RightRdwr},
- [AINCQ]= {SizeQ | RightRdwr},
- [AINCW]= {SizeW | RightRdwr},
-
- [AJCC]= {Cjmp | UseCarry},
- [AJCS]= {Cjmp | UseCarry},
- [AJEQ]= {Cjmp | UseCarry},
- [AJGE]= {Cjmp | UseCarry},
- [AJGT]= {Cjmp | UseCarry},
- [AJHI]= {Cjmp | UseCarry},
- [AJLE]= {Cjmp | UseCarry},
- [AJLS]= {Cjmp | UseCarry},
- [AJLT]= {Cjmp | UseCarry},
- [AJMI]= {Cjmp | UseCarry},
- [AJNE]= {Cjmp | UseCarry},
- [AJOC]= {Cjmp | UseCarry},
- [AJOS]= {Cjmp | UseCarry},
- [AJPC]= {Cjmp | UseCarry},
- [AJPL]= {Cjmp | UseCarry},
- [AJPS]= {Cjmp | UseCarry},
-
- [AJMP]= {Jump | Break | KillCarry},
-
- [ALEAL]= {LeftAddr | RightWrite},
- [ALEAQ]= {LeftAddr | RightWrite},
-
- [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVBQSX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVBQZX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv},
- [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv},
- [AMOVLQSX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVLQZX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVWQSX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVWQZX]= {SizeQ | LeftRead | RightWrite | Conv},
- [AMOVQL]= {SizeL | LeftRead | RightWrite | Conv},
-
- [AMOVB]= {SizeB | LeftRead | RightWrite | Move},
- [AMOVL]= {SizeL | LeftRead | RightWrite | Move},
- [AMOVQ]= {SizeQ | LeftRead | RightWrite | Move},
- [AMOVW]= {SizeW | LeftRead | RightWrite | Move},
-
- [AMOVSB]= {OK, DI|SI, DI|SI},
- [AMOVSL]= {OK, DI|SI, DI|SI},
- [AMOVSQ]= {OK, DI|SI, DI|SI},
- [AMOVSW]= {OK, DI|SI, DI|SI},
- [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX},
-
- [AMOVSD]= {SizeD | LeftRead | RightWrite | Move},
- [AMOVSS]= {SizeF | LeftRead | RightWrite | Move},
-
- // We use MOVAPD as a faster synonym for MOVSD.
- [AMOVAPD]= {SizeD | LeftRead | RightWrite | Move},
-
- [AMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AMULL]= {SizeL | LeftRead | SetCarry, AX, AX|DX},
- [AMULQ]= {SizeQ | LeftRead | SetCarry, AX, AX|DX},
- [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX},
-
- [AMULSD]= {SizeD | LeftRead | RightRdwr},
- [AMULSS]= {SizeF | LeftRead | RightRdwr},
-
- [ANEGB]= {SizeB | RightRdwr | SetCarry},
- [ANEGL]= {SizeL | RightRdwr | SetCarry},
- [ANEGQ]= {SizeQ | RightRdwr | SetCarry},
- [ANEGW]= {SizeW | RightRdwr | SetCarry},
-
- [ANOTB]= {SizeB | RightRdwr},
- [ANOTL]= {SizeL | RightRdwr},
- [ANOTQ]= {SizeQ | RightRdwr},
- [ANOTW]= {SizeW | RightRdwr},
-
- [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
- [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [APOPQ]= {SizeQ | RightWrite},
- [APUSHQ]= {SizeQ | LeftRead},
-
- [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
- [ARCRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
- [AREP]= {OK, CX, CX},
- [AREPN]= {OK, CX, CX},
-
- [ARET]= {Break | KillCarry},
-
- [AROLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [AROLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [AROLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ARORQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASALQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASARQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
- [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
- [ASBBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
- [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
- [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASTOSB]= {OK, AX|DI, DI},
- [ASTOSL]= {OK, AX|DI, DI},
- [ASTOSQ]= {OK, AX|DI, DI},
- [ASTOSW]= {OK, AX|DI, DI},
- [ADUFFZERO]= {OK, AX|DI, DI},
-
- [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [ASUBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
- [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [ASUBSD]= {SizeD | LeftRead | RightRdwr},
- [ASUBSS]= {SizeF | LeftRead | RightRdwr},
-
- [ATESTB]= {SizeB | LeftRead | RightRead | SetCarry},
- [ATESTL]= {SizeL | LeftRead | RightRead | SetCarry},
- [ATESTQ]= {SizeQ | LeftRead | RightRead | SetCarry},
- [ATESTW]= {SizeW | LeftRead | RightRead | SetCarry},
-
- [AUCOMISD]= {SizeD | LeftRead | RightRead},
- [AUCOMISS]= {SizeF | LeftRead | RightRead},
-
- [AXCHGB]= {SizeB | LeftRdwr | RightRdwr},
- [AXCHGL]= {SizeL | LeftRdwr | RightRdwr},
- [AXCHGQ]= {SizeQ | LeftRdwr | RightRdwr},
- [AXCHGW]= {SizeW | LeftRdwr | RightRdwr},
-
- [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AXORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AXORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
- [AXORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
- *info = progtable[p->as];
- if(info->flags == 0)
- fatal("unknown instruction %P", p);
-
- if((info->flags & ShiftCX) && p->from.type != TYPE_CONST)
- info->reguse |= CX;
-
- if(info->flags & ImulAXDX) {
- if(p->to.type == TYPE_NONE) {
- info->reguse |= AX;
- info->regset |= AX | DX;
- } else {
- info->flags |= RightRdwr;
- }
- }
-
- // Addressing makes some registers used.
- if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE)
- info->regindex |= RtoB(p->from.reg);
- if(p->from.index != REG_NONE)
- info->regindex |= RtoB(p->from.index);
- if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE)
- info->regindex |= RtoB(p->to.reg);
- if(p->to.index != REG_NONE)
- info->regindex |= RtoB(p->to.index);
-}
diff --git a/src/cmd/new6g/prog.go b/src/cmd/6g/prog.go
index 3f4c19567c..3f4c19567c 100644
--- a/src/cmd/new6g/prog.go
+++ b/src/cmd/6g/prog.go
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
deleted file mode 100644
index e01f265a13..0000000000
--- a/src/cmd/6g/reg.c
+++ /dev/null
@@ -1,153 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 "../gc/popt.h"
-
-enum {
- NREGVAR = 32,
-};
-
-static char* regname[] = {
- ".AX",
- ".CX",
- ".DX",
- ".BX",
- ".SP",
- ".BP",
- ".SI",
- ".DI",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".X0",
- ".X1",
- ".X2",
- ".X3",
- ".X4",
- ".X5",
- ".X6",
- ".X7",
- ".X8",
- ".X9",
- ".X10",
- ".X11",
- ".X12",
- ".X13",
- ".X14",
- ".X15",
-};
-
-char**
-regnames(int *n)
-{
- *n = NREGVAR;
- return regname;
-}
-
-uint64
-excludedregs(void)
-{
- return RtoB(REG_SP);
-}
-
-uint64
-doregbits(int r)
-{
- uint64 b;
-
- b = 0;
- if(r >= REG_AX && r <= REG_R15)
- b |= RtoB(r);
- else
- if(r >= REG_AL && r <= REG_R15B)
- b |= RtoB(r-REG_AL+REG_AX);
- else
- if(r >= REG_AH && r <= REG_BH)
- b |= RtoB(r-REG_AH+REG_AX);
- else
- if(r >= REG_X0 && r <= REG_X0+15)
- b |= FtoB(r);
- return b;
-}
-
-uint64
-RtoB(int r)
-{
-
- if(r < REG_AX || r > REG_R15)
- return 0;
- return 1ULL << (r-REG_AX);
-}
-
-int
-BtoR(uint64 b)
-{
- b &= 0xffffULL;
- if(nacl)
- b &= ~((1<<(REG_BP-REG_AX)) | (1<<(REG_R15-REG_AX)));
- else if(framepointer_enabled)
- // BP is part of the calling convention if framepointer_enabled.
- b &= ~(1<<(REG_BP-REG_AX));
- if(b == 0)
- return 0;
- return bitno(b) + REG_AX;
-}
-
-/*
- * bit reg
- * 16 X0
- * ...
- * 31 X15
- */
-uint64
-FtoB(int f)
-{
- if(f < REG_X0 || f > REG_X15)
- return 0;
- return 1ULL << (f - REG_X0 + 16);
-}
-
-int
-BtoF(uint64 b)
-{
-
- b &= 0xFFFF0000L;
- if(b == 0)
- return 0;
- return bitno(b) - 16 + REG_X0;
-}
diff --git a/src/cmd/new6g/reg.go b/src/cmd/6g/reg.go
index 0629a6248d..0629a6248d 100644
--- a/src/cmd/new6g/reg.go
+++ b/src/cmd/6g/reg.go
diff --git a/src/cmd/new6g/util.go b/src/cmd/6g/util.go
index bb5eedb15a..bb5eedb15a 100644
--- a/src/cmd/new6g/util.go
+++ b/src/cmd/6g/util.go
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
deleted file mode 100644
index 27290ddd71..0000000000
--- a/src/cmd/8a/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
- LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
deleted file mode 100644
index 24654b0ab8..0000000000
--- a/src/cmd/8a/a.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// Inferno utils/8a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
-//
-// 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 <bio.h>
-#include <link.h>
-#include "../8l/8.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef getc
-#undef ungetc
-#undef BUFSIZ
-
-#define getc ccgetc
-#define ungetc ccungetc
-
-typedef struct Sym Sym;
-typedef struct Ref Ref;
-typedef struct Io Io;
-typedef struct Addr2 Addr2;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 500
-#define BUFSIZ 8192
-#define HISTSZ 20
-#ifndef EOF
-#define EOF (-1)
-#endif
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- Ref* ref;
- char* macro;
- int32 value;
- ushort type;
- char *name;
- char* labelname;
- char sym;
-};
-#define S ((Sym*)0)
-
-struct Ref
-{
- int class;
-};
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-struct Addr2
-{
- Addr from;
- Addr to;
-};
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-};
-
-EXTERN int debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN int newflag;
-EXTERN char* hunk;
-EXTERN char** include;
-EXTERN Io* iofree;
-EXTERN Io* ionext;
-EXTERN Io* iostack;
-EXTERN int32 lineno;
-EXTERN int nerrors;
-EXTERN int32 nhunk;
-EXTERN int ninclude;
-EXTERN int32 nsymb;
-EXTERN Addr nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-EXTERN Link* ctxt;
-EXTERN Biobuf bstdout;
-EXTERN Prog* lastpc;
-
-void* alloc(int32);
-void* allocn(void*, int32, int32);
-void ensuresymb(int32);
-void errorexit(void);
-void pushio(void);
-void newio(void);
-void newfile(char*, int);
-Sym* slookup(char*);
-Sym* lookup(void);
-Sym* labellookup(Sym*);
-void settext(LSym*);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void checkscale(int);
-void pinit(char*);
-void cclean(void);
-int isreg(Addr*);
-void outcode(int, Addr2*);
-void outhist(void);
-int filbuf(void);
-Sym* getsym(void);
-void domacro(void);
-void macund(void);
-void macdef(void);
-void macexpand(Sym*, char*);
-void macinc(void);
-void macprag(void);
-void maclin(void);
-void macif(int);
-void macend(void);
-void dodefine(char*);
-void prfile(int32);
-void linehist(char*, int);
-void gethunk(void);
-void yyerror(char*, ...);
-int yyparse(void);
-void setinclude(char*);
-int assemble(char*);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 1a3ab72ff2..906ad331df 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -29,20 +29,28 @@
// THE SOFTWARE.
%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
+package main
+
+import (
+ "cmd/internal/asm"
+ "cmd/internal/obj"
+ . "cmd/internal/obj/i386"
+)
%}
-%union {
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
+
+%union {
+ sym *asm.Sym
+ lval int64
+ con2 struct {
+ v1 int32
+ v2 int32
+ }
+ dval float64
+ sval string
+ addr obj.Addr
+ addr2 Addr2
}
+
%left '|'
%left '^'
%left '&'
@@ -64,18 +72,19 @@
prog:
| prog
{
- stmtline = lineno;
+ stmtline = asm.Lineno;
}
line
line:
LNAME ':'
{
- $1 = labellookup($1);
- if($1->type == LLAB && $1->value != pc)
- yyerror("redeclaration of %s", $1->labelname);
- $1->type = LLAB;
- $1->value = pc;
+ $1 = asm.LabelLookup($1);
+ if $1.Type == LLAB && $1.Value != int64(asm.PC) {
+ yyerror("redeclaration of %s", $1.Labelname)
+ }
+ $1.Type = LLAB;
+ $1.Value = int64(asm.PC)
}
line
| ';'
@@ -85,33 +94,34 @@ line:
inst:
LNAME '=' expr
{
- $1->type = LVAR;
- $1->value = $3;
+ $1.Type = LVAR;
+ $1.Value = $3;
}
| LVAR '=' expr
{
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
- }
-| LTYPE0 nonnon { outcode($1, &$2); }
-| LTYPE1 nonrem { outcode($1, &$2); }
-| LTYPE2 rimnon { outcode($1, &$2); }
-| LTYPE3 rimrem { outcode($1, &$2); }
-| LTYPE4 remrim { outcode($1, &$2); }
-| LTYPER nonrel { outcode($1, &$2); }
+ if $1.Value != int64($3) {
+ yyerror("redeclaration of %s", $1.Name);
+ }
+ $1.Value = $3;
+ }
+| LTYPE0 nonnon { outcode(int($1), &$2); }
+| LTYPE1 nonrem { outcode(int($1), &$2); }
+| LTYPE2 rimnon { outcode(int($1), &$2); }
+| LTYPE3 rimrem { outcode(int($1), &$2); }
+| LTYPE4 remrim { outcode(int($1), &$2); }
+| LTYPER nonrel { outcode(int($1), &$2); }
| spec1
| spec2
-| LTYPEC spec3 { outcode($1, &$2); }
-| LTYPEN spec4 { outcode($1, &$2); }
-| LTYPES spec5 { outcode($1, &$2); }
-| LTYPEM spec6 { outcode($1, &$2); }
-| LTYPEI spec7 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode(int($1), &$2); }
+| LTYPEN spec4 { outcode(int($1), &$2); }
+| LTYPES spec5 { outcode(int($1), &$2); }
+| LTYPEM spec6 { outcode(int($1), &$2); }
+| LTYPEI spec7 { outcode(int($1), &$2); }
| spec8
-| LTYPEXC spec9 { outcode($1, &$2); }
-| LTYPEX spec10 { outcode($1, &$2); }
-| LTYPEPC spec11 { outcode($1, &$2); }
-| LTYPEF spec12 { outcode($1, &$2); }
+| LTYPEXC spec9 { outcode(int($1), &$2); }
+| LTYPEX spec10 { outcode(int($1), &$2); }
+| LTYPEPC spec11 { outcode(int($1), &$2); }
+| LTYPEF spec12 { outcode(int($1), &$2); }
nonnon:
{
@@ -182,60 +192,46 @@ nonrel:
spec1: /* DATA */
LTYPED nam '/' con ',' imm
{
- Addr2 a;
- a.from = $2;
- a.to = $6;
- outcode(ADATA, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ outcode(obj.ADATA, &Addr2{$2, $6})
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
spec2: /* TEXT */
LTYPET mem ',' '$' textsize
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $5;
- outcode(ATEXT, &a);
+ asm.Settext($2.Sym);
+ outcode(obj.ATEXT, &Addr2{$2, $5})
}
| LTYPET mem ',' con ',' '$' textsize
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $7;
- outcode(ATEXT, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym);
+ outcode(obj.ATEXT, &Addr2{$2, $7})
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
spec8: /* GLOBL */
LTYPEG mem ',' imm
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $4;
- outcode(AGLOBL, &a);
+ asm.Settext($2.Sym);
+ outcode(obj.AGLOBL, &Addr2{$2, $4})
}
| LTYPEG mem ',' con ',' imm
{
- Addr2 a;
- settext($2.sym);
- a.from = $2;
- a.to = $6;
- outcode(AGLOBL, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym);
+ outcode(obj.AGLOBL, &Addr2{$2, $6})
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
+
spec3: /* JMP/CALL */
',' rom
{
@@ -251,7 +247,7 @@ spec3: /* JMP/CALL */
{
$$.from = nullgen;
$$.to = $2;
- $$.to.type = TYPE_INDIR;
+ $$.to.Type = obj.TYPE_INDIR
}
spec4: /* NOP */
@@ -268,9 +264,10 @@ spec5: /* SHL/SHR */
{
$$.from = $1;
$$.to = $3;
- if($$.from.index != TYPE_NONE)
+ if $$.from.Index != obj.TYPE_NONE {
yyerror("dp shift with lhs index");
- $$.from.index = $5;
+ }
+ $$.from.Index = int16($5);
}
spec6: /* MOVW/MOVL */
@@ -283,9 +280,10 @@ spec6: /* MOVW/MOVL */
{
$$.from = $1;
$$.to = $3;
- if($$.to.index != TYPE_NONE)
+ if $$.to.Index != obj.TYPE_NONE {
yyerror("dp move with lhs index");
- $$.to.index = $5;
+ }
+ $$.to.Index = int16($5);
}
spec7:
@@ -310,7 +308,7 @@ spec9: /* CMPPS/CMPPD */
{
$$.from = $1;
$$.to = $3;
- $$.to.offset = $5;
+ $$.to.Offset = $5;
}
spec10: /* PINSRD */
@@ -318,16 +316,18 @@ spec10: /* PINSRD */
{
$$.from = $3;
$$.to = $5;
- if($1.type != TYPE_CONST)
- yyerror("illegal constant");
- $$.to.offset = $1.offset;
+ if $1.Type != obj.TYPE_CONST {
+ yyerror("illegal constant")
+ }
+ $$.to.Offset = $1.Offset;
}
spec11: /* PCDATA */
rim ',' rim
{
- if($1.type != TYPE_CONST || $3.type != TYPE_CONST)
+ if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST {
yyerror("arguments to PCDATA must be integer constants");
+ }
$$.from = $1;
$$.to = $3;
}
@@ -335,10 +335,12 @@ spec11: /* PCDATA */
spec12: /* FUNCDATA */
rim ',' rim
{
- if($1.type != TYPE_CONST)
+ if $1.Type != obj.TYPE_CONST {
yyerror("index for FUNCDATA must be integer constant");
- if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC))
+ }
+ if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) {
yyerror("value for FUNCDATA must be symbol reference");
+ }
$$.from = $1;
$$.to = $3;
}
@@ -370,135 +372,137 @@ rel:
con '(' LPC ')'
{
$$ = nullgen;
- $$.type = TYPE_BRANCH;
- $$.offset = $1 + pc;
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1 + int64(asm.PC);
}
| LNAME offset
{
- $1 = labellookup($1);
+ $1 = asm.LabelLookup($1);
$$ = nullgen;
- if(pass == 2 && $1->type != LLAB)
- yyerror("undefined label: %s", $1->labelname);
- $$.type = TYPE_BRANCH;
- $$.offset = $1->value + $2;
+ if asm.Pass == 2 && $1.Type != LLAB {
+ yyerror("undefined label: %s", $1.Labelname);
+ }
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1.Value + $2;
}
reg:
LBREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LFREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LLREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LXREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
| LSP
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = REG_SP;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = REG_SP;
}
| LSREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1);
}
imm:
'$' con
{
$$ = nullgen;
- $$.type = TYPE_CONST;
- $$.offset = $2;
+ $$.Type = obj.TYPE_CONST;
+ $$.Offset = $2;
}
| '$' nam
{
$$ = $2;
- $$.type = TYPE_ADDR;
+ $$.Type = obj.TYPE_ADDR
/*
- if($2.name == NAME_AUTO || $2.name == NAME_PARAM)
+ if($2.Type == D_AUTO || $2.Type == D_PARAM)
yyerror("constant cannot be automatic: %s",
- $2.sym->name);
+ $2.Sym.name);
*/
}
| '$' LSCONST
{
$$ = nullgen;
- $$.type = TYPE_SCONST;
- memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ $$.Type = obj.TYPE_SCONST;
+ $$.U.Sval = $2
}
| '$' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $2;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $3;
}
| '$' '(' '-' LFCONST ')'
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$4;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$4;
}
| '$' '-' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$3;
}
textsize:
LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = $1;
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -$2;
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = $3;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = $1;
+ $$.U.Argsize = int32($3);
}
| '-' LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = $4;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -$2;
+ $$.U.Argsize = int32($4);
}
+
mem:
omem
| nmem
@@ -507,90 +511,87 @@ omem:
con
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_NONE;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Offset = $1;
}
| con '(' LLREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
}
| con '(' LSP ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_SP;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = REG_SP
+ $$.Offset = $1;
}
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_NONE;
- $$.offset = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Offset = $1;
+ $$.Index = int16($3);
+ $$.Scale = int8($5);
+ checkscale($$.Scale);
}
| con '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
+ $$.Index = int16($6);
+ $$.Scale = int8($8);
+ checkscale($$.Scale);
}
| con '(' LLREG ')' '(' LSREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
- $$.index = $6;
- $$.scale = $8;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
+ $$.Index = int16($6);
+ $$.Scale = int8($8);
+ checkscale($$.Scale);
}
| '(' LLREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($2);
}
| '(' LSP ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_SP;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = REG_SP
}
| con '(' LSREG ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($3)
+ $$.Offset = $1;
}
| '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = REG_NONE;
- $$.index = $2;
- $$.scale = $4;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Index = int16($2);
+ $$.Scale = int8($4);
+ checkscale($$.Scale);
}
| '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
- $$.index = $5;
- $$.scale = $7;
- checkscale($$.scale);
+ $$.Type = obj.TYPE_MEM
+ $$.Reg = int16($2)
+ $$.Index = int16($5);
+ $$.Scale = int8($7);
+ checkscale($$.Scale);
}
nmem:
@@ -601,27 +602,27 @@ nmem:
| nam '(' LLREG '*' con ')'
{
$$ = $1;
- $$.index = $3;
- $$.scale = $5;
- checkscale($$.scale);
+ $$.Index = int16($3);
+ $$.Scale = int8($5);
+ checkscale($$.Scale);
}
nam:
LNAME offset '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $4;
- $$.sym = linklookup(ctxt, $1->name, 0);
- $$.offset = $2;
+ $$.Type = obj.TYPE_MEM
+ $$.Name = int8($4);
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
+ $$.Offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = NAME_STATIC;
- $$.sym = linklookup(ctxt, $1->name, 1);
- $$.offset = $4;
+ $$.Type = obj.TYPE_MEM
+ $$.Name = obj.NAME_STATIC
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
+ $$.Offset = $4;
}
offset:
@@ -641,7 +642,7 @@ pointer:
LSB
| LSP
{
- $$ = NAME_AUTO;
+ $$ = obj.NAME_AUTO;
}
| LFP
@@ -649,7 +650,7 @@ con:
LCONST
| LVAR
{
- $$ = $1->value;
+ $$ = $1.Value;
}
| '-' con
{
@@ -661,7 +662,7 @@ con:
}
| '~' con
{
- $$ = ~$2;
+ $$ = ^$2;
}
| '(' expr ')'
{
@@ -692,11 +693,11 @@ expr:
}
| expr '<' '<' expr
{
- $$ = $1 << $4;
+ $$ = $1 << uint($4);
}
| expr '>' '>' expr
{
- $$ = $1 >> $4;
+ $$ = $1 >> uint($4);
}
| expr '&' expr
{
diff --git a/src/cmd/8a/doc.go b/src/cmd/8a/doc.go
deleted file mode 100644
index 84c7254c80..0000000000
--- a/src/cmd/8a/doc.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-8a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
- http://golang.org/doc/asm
-
-I
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package main
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
deleted file mode 100644
index 846f6c6daf..0000000000
--- a/src/cmd/8a/lex.c
+++ /dev/null
@@ -1,914 +0,0 @@
-// Inferno utils/8a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.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.
-
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
- return sys&Windows;
-#else
- return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
- if(nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
-}
-
-void
-usage(void)
-{
- print("usage: %ca [options] file.c...\n", thechar);
- flagprint(1);
- errorexit();
-}
-void
-main(int argc, char *argv[])
-{
- char *p;
-
- thechar = '8';
- thestring = "386";
-
- ctxt = linknew(&link386);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- ctxt->enforce_data_order = 1;
- Binit(&bstdout, 1, OWRITE);
- listinit8();
- fmtinstall('L', Lconv);
-
- // Allow GOARCH=thestring or GOARCH=thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
-
- flagfn1("D", "name[=value]: add #define", dodef);
- flagfn1("I", "dir: add dir to include path", setinclude);
- flagcount("S", "print assembly and machine code", &debug['S']);
- flagcount("m", "debug preprocessor macros", &debug['m']);
- flagstr("o", "file: set output file", &outfile);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
-
- if(argc < 1)
- usage();
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
-
- if(assemble(argv[0]))
- errorexit();
- Bflush(&bstdout);
- if(nerrors > 0)
- errorexit();
- exits(0);
-}
-
-int
-assemble(char *file)
-{
- char *ofile, *p;
- int i, of;
-
- ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
- strcpy(ofile, file);
- p = utfrrune(ofile, pathchar());
- if(p) {
- include[0] = ofile;
- *p++ = 0;
- } else
- p = ofile;
- if(outfile == 0) {
- outfile = p;
- if(outfile){
- p = utfrrune(outfile, '.');
- if(p)
- if(p[1] == 's' && p[2] == 0)
- p[0] = 0;
- p = utfrune(outfile, 0);
- p[0] = '.';
- p[1] = thechar;
- p[2] = 0;
- } else
- outfile = "/dev/null";
- }
-
- of = create(outfile, OWRITE, 0664);
- if(of < 0) {
- yyerror("%ca: cannot create %s", thechar, outfile);
- errorexit();
- }
- Binit(&obuf, of, OWRITE);
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- Bprint(&obuf, "!\n");
-
- for(pass = 1; pass <= 2; pass++) {
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- if(nerrors)
- return nerrors;
- }
-
- writeobj(ctxt, &obuf);
- Bflush(&obuf);
- return 0;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, NAME_AUTO,
- "SB", LSB, NAME_EXTERN,
- "FP", LFP, NAME_PARAM,
-
- "PC", LPC, TYPE_BRANCH,
-
- "AL", LBREG, REG_AL,
- "CL", LBREG, REG_CL,
- "DL", LBREG, REG_DL,
- "BL", LBREG, REG_BL,
- "AH", LBREG, REG_AH,
- "CH", LBREG, REG_CH,
- "DH", LBREG, REG_DH,
- "BH", LBREG, REG_BH,
-
- "AX", LLREG, REG_AX,
- "CX", LLREG, REG_CX,
- "DX", LLREG, REG_DX,
- "BX", LLREG, REG_BX,
-/* "SP", LLREG, REG_SP, */
- "BP", LLREG, REG_BP,
- "SI", LLREG, REG_SI,
- "DI", LLREG, REG_DI,
-
- "F0", LFREG, REG_F0+0,
- "F1", LFREG, REG_F0+1,
- "F2", LFREG, REG_F0+2,
- "F3", LFREG, REG_F0+3,
- "F4", LFREG, REG_F0+4,
- "F5", LFREG, REG_F0+5,
- "F6", LFREG, REG_F0+6,
- "F7", LFREG, REG_F0+7,
-
- "X0", LXREG, REG_X0+0,
- "X1", LXREG, REG_X0+1,
- "X2", LXREG, REG_X0+2,
- "X3", LXREG, REG_X0+3,
- "X4", LXREG, REG_X0+4,
- "X5", LXREG, REG_X0+5,
- "X6", LXREG, REG_X0+6,
- "X7", LXREG, REG_X0+7,
-
- "CS", LSREG, REG_CS,
- "SS", LSREG, REG_SS,
- "DS", LSREG, REG_DS,
- "ES", LSREG, REG_ES,
- "FS", LSREG, REG_FS,
- "GS", LSREG, REG_GS,
- "TLS", LSREG, REG_TLS,
-
- "GDTR", LBREG, REG_GDTR,
- "IDTR", LBREG, REG_IDTR,
- "LDTR", LBREG, REG_LDTR,
- "MSW", LBREG, REG_MSW,
- "TASK", LBREG, REG_TASK,
-
- "CR0", LBREG, REG_CR+0,
- "CR1", LBREG, REG_CR+1,
- "CR2", LBREG, REG_CR+2,
- "CR3", LBREG, REG_CR+3,
- "CR4", LBREG, REG_CR+4,
- "CR5", LBREG, REG_CR+5,
- "CR6", LBREG, REG_CR+6,
- "CR7", LBREG, REG_CR+7,
-
- "DR0", LBREG, REG_DR+0,
- "DR1", LBREG, REG_DR+1,
- "DR2", LBREG, REG_DR+2,
- "DR3", LBREG, REG_DR+3,
- "DR4", LBREG, REG_DR+4,
- "DR5", LBREG, REG_DR+5,
- "DR6", LBREG, REG_DR+6,
- "DR7", LBREG, REG_DR+7,
-
- "TR0", LBREG, REG_TR+0,
- "TR1", LBREG, REG_TR+1,
- "TR2", LBREG, REG_TR+2,
- "TR3", LBREG, REG_TR+3,
- "TR4", LBREG, REG_TR+4,
- "TR5", LBREG, REG_TR+5,
- "TR6", LBREG, REG_TR+6,
- "TR7", LBREG, REG_TR+7,
-
- "AAA", LTYPE0, AAAA,
- "AAD", LTYPE0, AAAD,
- "AAM", LTYPE0, AAAM,
- "AAS", LTYPE0, AAAS,
- "ADCB", LTYPE3, AADCB,
- "ADCL", LTYPE3, AADCL,
- "ADCW", LTYPE3, AADCW,
- "ADDB", LTYPE3, AADDB,
- "ADDL", LTYPE3, AADDL,
- "ADDW", LTYPE3, AADDW,
- "ADJSP", LTYPE2, AADJSP,
- "ANDB", LTYPE3, AANDB,
- "ANDL", LTYPE3, AANDL,
- "ANDW", LTYPE3, AANDW,
- "ARPL", LTYPE3, AARPL,
- "BOUNDL", LTYPE3, ABOUNDL,
- "BOUNDW", LTYPE3, ABOUNDW,
- "BSFL", LTYPE3, ABSFL,
- "BSFW", LTYPE3, ABSFW,
- "BSRL", LTYPE3, ABSRL,
- "BSRW", LTYPE3, ABSRW,
- "BSWAPL", LTYPE1, ABSWAPL,
- "BTCL", LTYPE3, ABTCL,
- "BTCW", LTYPE3, ABTCW,
- "BTL", LTYPE3, ABTL,
- "BTRL", LTYPE3, ABTRL,
- "BTRW", LTYPE3, ABTRW,
- "BTSL", LTYPE3, ABTSL,
- "BTSW", LTYPE3, ABTSW,
- "BTW", LTYPE3, ABTW,
- "BYTE", LTYPE2, ABYTE,
- "CALL", LTYPEC, ACALL,
- "CLC", LTYPE0, ACLC,
- "CLD", LTYPE0, ACLD,
- "CLI", LTYPE0, ACLI,
- "CLTS", LTYPE0, ACLTS,
- "CMC", LTYPE0, ACMC,
- "CMPB", LTYPE4, ACMPB,
- "CMPL", LTYPE4, ACMPL,
- "CMPW", LTYPE4, ACMPW,
- "CMPSB", LTYPE0, ACMPSB,
- "CMPSL", LTYPE0, ACMPSL,
- "CMPSW", LTYPE0, ACMPSW,
- "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
- "CMPXCHGB", LTYPE3, ACMPXCHGB,
- "CMPXCHGL", LTYPE3, ACMPXCHGL,
- "CMPXCHGW", LTYPE3, ACMPXCHGW,
- "CPUID", LTYPE0, ACPUID,
- "DAA", LTYPE0, ADAA,
- "DAS", LTYPE0, ADAS,
- "DATA", LTYPED, ADATA,
- "DECB", LTYPE1, ADECB,
- "DECL", LTYPE1, ADECL,
- "DECW", LTYPE1, ADECW,
- "DIVB", LTYPE2, ADIVB,
- "DIVL", LTYPE2, ADIVL,
- "DIVW", LTYPE2, ADIVW,
- "END", LTYPE0, AEND,
- "ENTER", LTYPE2, AENTER,
- "GLOBL", LTYPEG, AGLOBL,
- "HLT", LTYPE0, AHLT,
- "IDIVB", LTYPE2, AIDIVB,
- "IDIVL", LTYPE2, AIDIVL,
- "IDIVW", LTYPE2, AIDIVW,
- "IMULB", LTYPE2, AIMULB,
- "IMULL", LTYPEI, AIMULL,
- "IMULW", LTYPEI, AIMULW,
- "INB", LTYPE0, AINB,
- "INL", LTYPE0, AINL,
- "INW", LTYPE0, AINW,
- "INCB", LTYPE1, AINCB,
- "INCL", LTYPE1, AINCL,
- "INCW", LTYPE1, AINCW,
- "INSB", LTYPE0, AINSB,
- "INSL", LTYPE0, AINSL,
- "INSW", LTYPE0, AINSW,
- "INT", LTYPE2, AINT,
- "INTO", LTYPE0, AINTO,
- "IRETL", LTYPE0, AIRETL,
- "IRETW", LTYPE0, AIRETW,
-
- "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
- "JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
- "JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS, /* carry set (CF = 1) */
- "JB", LTYPER, AJCS, /* alternate */
- "JC", LTYPER, AJCS, /* alternate */
- "JNAE", LTYPER, AJCS, /* alternate */
- "JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
- "JAE", LTYPER, AJCC, /* alternate */
- "JNB", LTYPER, AJCC, /* alternate */
- "JNC", LTYPER, AJCC, /* alternate */
- "JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
- "JE", LTYPER, AJEQ, /* alternate */
- "JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
- "JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
- "JBE", LTYPER, AJLS, /* alternate */
- "JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
- "JA", LTYPER, AJHI, /* alternate */
- "JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
- "JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
- "JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS, /* parity set (PF = 1) */
- "JP", LTYPER, AJPS, /* alternate */
- "JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
- "JNP", LTYPER, AJPC, /* alternate */
- "JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
- "JL", LTYPER, AJLT, /* alternate */
- "JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
- "JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
- "JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
- "JG", LTYPER, AJGT, /* alternate */
- "JNLE", LTYPER, AJGT, /* alternate */
-
- "JCXZL", LTYPER, AJCXZL,
- "JCXZW", LTYPER, AJCXZW,
- "JMP", LTYPEC, AJMP,
- "LAHF", LTYPE0, ALAHF,
- "LARL", LTYPE3, ALARL,
- "LARW", LTYPE3, ALARW,
- "LEAL", LTYPE3, ALEAL,
- "LEAW", LTYPE3, ALEAW,
- "LEAVEL", LTYPE0, ALEAVEL,
- "LEAVEW", LTYPE0, ALEAVEW,
- "LOCK", LTYPE0, ALOCK,
- "LODSB", LTYPE0, ALODSB,
- "LODSL", LTYPE0, ALODSL,
- "LODSW", LTYPE0, ALODSW,
- "LONG", LTYPE2, ALONG,
- "LOOP", LTYPER, ALOOP,
- "LOOPEQ", LTYPER, ALOOPEQ,
- "LOOPNE", LTYPER, ALOOPNE,
- "LSLL", LTYPE3, ALSLL,
- "LSLW", LTYPE3, ALSLW,
- "MOVB", LTYPE3, AMOVB,
- "MOVL", LTYPEM, AMOVL,
- "MOVW", LTYPEM, AMOVW,
- "MOVQ", LTYPEM, AMOVQ,
- "MOVBLSX", LTYPE3, AMOVBLSX,
- "MOVBLZX", LTYPE3, AMOVBLZX,
- "MOVBWSX", LTYPE3, AMOVBWSX,
- "MOVBWZX", LTYPE3, AMOVBWZX,
- "MOVWLSX", LTYPE3, AMOVWLSX,
- "MOVWLZX", LTYPE3, AMOVWLZX,
- "MOVSB", LTYPE0, AMOVSB,
- "MOVSL", LTYPE0, AMOVSL,
- "MOVSW", LTYPE0, AMOVSW,
- "MULB", LTYPE2, AMULB,
- "MULL", LTYPE2, AMULL,
- "MULW", LTYPE2, AMULW,
- "NEGB", LTYPE1, ANEGB,
- "NEGL", LTYPE1, ANEGL,
- "NEGW", LTYPE1, ANEGW,
- "NOP", LTYPEN, ANOP,
- "NOTB", LTYPE1, ANOTB,
- "NOTL", LTYPE1, ANOTL,
- "NOTW", LTYPE1, ANOTW,
- "ORB", LTYPE3, AORB,
- "ORL", LTYPE3, AORL,
- "ORW", LTYPE3, AORW,
- "OUTB", LTYPE0, AOUTB,
- "OUTL", LTYPE0, AOUTL,
- "OUTW", LTYPE0, AOUTW,
- "OUTSB", LTYPE0, AOUTSB,
- "OUTSL", LTYPE0, AOUTSL,
- "OUTSW", LTYPE0, AOUTSW,
- "PAUSE", LTYPEN, APAUSE,
- "PINSRD", LTYPEX, APINSRD,
- "POPAL", LTYPE0, APOPAL,
- "POPAW", LTYPE0, APOPAW,
- "POPFL", LTYPE0, APOPFL,
- "POPFW", LTYPE0, APOPFW,
- "POPL", LTYPE1, APOPL,
- "POPW", LTYPE1, APOPW,
- "PUSHAL", LTYPE0, APUSHAL,
- "PUSHAW", LTYPE0, APUSHAW,
- "PUSHFL", LTYPE0, APUSHFL,
- "PUSHFW", LTYPE0, APUSHFW,
- "PUSHL", LTYPE2, APUSHL,
- "PUSHW", LTYPE2, APUSHW,
- "RCLB", LTYPE3, ARCLB,
- "RCLL", LTYPE3, ARCLL,
- "RCLW", LTYPE3, ARCLW,
- "RCRB", LTYPE3, ARCRB,
- "RCRL", LTYPE3, ARCRL,
- "RCRW", LTYPE3, ARCRW,
- "RDTSC", LTYPE0, ARDTSC,
- "REP", LTYPE0, AREP,
- "REPN", LTYPE0, AREPN,
- "RET", LTYPE0, ARET,
- "ROLB", LTYPE3, AROLB,
- "ROLL", LTYPE3, AROLL,
- "ROLW", LTYPE3, AROLW,
- "RORB", LTYPE3, ARORB,
- "RORL", LTYPE3, ARORL,
- "RORW", LTYPE3, ARORW,
- "SAHF", LTYPE0, ASAHF,
- "SALB", LTYPE3, ASALB,
- "SALL", LTYPE3, ASALL,
- "SALW", LTYPE3, ASALW,
- "SARB", LTYPE3, ASARB,
- "SARL", LTYPE3, ASARL,
- "SARW", LTYPE3, ASARW,
- "SBBB", LTYPE3, ASBBB,
- "SBBL", LTYPE3, ASBBL,
- "SBBW", LTYPE3, ASBBW,
- "SCASB", LTYPE0, ASCASB,
- "SCASL", LTYPE0, ASCASL,
- "SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
- "SETCS", LTYPE1, ASETCS,
- "SETEQ", LTYPE1, ASETEQ,
- "SETGE", LTYPE1, ASETGE,
- "SETGT", LTYPE1, ASETGT,
- "SETHI", LTYPE1, ASETHI,
- "SETLE", LTYPE1, ASETLE,
- "SETLS", LTYPE1, ASETLS,
- "SETLT", LTYPE1, ASETLT,
- "SETMI", LTYPE1, ASETMI,
- "SETNE", LTYPE1, ASETNE,
- "SETOC", LTYPE1, ASETOC,
- "SETOS", LTYPE1, ASETOS,
- "SETPC", LTYPE1, ASETPC,
- "SETPL", LTYPE1, ASETPL,
- "SETPS", LTYPE1, ASETPS,
- "CDQ", LTYPE0, ACDQ,
- "CWD", LTYPE0, ACWD,
- "SHLB", LTYPE3, ASHLB,
- "SHLL", LTYPES, ASHLL,
- "SHLW", LTYPES, ASHLW,
- "SHRB", LTYPE3, ASHRB,
- "SHRL", LTYPES, ASHRL,
- "SHRW", LTYPES, ASHRW,
- "STC", LTYPE0, ASTC,
- "STD", LTYPE0, ASTD,
- "STI", LTYPE0, ASTI,
- "STOSB", LTYPE0, ASTOSB,
- "STOSL", LTYPE0, ASTOSL,
- "STOSW", LTYPE0, ASTOSW,
- "SUBB", LTYPE3, ASUBB,
- "SUBL", LTYPE3, ASUBL,
- "SUBW", LTYPE3, ASUBW,
- "SYSCALL", LTYPE0, ASYSCALL,
- "TESTB", LTYPE3, ATESTB,
- "TESTL", LTYPE3, ATESTL,
- "TESTW", LTYPE3, ATESTW,
- "TEXT", LTYPET, ATEXT,
- "VERR", LTYPE2, AVERR,
- "VERW", LTYPE2, AVERW,
- "WAIT", LTYPE0, AWAIT,
- "WORD", LTYPE2, AWORD,
- "XADDB", LTYPE3, AXADDB,
- "XADDL", LTYPE3, AXADDL,
- "XADDW", LTYPE3, AXADDW,
- "XCHGB", LTYPE3, AXCHGB,
- "XCHGL", LTYPE3, AXCHGL,
- "XCHGW", LTYPE3, AXCHGW,
- "XLAT", LTYPE2, AXLAT,
- "XORB", LTYPE3, AXORB,
- "XORL", LTYPE3, AXORL,
- "XORW", LTYPE3, AXORW,
-
- "CMOVLCC", LTYPE3, ACMOVLCC,
- "CMOVLCS", LTYPE3, ACMOVLCS,
- "CMOVLEQ", LTYPE3, ACMOVLEQ,
- "CMOVLGE", LTYPE3, ACMOVLGE,
- "CMOVLGT", LTYPE3, ACMOVLGT,
- "CMOVLHI", LTYPE3, ACMOVLHI,
- "CMOVLLE", LTYPE3, ACMOVLLE,
- "CMOVLLS", LTYPE3, ACMOVLLS,
- "CMOVLLT", LTYPE3, ACMOVLLT,
- "CMOVLMI", LTYPE3, ACMOVLMI,
- "CMOVLNE", LTYPE3, ACMOVLNE,
- "CMOVLOC", LTYPE3, ACMOVLOC,
- "CMOVLOS", LTYPE3, ACMOVLOS,
- "CMOVLPC", LTYPE3, ACMOVLPC,
- "CMOVLPL", LTYPE3, ACMOVLPL,
- "CMOVLPS", LTYPE3, ACMOVLPS,
- "CMOVWCC", LTYPE3, ACMOVWCC,
- "CMOVWCS", LTYPE3, ACMOVWCS,
- "CMOVWEQ", LTYPE3, ACMOVWEQ,
- "CMOVWGE", LTYPE3, ACMOVWGE,
- "CMOVWGT", LTYPE3, ACMOVWGT,
- "CMOVWHI", LTYPE3, ACMOVWHI,
- "CMOVWLE", LTYPE3, ACMOVWLE,
- "CMOVWLS", LTYPE3, ACMOVWLS,
- "CMOVWLT", LTYPE3, ACMOVWLT,
- "CMOVWMI", LTYPE3, ACMOVWMI,
- "CMOVWNE", LTYPE3, ACMOVWNE,
- "CMOVWOC", LTYPE3, ACMOVWOC,
- "CMOVWOS", LTYPE3, ACMOVWOS,
- "CMOVWPC", LTYPE3, ACMOVWPC,
- "CMOVWPL", LTYPE3, ACMOVWPL,
- "CMOVWPS", LTYPE3, ACMOVWPS,
-
- "FMOVB", LTYPE3, AFMOVB,
- "FMOVBP", LTYPE3, AFMOVBP,
- "FMOVD", LTYPE3, AFMOVD,
- "FMOVDP", LTYPE3, AFMOVDP,
- "FMOVF", LTYPE3, AFMOVF,
- "FMOVFP", LTYPE3, AFMOVFP,
- "FMOVL", LTYPE3, AFMOVL,
- "FMOVLP", LTYPE3, AFMOVLP,
- "FMOVV", LTYPE3, AFMOVV,
- "FMOVVP", LTYPE3, AFMOVVP,
- "FMOVW", LTYPE3, AFMOVW,
- "FMOVWP", LTYPE3, AFMOVWP,
- "FMOVX", LTYPE3, AFMOVX,
- "FMOVXP", LTYPE3, AFMOVXP,
- "FCMOVCC", LTYPE3, AFCMOVCC,
- "FCMOVCS", LTYPE3, AFCMOVCS,
- "FCMOVEQ", LTYPE3, AFCMOVEQ,
- "FCMOVHI", LTYPE3, AFCMOVHI,
- "FCMOVLS", LTYPE3, AFCMOVLS,
- "FCMOVNE", LTYPE3, AFCMOVNE,
- "FCMOVNU", LTYPE3, AFCMOVNU,
- "FCMOVUN", LTYPE3, AFCMOVUN,
- "FCOMB", LTYPE3, AFCOMB,
- "FCOMBP", LTYPE3, AFCOMBP,
- "FCOMD", LTYPE3, AFCOMD,
- "FCOMDP", LTYPE3, AFCOMDP,
- "FCOMDPP", LTYPE3, AFCOMDPP,
- "FCOMF", LTYPE3, AFCOMF,
- "FCOMFP", LTYPE3, AFCOMFP,
- "FCOMI", LTYPE3, AFCOMI,
- "FCOMIP", LTYPE3, AFCOMIP,
- "FCOML", LTYPE3, AFCOML,
- "FCOMLP", LTYPE3, AFCOMLP,
- "FCOMW", LTYPE3, AFCOMW,
- "FCOMWP", LTYPE3, AFCOMWP,
- "FUCOM", LTYPE3, AFUCOM,
- "FUCOMI", LTYPE3, AFUCOMI,
- "FUCOMIP", LTYPE3, AFUCOMIP,
- "FUCOMP", LTYPE3, AFUCOMP,
- "FUCOMPP", LTYPE3, AFUCOMPP,
- "FADDW", LTYPE3, AFADDW,
- "FADDL", LTYPE3, AFADDL,
- "FADDF", LTYPE3, AFADDF,
- "FADDD", LTYPE3, AFADDD,
- "FADDDP", LTYPE3, AFADDDP,
- "FSUBDP", LTYPE3, AFSUBDP,
- "FSUBW", LTYPE3, AFSUBW,
- "FSUBL", LTYPE3, AFSUBL,
- "FSUBF", LTYPE3, AFSUBF,
- "FSUBD", LTYPE3, AFSUBD,
- "FSUBRDP", LTYPE3, AFSUBRDP,
- "FSUBRW", LTYPE3, AFSUBRW,
- "FSUBRL", LTYPE3, AFSUBRL,
- "FSUBRF", LTYPE3, AFSUBRF,
- "FSUBRD", LTYPE3, AFSUBRD,
- "FMULDP", LTYPE3, AFMULDP,
- "FMULW", LTYPE3, AFMULW,
- "FMULL", LTYPE3, AFMULL,
- "FMULF", LTYPE3, AFMULF,
- "FMULD", LTYPE3, AFMULD,
- "FDIVDP", LTYPE3, AFDIVDP,
- "FDIVW", LTYPE3, AFDIVW,
- "FDIVL", LTYPE3, AFDIVL,
- "FDIVF", LTYPE3, AFDIVF,
- "FDIVD", LTYPE3, AFDIVD,
- "FDIVRDP", LTYPE3, AFDIVRDP,
- "FDIVRW", LTYPE3, AFDIVRW,
- "FDIVRL", LTYPE3, AFDIVRL,
- "FDIVRF", LTYPE3, AFDIVRF,
- "FDIVRD", LTYPE3, AFDIVRD,
- "FXCHD", LTYPE3, AFXCHD,
- "FFREE", LTYPE1, AFFREE,
- "FLDCW", LTYPE2, AFLDCW,
- "FLDENV", LTYPE1, AFLDENV,
- "FRSTOR", LTYPE2, AFRSTOR,
- "FSAVE", LTYPE1, AFSAVE,
- "FSTCW", LTYPE1, AFSTCW,
- "FSTENV", LTYPE1, AFSTENV,
- "FSTSW", LTYPE1, AFSTSW,
- "F2XM1", LTYPE0, AF2XM1,
- "FABS", LTYPE0, AFABS,
- "FCHS", LTYPE0, AFCHS,
- "FCLEX", LTYPE0, AFCLEX,
- "FCOS", LTYPE0, AFCOS,
- "FDECSTP", LTYPE0, AFDECSTP,
- "FINCSTP", LTYPE0, AFINCSTP,
- "FINIT", LTYPE0, AFINIT,
- "FLD1", LTYPE0, AFLD1,
- "FLDL2E", LTYPE0, AFLDL2E,
- "FLDL2T", LTYPE0, AFLDL2T,
- "FLDLG2", LTYPE0, AFLDLG2,
- "FLDLN2", LTYPE0, AFLDLN2,
- "FLDPI", LTYPE0, AFLDPI,
- "FLDZ", LTYPE0, AFLDZ,
- "FNOP", LTYPE0, AFNOP,
- "FPATAN", LTYPE0, AFPATAN,
- "FPREM", LTYPE0, AFPREM,
- "FPREM1", LTYPE0, AFPREM1,
- "FPTAN", LTYPE0, AFPTAN,
- "FRNDINT", LTYPE0, AFRNDINT,
- "FSCALE", LTYPE0, AFSCALE,
- "FSIN", LTYPE0, AFSIN,
- "FSINCOS", LTYPE0, AFSINCOS,
- "FSQRT", LTYPE0, AFSQRT,
- "FTST", LTYPE0, AFTST,
- "FXAM", LTYPE0, AFXAM,
- "FXTRACT", LTYPE0, AFXTRACT,
- "FYL2X", LTYPE0, AFYL2X,
- "FYL2XP1", LTYPE0, AFYL2XP1,
- "LFENCE", LTYPE0, ALFENCE,
- "MFENCE", LTYPE0, AMFENCE,
- "SFENCE", LTYPE0, ASFENCE,
- "EMMS", LTYPE0, AEMMS,
- "PREFETCHT0", LTYPE2, APREFETCHT0,
- "PREFETCHT1", LTYPE2, APREFETCHT1,
- "PREFETCHT2", LTYPE2, APREFETCHT2,
- "PREFETCHNTA", LTYPE2, APREFETCHNTA,
- "UNDEF", LTYPE0, AUNDEF,
-
- "ADDPD", LTYPE3, AADDPD,
- "ADDPS", LTYPE3, AADDPS,
- "ADDSD", LTYPE3, AADDSD,
- "ADDSS", LTYPE3, AADDSS,
- "AESENC", LTYPE3, AAESENC,
- "ANDNPD", LTYPE3, AANDNPD,
- "ANDNPS", LTYPE3, AANDNPS,
- "ANDPD", LTYPE3, AANDPD,
- "ANDPS", LTYPE3, AANDPS,
- "CMPPD", LTYPEXC,ACMPPD,
- "CMPPS", LTYPEXC,ACMPPS,
- "CMPSD", LTYPEXC,ACMPSD,
- "CMPSS", LTYPEXC,ACMPSS,
- "COMISD", LTYPE3, ACOMISD,
- "COMISS", LTYPE3, ACOMISS,
- "CVTPL2PD", LTYPE3, ACVTPL2PD,
- "CVTPL2PS", LTYPE3, ACVTPL2PS,
- "CVTPD2PL", LTYPE3, ACVTPD2PL,
- "CVTPD2PS", LTYPE3, ACVTPD2PS,
- "CVTPS2PL", LTYPE3, ACVTPS2PL,
- "CVTPS2PD", LTYPE3, ACVTPS2PD,
- "CVTSD2SL", LTYPE3, ACVTSD2SL,
- "CVTSD2SS", LTYPE3, ACVTSD2SS,
- "CVTSL2SD", LTYPE3, ACVTSL2SD,
- "CVTSL2SS", LTYPE3, ACVTSL2SS,
- "CVTSS2SD", LTYPE3, ACVTSS2SD,
- "CVTSS2SL", LTYPE3, ACVTSS2SL,
- "CVTTPD2PL", LTYPE3, ACVTTPD2PL,
- "CVTTPS2PL", LTYPE3, ACVTTPS2PL,
- "CVTTSD2SL", LTYPE3, ACVTTSD2SL,
- "CVTTSS2SL", LTYPE3, ACVTTSS2SL,
- "DIVPD", LTYPE3, ADIVPD,
- "DIVPS", LTYPE3, ADIVPS,
- "DIVSD", LTYPE3, ADIVSD,
- "DIVSS", LTYPE3, ADIVSS,
- "MASKMOVOU", LTYPE3, AMASKMOVOU,
- "MASKMOVDQU", LTYPE3, AMASKMOVOU, /* syn */
- "MAXPD", LTYPE3, AMAXPD,
- "MAXPS", LTYPE3, AMAXPS,
- "MAXSD", LTYPE3, AMAXSD,
- "MAXSS", LTYPE3, AMAXSS,
- "MINPD", LTYPE3, AMINPD,
- "MINPS", LTYPE3, AMINPS,
- "MINSD", LTYPE3, AMINSD,
- "MINSS", LTYPE3, AMINSS,
- "MOVAPD", LTYPE3, AMOVAPD,
- "MOVAPS", LTYPE3, AMOVAPS,
- "MOVO", LTYPE3, AMOVO,
- "MOVOA", LTYPE3, AMOVO, /* syn */
- "MOVOU", LTYPE3, AMOVOU,
- "MOVHLPS", LTYPE3, AMOVHLPS,
- "MOVHPD", LTYPE3, AMOVHPD,
- "MOVHPS", LTYPE3, AMOVHPS,
- "MOVLHPS", LTYPE3, AMOVLHPS,
- "MOVLPD", LTYPE3, AMOVLPD,
- "MOVLPS", LTYPE3, AMOVLPS,
- "MOVMSKPD", LTYPE3, AMOVMSKPD,
- "MOVMSKPS", LTYPE3, AMOVMSKPS,
- "MOVNTO", LTYPE3, AMOVNTO,
- "MOVNTDQ", LTYPE3, AMOVNTO, /* syn */
- "MOVNTPD", LTYPE3, AMOVNTPD,
- "MOVNTPS", LTYPE3, AMOVNTPS,
- "MOVSD", LTYPE3, AMOVSD,
- "MOVSS", LTYPE3, AMOVSS,
- "MOVUPD", LTYPE3, AMOVUPD,
- "MOVUPS", LTYPE3, AMOVUPS,
- "MULPD", LTYPE3, AMULPD,
- "MULPS", LTYPE3, AMULPS,
- "MULSD", LTYPE3, AMULSD,
- "MULSS", LTYPE3, AMULSS,
- "ORPD", LTYPE3, AORPD,
- "ORPS", LTYPE3, AORPS,
- "PADDQ", LTYPE3, APADDQ,
- "PAND", LTYPE3, APAND,
- "PCMPEQB", LTYPE3, APCMPEQB,
- "PMAXSW", LTYPE3, APMAXSW,
- "PMAXUB", LTYPE3, APMAXUB,
- "PMINSW", LTYPE3, APMINSW,
- "PMINUB", LTYPE3, APMINUB,
- "PMOVMSKB", LTYPE3, APMOVMSKB,
- "PSADBW", LTYPE3, APSADBW,
- "PSHUFB", LTYPE3, APSHUFB,
- "PSHUFHW", LTYPEX, APSHUFHW,
- "PSHUFL", LTYPEX, APSHUFL,
- "PSHUFLW", LTYPEX, APSHUFLW,
- "PSUBB", LTYPE3, APSUBB,
- "PSUBL", LTYPE3, APSUBL,
- "PSUBQ", LTYPE3, APSUBQ,
- "PSUBSB", LTYPE3, APSUBSB,
- "PSUBSW", LTYPE3, APSUBSW,
- "PSUBUSB", LTYPE3, APSUBUSB,
- "PSUBUSW", LTYPE3, APSUBUSW,
- "PSUBW", LTYPE3, APSUBW,
- "PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
- "PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
- "PXOR", LTYPE3, APXOR,
- "RCPPS", LTYPE3, ARCPPS,
- "RCPSS", LTYPE3, ARCPSS,
- "RSQRTPS", LTYPE3, ARSQRTPS,
- "RSQRTSS", LTYPE3, ARSQRTSS,
- "SQRTPD", LTYPE3, ASQRTPD,
- "SQRTPS", LTYPE3, ASQRTPS,
- "SQRTSD", LTYPE3, ASQRTSD,
- "SQRTSS", LTYPE3, ASQRTSS,
- "SUBPD", LTYPE3, ASUBPD,
- "SUBPS", LTYPE3, ASUBPS,
- "SUBSD", LTYPE3, ASUBSD,
- "SUBSS", LTYPE3, ASUBSS,
- "UCOMISD", LTYPE3, AUCOMISD,
- "UCOMISS", LTYPE3, AUCOMISS,
- "UNPCKHPD", LTYPE3, AUNPCKHPD,
- "UNPCKHPS", LTYPE3, AUNPCKHPS,
- "UNPCKLPD", LTYPE3, AUNPCKLPD,
- "UNPCKLPS", LTYPE3, AUNPCKLPS,
- "XORPD", LTYPE3, AXORPD,
- "XORPS", LTYPE3, AXORPS,
- "USEFIELD", LTYPEN, AUSEFIELD,
- "PCDATA", LTYPEPC, APCDATA,
- "FUNCDATA", LTYPEF, AFUNCDATA,
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.type = TYPE_NONE;
- nullgen.index = TYPE_NONE;
-
- nerrors = 0;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- if(s->type != LNAME)
- yyerror("double initialization %s", itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-}
-
-void
-checkscale(int scale)
-{
-
- switch(scale) {
- case 1:
- case 2:
- case 4:
- case 8:
- return;
- }
- yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-void
-cclean(void)
-{
- Addr2 g2;
-
- g2.from = nullgen;
- g2.to = nullgen;
- outcode(AEND, &g2);
-}
-
-void
-outcode(int a, Addr2 *g2)
-{
- Prog *p;
- Plist *pl;
-
- if(pass == 1)
- goto out;
-
- p = malloc(sizeof *p);
- memset(p, 0, sizeof *p);
- p->as = a;
- p->lineno = stmtline;
- p->from = g2->from;
- p->to = g2->to;
- p->pc = pc;
-
- if(lastpc == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastpc->link = p;
- lastpc = p;
-
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/new8a/lex.go b/src/cmd/8a/lex.go
index bbd8610ec4..bbd8610ec4 100644
--- a/src/cmd/new8a/lex.go
+++ b/src/cmd/8a/lex.go
diff --git a/src/cmd/new8a/y.go b/src/cmd/8a/y.go
index 82c8a5fb2e..82c8a5fb2e 100644
--- a/src/cmd/new8a/y.go
+++ b/src/cmd/8a/y.go
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
deleted file mode 100644
index d80f0ee4de..0000000000
--- a/src/cmd/8a/y.tab.c
+++ /dev/null
@@ -1,2778 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE0 = 258,
- LTYPE1 = 259,
- LTYPE2 = 260,
- LTYPE3 = 261,
- LTYPE4 = 262,
- LTYPEC = 263,
- LTYPED = 264,
- LTYPEN = 265,
- LTYPER = 266,
- LTYPET = 267,
- LTYPES = 268,
- LTYPEM = 269,
- LTYPEI = 270,
- LTYPEG = 271,
- LTYPEXC = 272,
- LTYPEX = 273,
- LTYPEPC = 274,
- LTYPEF = 275,
- LCONST = 276,
- LFP = 277,
- LPC = 278,
- LSB = 279,
- LBREG = 280,
- LLREG = 281,
- LSREG = 282,
- LFREG = 283,
- LXREG = 284,
- LFCONST = 285,
- LSCONST = 286,
- LSP = 287,
- LNAME = 288,
- LLAB = 289,
- LVAR = 290
- };
-#endif
-/* Tokens. */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPES 268
-#define LTYPEM 269
-#define LTYPEI 270
-#define LTYPEG 271
-#define LTYPEXC 272
-#define LTYPEX 273
-#define LTYPEPC 274
-#define LTYPEF 275
-#define LCONST 276
-#define LFP 277
-#define LPC 278
-#define LSB 279
-#define LBREG 280
-#define LLREG 281
-#define LSREG 282
-#define LFREG 283
-#define LXREG 284
-#define LFCONST 285
-#define LSCONST 286
-#define LSP 287
-#define LNAME 288
-#define LLAB 289
-#define LVAR 290
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
-}
-/* Line 193 of yacc.c. */
-#line 183 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 196 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 544
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 54
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 39
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 131
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 270
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 290
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 50, 12, 5, 2,
- 51, 52, 10, 8, 49, 9, 2, 11, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 46, 47,
- 6, 48, 7, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 2, 53, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 5, 9, 10, 15, 17, 20,
- 23, 27, 31, 34, 37, 40, 43, 46, 49, 51,
- 53, 56, 59, 62, 65, 68, 70, 73, 76, 79,
- 82, 83, 85, 89, 93, 96, 98, 101, 103, 106,
- 108, 112, 119, 125, 133, 138, 145, 148, 150, 153,
- 155, 157, 161, 167, 171, 177, 180, 182, 186, 192,
- 198, 202, 206, 208, 210, 212, 214, 217, 220, 222,
- 224, 226, 228, 230, 235, 238, 240, 242, 244, 246,
- 248, 250, 253, 256, 259, 262, 267, 273, 277, 279,
- 282, 286, 291, 293, 295, 297, 302, 307, 314, 324,
- 334, 338, 342, 347, 353, 362, 364, 371, 377, 385,
- 386, 389, 392, 394, 396, 398, 400, 402, 405, 408,
- 411, 415, 417, 421, 425, 429, 433, 437, 442, 447,
- 451, 455
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 55, 0, -1, -1, -1, 55, 56, 57, -1, -1,
- 43, 46, 58, 57, -1, 47, -1, 59, 47, -1,
- 1, 47, -1, 43, 48, 92, -1, 45, 48, 92,
- -1, 13, 60, -1, 14, 64, -1, 15, 63, -1,
- 16, 61, -1, 17, 62, -1, 21, 65, -1, 66,
- -1, 67, -1, 18, 69, -1, 20, 70, -1, 23,
- 71, -1, 24, 72, -1, 25, 73, -1, 68, -1,
- 27, 74, -1, 28, 75, -1, 29, 76, -1, 30,
- 77, -1, -1, 49, -1, 80, 49, 78, -1, 78,
- 49, 80, -1, 80, 49, -1, 80, -1, 49, 78,
- -1, 78, -1, 49, 81, -1, 81, -1, 83, 49,
- 81, -1, 19, 88, 11, 91, 49, 83, -1, 22,
- 85, 49, 50, 84, -1, 22, 85, 49, 91, 49,
- 50, 84, -1, 26, 85, 49, 83, -1, 26, 85,
- 49, 91, 49, 83, -1, 49, 79, -1, 79, -1,
- 10, 88, -1, 60, -1, 64, -1, 80, 49, 78,
- -1, 80, 49, 78, 46, 36, -1, 80, 49, 78,
- -1, 80, 49, 78, 46, 37, -1, 80, 49, -1,
- 80, -1, 80, 49, 78, -1, 82, 49, 78, 49,
- 91, -1, 83, 49, 78, 49, 82, -1, 80, 49,
- 80, -1, 80, 49, 80, -1, 82, -1, 85, -1,
- 81, -1, 87, -1, 10, 82, -1, 10, 86, -1,
- 82, -1, 86, -1, 83, -1, 78, -1, 83, -1,
- 91, 51, 33, 52, -1, 43, 89, -1, 35, -1,
- 38, -1, 36, -1, 39, -1, 42, -1, 37, -1,
- 50, 91, -1, 50, 88, -1, 50, 41, -1, 50,
- 40, -1, 50, 51, 40, 52, -1, 50, 51, 9,
- 40, 52, -1, 50, 9, 40, -1, 31, -1, 9,
- 31, -1, 31, 9, 31, -1, 9, 31, 9, 31,
- -1, 86, -1, 87, -1, 91, -1, 91, 51, 36,
- 52, -1, 91, 51, 42, 52, -1, 91, 51, 36,
- 10, 91, 52, -1, 91, 51, 36, 52, 51, 36,
- 10, 91, 52, -1, 91, 51, 36, 52, 51, 37,
- 10, 91, 52, -1, 51, 36, 52, -1, 51, 42,
- 52, -1, 91, 51, 37, 52, -1, 51, 36, 10,
- 91, 52, -1, 51, 36, 52, 51, 36, 10, 91,
- 52, -1, 88, -1, 88, 51, 36, 10, 91, 52,
- -1, 43, 89, 51, 90, 52, -1, 43, 6, 7,
- 89, 51, 34, 52, -1, -1, 8, 91, -1, 9,
- 91, -1, 34, -1, 42, -1, 32, -1, 31, -1,
- 45, -1, 9, 91, -1, 8, 91, -1, 53, 91,
- -1, 51, 92, 52, -1, 91, -1, 92, 8, 92,
- -1, 92, 9, 92, -1, 92, 10, 92, -1, 92,
- 11, 92, -1, 92, 12, 92, -1, 92, 6, 6,
- 92, -1, 92, 7, 7, 92, -1, 92, 5, 92,
- -1, 92, 4, 92, -1, 92, 3, 92, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 64, 64, 66, 65, 73, 72, 81, 82, 83,
- 86, 91, 97, 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
- 117, 121, 128, 135, 142, 147, 154, 159, 166, 171,
- 176, 183, 196, 204, 218, 226, 240, 245, 250, 258,
- 259, 262, 267, 277, 282, 292, 297, 302, 309, 317,
- 327, 336, 347, 348, 351, 352, 353, 357, 361, 362,
- 363, 366, 367, 370, 376, 387, 393, 399, 405, 411,
- 417, 425, 431, 441, 447, 453, 459, 465, 473, 480,
- 487, 494, 503, 504, 507, 514, 521, 528, 538, 548,
- 558, 564, 570, 577, 586, 597, 601, 610, 618, 628,
- 631, 635, 641, 642, 646, 649, 650, 654, 658, 662,
- 666, 672, 673, 677, 681, 685, 689, 693, 697, 701,
- 705, 709
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
- "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
- "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES",
- "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF",
- "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG",
- "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
- "';'", "'='", "','", "'$'", "'('", "')'", "'~'", "$accept", "prog", "@1",
- "line", "@2", "inst", "nonnon", "rimrem", "remrim", "rimnon", "nonrem",
- "nonrel", "spec1", "spec2", "spec8", "spec3", "spec4", "spec5", "spec6",
- "spec7", "spec9", "spec10", "spec11", "spec12", "rem", "rom", "rim",
- "rel", "reg", "imm", "textsize", "mem", "omem", "nmem", "nam", "offset",
- "pointer", "con", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
- 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 58, 59, 61, 44,
- 36, 40, 41, 126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 54, 55, 56, 55, 58, 57, 57, 57, 57,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 60, 60, 61, 62, 63, 63, 64, 64, 65, 65,
- 65, 66, 67, 67, 68, 68, 69, 69, 69, 70,
- 70, 71, 71, 72, 72, 73, 73, 73, 74, 75,
- 76, 77, 78, 78, 79, 79, 79, 79, 79, 79,
- 79, 80, 80, 81, 81, 82, 82, 82, 82, 82,
- 82, 83, 83, 83, 83, 83, 83, 83, 84, 84,
- 84, 84, 85, 85, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 87, 87, 88, 88, 89,
- 89, 89, 90, 90, 90, 91, 91, 91, 91, 91,
- 91, 92, 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 92
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 0, 3, 0, 4, 1, 2, 2,
- 3, 3, 2, 2, 2, 2, 2, 2, 1, 1,
- 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
- 0, 1, 3, 3, 2, 1, 2, 1, 2, 1,
- 3, 6, 5, 7, 4, 6, 2, 1, 2, 1,
- 1, 3, 5, 3, 5, 2, 1, 3, 5, 5,
- 3, 3, 1, 1, 1, 1, 2, 2, 1, 1,
- 1, 1, 1, 4, 2, 1, 1, 1, 1, 1,
- 1, 2, 2, 2, 2, 4, 5, 3, 1, 2,
- 3, 4, 1, 1, 1, 4, 4, 6, 9, 9,
- 3, 3, 4, 5, 8, 1, 6, 5, 7, 0,
- 2, 2, 1, 1, 1, 1, 1, 2, 2, 2,
- 3, 1, 3, 3, 3, 3, 3, 4, 4, 3,
- 3, 3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 3, 1, 0, 0, 30, 0, 0, 0, 0,
- 0, 0, 30, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 7, 4, 0, 18, 19,
- 25, 9, 31, 12, 0, 0, 115, 75, 77, 80,
- 76, 78, 79, 109, 116, 0, 0, 0, 13, 37,
- 62, 63, 92, 93, 105, 94, 0, 14, 71, 35,
- 72, 15, 0, 16, 0, 0, 109, 0, 20, 47,
- 64, 68, 70, 69, 65, 94, 0, 31, 49, 50,
- 21, 109, 0, 0, 17, 39, 0, 0, 0, 22,
- 0, 23, 0, 24, 56, 0, 26, 0, 27, 0,
- 28, 0, 29, 0, 5, 0, 0, 8, 118, 117,
- 0, 0, 0, 0, 36, 0, 0, 121, 0, 119,
- 0, 0, 0, 84, 83, 0, 82, 81, 34, 0,
- 0, 66, 67, 48, 74, 0, 46, 0, 0, 74,
- 38, 0, 0, 0, 0, 0, 55, 0, 0, 0,
- 0, 0, 0, 10, 11, 109, 110, 111, 0, 0,
- 100, 101, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 120, 0, 0, 0, 0, 87, 0, 0,
- 32, 33, 0, 0, 40, 0, 0, 51, 53, 57,
- 44, 0, 0, 0, 60, 61, 6, 0, 114, 112,
- 113, 0, 0, 0, 131, 130, 129, 0, 0, 122,
- 123, 124, 125, 126, 0, 0, 95, 102, 96, 0,
- 85, 73, 0, 0, 88, 42, 0, 0, 0, 0,
- 0, 0, 0, 107, 103, 0, 127, 128, 0, 0,
- 0, 86, 41, 89, 0, 0, 52, 54, 45, 58,
- 59, 0, 0, 106, 97, 0, 0, 0, 90, 43,
- 108, 0, 0, 0, 91, 104, 0, 0, 98, 99
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 3, 26, 152, 27, 33, 61, 63, 57,
- 48, 84, 28, 29, 30, 68, 80, 89, 91, 93,
- 96, 98, 100, 102, 58, 69, 59, 70, 50, 60,
- 225, 51, 52, 53, 54, 113, 201, 55, 118
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -87
-static const yytype_int16 yypact[] =
-{
- -87, 35, -87, 242, 2, -4, 164, 313, 313, 361,
- 265, 8, 337, 60, 410, 313, 313, 313, 410, 241,
- -11, 313, 313, -31, 17, -87, -87, 23, -87, -87,
- -87, -87, -87, -87, 474, 474, -87, -87, -87, -87,
- -87, -87, -87, 20, -87, 361, 401, 474, -87, -87,
- -87, -87, -87, -87, 16, 28, 185, -87, -87, 22,
- -87, -87, 25, -87, 31, 361, 20, 289, -87, -87,
- -87, -87, -87, -87, -87, 48, 29, 361, -87, -87,
- -87, 13, 417, 474, -87, -87, 51, 53, 57, -87,
- 58, -87, 59, -87, 70, 71, -87, 75, -87, 80,
- -87, 86, -87, 102, -87, 474, 474, -87, -87, -87,
- 37, 474, 474, 76, -87, 1, 103, -87, 175, -87,
- 126, 50, 85, -87, -87, 426, -87, -87, -87, 361,
- 313, -87, -87, -87, 76, 385, -87, 81, 474, -87,
- -87, 417, 130, 436, 361, 361, 361, 464, 361, 361,
- 313, 313, 242, 525, 525, 13, -87, -87, 18, 474,
- 113, -87, 474, 474, 474, 165, 167, 474, 474, 474,
- 474, 474, -87, 186, 3, 123, 156, -87, 467, 158,
- -87, -87, 159, 163, -87, 7, 169, 173, 177, -87,
- -87, 182, 183, 184, -87, -87, -87, 178, -87, -87,
- -87, 172, 187, 198, 136, 239, 532, 474, 474, 78,
- 78, -87, -87, -87, 474, 474, 189, -87, -87, 202,
- -87, -87, -11, 204, 228, -87, 191, 245, 247, -11,
- 474, 241, 248, -87, -87, 276, 180, 180, 236, 238,
- -5, -87, -87, 282, 261, 7, -87, -87, -87, -87,
- -87, 243, 474, -87, -87, 283, 284, 274, -87, -87,
- -87, 254, 474, 474, -87, -87, 257, 259, -87, -87
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -87, -87, -87, 160, -87, -87, 301, -87, -87, -87,
- 305, -87, -87, -87, -87, -87, -87, -87, -87, -87,
- -87, -87, -87, -87, 21, 252, 26, -7, -9, -8,
- 84, 0, -3, -6, -2, -58, -87, -10, -86
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -1
-static const yytype_uint16 yytable[] =
-{
- 75, 71, 72, 87, 74, 86, 85, 73, 134, 76,
- 97, 159, 99, 215, 88, 104, 223, 105, 95, 153,
- 154, 111, 112, 139, 108, 109, 110, 49, 111, 112,
- 64, 255, 256, 49, 62, 2, 117, 119, 224, 56,
- 138, 90, 92, 94, 155, 32, 127, 101, 103, 31,
- 198, 43, 199, 160, 126, 216, 131, 75, 71, 72,
- 200, 74, 132, 133, 73, 106, 114, 120, 34, 35,
- 107, 128, 87, 117, 129, 140, 204, 205, 206, 121,
- 130, 209, 210, 211, 212, 213, 174, 175, 169, 170,
- 171, 36, 176, 34, 35, 117, 117, 197, 114, 137,
- 141, 156, 157, 81, 142, 44, 143, 144, 145, 82,
- 56, 83, 109, 47, 182, 117, 36, 174, 175, 146,
- 147, 236, 237, 176, 148, 177, 131, 158, 183, 149,
- 44, 87, 132, 186, 184, 150, 83, 191, 47, 190,
- 163, 164, 165, 166, 167, 168, 169, 170, 171, 202,
- 180, 151, 117, 117, 117, 161, 181, 117, 117, 117,
- 117, 117, 173, 182, 203, 187, 188, 189, 109, 192,
- 193, 207, 34, 35, 208, 217, 194, 195, 162, 163,
- 164, 165, 166, 167, 168, 169, 170, 171, 167, 168,
- 169, 170, 171, 34, 122, 36, 214, 117, 117, 37,
- 38, 39, 40, 41, 238, 239, 42, 43, 218, 44,
- 220, 221, 222, 45, 242, 46, 36, 47, 226, 227,
- 249, 248, 250, 228, 233, 123, 124, 172, 43, 232,
- 44, 229, 230, 231, 235, 243, 125, 244, 47, 234,
- 240, 245, 261, 4, 164, 165, 166, 167, 168, 169,
- 170, 171, 266, 267, 241, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 34, 35, 65, 37, 38, 39, 40,
- 41, 246, 251, 42, 247, 23, 252, 24, 253, 25,
- 254, 257, 258, 262, 263, 260, 36, 34, 35, 135,
- 37, 38, 39, 40, 41, 264, 265, 42, 66, 268,
- 44, 269, 196, 78, 67, 56, 46, 79, 47, 136,
- 36, 34, 35, 0, 37, 38, 39, 40, 41, 259,
- 0, 42, 66, 0, 44, 0, 0, 0, 0, 56,
- 46, 0, 47, 0, 36, 34, 35, 0, 37, 38,
- 39, 40, 41, 0, 0, 42, 43, 0, 44, 0,
- 0, 0, 0, 56, 46, 0, 47, 0, 36, 34,
- 35, 0, 37, 38, 39, 40, 41, 0, 0, 42,
- 43, 0, 44, 0, 0, 0, 77, 0, 46, 0,
- 47, 0, 36, 34, 35, 0, 37, 38, 39, 40,
- 41, 0, 0, 42, 43, 0, 44, 0, 0, 34,
- 35, 0, 46, 0, 47, 0, 36, 0, 34, 35,
- 37, 38, 39, 40, 41, 34, 35, 42, 0, 0,
- 44, 0, 36, 0, 34, 178, 46, 115, 47, 0,
- 0, 36, 0, 116, 34, 35, 44, 0, 36, 0,
- 0, 0, 83, 43, 47, 44, 0, 36, 0, 0,
- 81, 46, 44, 47, 0, 0, 179, 36, 83, 0,
- 47, 44, 34, 35, 0, 34, 35, 83, 0, 47,
- 0, 44, 34, 35, 0, 0, 185, 83, 0, 47,
- 0, 0, 0, 0, 0, 36, 0, 0, 36, 0,
- 0, 0, 0, 0, 0, 36, 0, 219, 0, 44,
- 0, 0, 44, 0, 56, 83, 0, 47, 83, 44,
- 47, 0, 0, 0, 0, 83, 0, 47, 162, 163,
- 164, 165, 166, 167, 168, 169, 170, 171, 165, 166,
- 167, 168, 169, 170, 171
-};
-
-static const yytype_int16 yycheck[] =
-{
- 10, 10, 10, 13, 10, 13, 13, 10, 66, 11,
- 19, 10, 20, 10, 14, 46, 9, 48, 18, 105,
- 106, 8, 9, 81, 34, 35, 6, 6, 8, 9,
- 9, 36, 37, 12, 8, 0, 46, 47, 31, 50,
- 11, 15, 16, 17, 7, 49, 56, 21, 22, 47,
- 32, 43, 34, 52, 56, 52, 65, 67, 67, 67,
- 42, 67, 65, 65, 67, 48, 45, 51, 8, 9,
- 47, 49, 82, 83, 49, 82, 162, 163, 164, 51,
- 49, 167, 168, 169, 170, 171, 36, 37, 10, 11,
- 12, 31, 42, 8, 9, 105, 106, 155, 77, 51,
- 49, 111, 112, 43, 51, 45, 49, 49, 49, 49,
- 50, 51, 122, 53, 33, 125, 31, 36, 37, 49,
- 49, 207, 208, 42, 49, 40, 135, 51, 138, 49,
- 45, 141, 135, 143, 141, 49, 51, 147, 53, 147,
- 4, 5, 6, 7, 8, 9, 10, 11, 12, 159,
- 129, 49, 162, 163, 164, 52, 130, 167, 168, 169,
- 170, 171, 36, 33, 51, 144, 145, 146, 178, 148,
- 149, 6, 8, 9, 7, 52, 150, 151, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 8, 9,
- 10, 11, 12, 8, 9, 31, 10, 207, 208, 35,
- 36, 37, 38, 39, 214, 215, 42, 43, 52, 45,
- 52, 52, 49, 49, 222, 51, 31, 53, 49, 46,
- 230, 229, 231, 46, 52, 40, 41, 52, 43, 51,
- 45, 49, 49, 49, 36, 31, 51, 9, 53, 52,
- 51, 50, 252, 1, 5, 6, 7, 8, 9, 10,
- 11, 12, 262, 263, 52, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 8, 9, 10, 35, 36, 37, 38,
- 39, 36, 34, 42, 37, 43, 10, 45, 52, 47,
- 52, 9, 31, 10, 10, 52, 31, 8, 9, 10,
- 35, 36, 37, 38, 39, 31, 52, 42, 43, 52,
- 45, 52, 152, 12, 49, 50, 51, 12, 53, 67,
- 31, 8, 9, -1, 35, 36, 37, 38, 39, 245,
- -1, 42, 43, -1, 45, -1, -1, -1, -1, 50,
- 51, -1, 53, -1, 31, 8, 9, -1, 35, 36,
- 37, 38, 39, -1, -1, 42, 43, -1, 45, -1,
- -1, -1, -1, 50, 51, -1, 53, -1, 31, 8,
- 9, -1, 35, 36, 37, 38, 39, -1, -1, 42,
- 43, -1, 45, -1, -1, -1, 49, -1, 51, -1,
- 53, -1, 31, 8, 9, -1, 35, 36, 37, 38,
- 39, -1, -1, 42, 43, -1, 45, -1, -1, 8,
- 9, -1, 51, -1, 53, -1, 31, -1, 8, 9,
- 35, 36, 37, 38, 39, 8, 9, 42, -1, -1,
- 45, -1, 31, -1, 8, 9, 51, 36, 53, -1,
- -1, 31, -1, 42, 8, 9, 45, -1, 31, -1,
- -1, -1, 51, 43, 53, 45, -1, 31, -1, -1,
- 43, 51, 45, 53, -1, -1, 40, 31, 51, -1,
- 53, 45, 8, 9, -1, 8, 9, 51, -1, 53,
- -1, 45, 8, 9, -1, -1, 50, 51, -1, 53,
- -1, -1, -1, -1, -1, 31, -1, -1, 31, -1,
- -1, -1, -1, -1, -1, 31, -1, 40, -1, 45,
- -1, -1, 45, -1, 50, 51, -1, 53, 51, 45,
- 53, -1, -1, -1, -1, 51, -1, 53, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 6, 7,
- 8, 9, 10, 11, 12
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 55, 0, 56, 1, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 43, 45, 47, 57, 59, 66, 67,
- 68, 47, 49, 60, 8, 9, 31, 35, 36, 37,
- 38, 39, 42, 43, 45, 49, 51, 53, 64, 78,
- 82, 85, 86, 87, 88, 91, 50, 63, 78, 80,
- 83, 61, 80, 62, 78, 10, 43, 49, 69, 79,
- 81, 82, 83, 86, 87, 91, 88, 49, 60, 64,
- 70, 43, 49, 51, 65, 81, 83, 91, 85, 71,
- 80, 72, 80, 73, 80, 85, 74, 82, 75, 83,
- 76, 80, 77, 80, 46, 48, 48, 47, 91, 91,
- 6, 8, 9, 89, 78, 36, 42, 91, 92, 91,
- 51, 51, 9, 40, 41, 51, 88, 91, 49, 49,
- 49, 82, 86, 88, 89, 10, 79, 51, 11, 89,
- 81, 49, 51, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 58, 92, 92, 7, 91, 91, 51, 10,
- 52, 52, 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 52, 36, 36, 37, 42, 40, 9, 40,
- 78, 80, 33, 91, 81, 50, 91, 78, 78, 78,
- 83, 91, 78, 78, 80, 80, 57, 89, 32, 34,
- 42, 90, 91, 51, 92, 92, 92, 6, 7, 92,
- 92, 92, 92, 92, 10, 10, 52, 52, 52, 40,
- 52, 52, 49, 9, 31, 84, 49, 46, 46, 49,
- 49, 49, 51, 52, 52, 36, 92, 92, 91, 91,
- 51, 52, 83, 31, 9, 50, 36, 37, 83, 91,
- 82, 34, 10, 52, 52, 36, 37, 9, 31, 84,
- 52, 91, 10, 10, 31, 52, 91, 91, 52, 52
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 3:
-#line 66 "a.y"
- {
- stmtline = lineno;
- }
- break;
-
- case 5:
-#line 73 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyvsp[(1) - (2)].sym)->type = LLAB;
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 10:
-#line 87 "a.y"
- {
- (yyvsp[(1) - (3)].sym)->type = LVAR;
- (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 11:
-#line 92 "a.y"
- {
- if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
- yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
- (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 12:
-#line 97 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 13:
-#line 98 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 14:
-#line 99 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 15:
-#line 100 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 16:
-#line 101 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 17:
-#line 102 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 20:
-#line 105 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 21:
-#line 106 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 22:
-#line 107 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 23:
-#line 108 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 24:
-#line 109 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 26:
-#line 111 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 27:
-#line 112 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 28:
-#line 113 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 29:
-#line 114 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
- break;
-
- case 30:
-#line 117 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 31:
-#line 122 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 32:
-#line 129 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 33:
-#line 136 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 34:
-#line 143 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 35:
-#line 148 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 36:
-#line 155 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 37:
-#line 160 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 38:
-#line 167 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 39:
-#line 172 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 40:
-#line 177 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 41:
-#line 184 "a.y"
- {
- Addr2 a;
- a.from = (yyvsp[(2) - (6)].addr);
- a.to = (yyvsp[(6) - (6)].addr);
- outcode(ADATA, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 42:
-#line 197 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (5)].addr).sym);
- a.from = (yyvsp[(2) - (5)].addr);
- a.to = (yyvsp[(5) - (5)].addr);
- outcode(ATEXT, &a);
- }
- break;
-
- case 43:
-#line 205 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (7)].addr).sym);
- a.from = (yyvsp[(2) - (7)].addr);
- a.to = (yyvsp[(7) - (7)].addr);
- outcode(ATEXT, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
- }
- }
- break;
-
- case 44:
-#line 219 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (4)].addr).sym);
- a.from = (yyvsp[(2) - (4)].addr);
- a.to = (yyvsp[(4) - (4)].addr);
- outcode(AGLOBL, &a);
- }
- break;
-
- case 45:
-#line 227 "a.y"
- {
- Addr2 a;
- settext((yyvsp[(2) - (6)].addr).sym);
- a.from = (yyvsp[(2) - (6)].addr);
- a.to = (yyvsp[(6) - (6)].addr);
- outcode(AGLOBL, &a);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 46:
-#line 241 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 47:
-#line 246 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 48:
-#line 251 "a.y"
- {
- (yyval.addr2).from = nullgen;
- (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
- (yyval.addr2).to.type = TYPE_INDIR;
- }
- break;
-
- case 51:
-#line 263 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 52:
-#line 268 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- if((yyval.addr2).from.index != TYPE_NONE)
- yyerror("dp shift with lhs index");
- (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 53:
-#line 278 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 54:
-#line 283 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- if((yyval.addr2).to.index != TYPE_NONE)
- yyerror("dp move with lhs index");
- (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 55:
-#line 293 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 56:
-#line 298 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
- (yyval.addr2).to = nullgen;
- }
- break;
-
- case 57:
-#line 303 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 58:
-#line 310 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
- (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
- }
- break;
-
- case 59:
-#line 318 "a.y"
- {
- (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
- (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
- if((yyvsp[(1) - (5)].addr).type != TYPE_CONST)
- yyerror("illegal constant");
- (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
- }
- break;
-
- case 60:
-#line 328 "a.y"
- {
- if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 61:
-#line 337 "a.y"
- {
- if((yyvsp[(1) - (3)].addr).type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC))
- yyerror("value for FUNCDATA must be symbol reference");
- (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- }
- break;
-
- case 66:
-#line 354 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 67:
-#line 358 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- }
- break;
-
- case 73:
-#line 371 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
- }
- break;
-
- case 74:
-#line 377 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- (yyval.addr) = nullgen;
- if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 75:
-#line 388 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 76:
-#line 394 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 77:
-#line 400 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 78:
-#line 406 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 79:
-#line 412 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = REG_SP;
- }
- break;
-
- case 80:
-#line 418 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 81:
-#line 426 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 82:
-#line 432 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- (yyval.addr).type = TYPE_ADDR;
- /*
- if($2.name == NAME_AUTO || $2.name == NAME_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.sym->name);
- */
- }
- break;
-
- case 83:
-#line 442 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SCONST;
- memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
- }
- break;
-
- case 84:
-#line 448 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
- }
- break;
-
- case 85:
-#line 454 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
- }
- break;
-
- case 86:
-#line 460 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
- }
- break;
-
- case 87:
-#line 466 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
- }
- break;
-
- case 88:
-#line 474 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 89:
-#line 481 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 90:
-#line 488 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
- (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 91:
-#line 495 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
- (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 94:
-#line 508 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_NONE;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 95:
-#line 515 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 96:
-#line 522 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_SP;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 97:
-#line 529 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_NONE;
- (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
- (yyval.addr).index = (yyvsp[(3) - (6)].lval);
- (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 98:
-#line 539 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
- (yyval.addr).index = (yyvsp[(6) - (9)].lval);
- (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 99:
-#line 549 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (9)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
- (yyval.addr).index = (yyvsp[(6) - (9)].lval);
- (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 100:
-#line 559 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 101:
-#line 565 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_SP;
- }
- break;
-
- case 102:
-#line 571 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 103:
-#line 578 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = REG_NONE;
- (yyval.addr).index = (yyvsp[(2) - (5)].lval);
- (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 104:
-#line 587 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (8)].lval);
- (yyval.addr).index = (yyvsp[(5) - (8)].lval);
- (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 105:
-#line 598 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (1)].addr);
- }
- break;
-
- case 106:
-#line 602 "a.y"
- {
- (yyval.addr) = (yyvsp[(1) - (6)].addr);
- (yyval.addr).index = (yyvsp[(3) - (6)].lval);
- (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.addr).scale);
- }
- break;
-
- case 107:
-#line 611 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(4) - (5)].lval);
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
- (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
- }
- break;
-
- case 108:
-#line 619 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = NAME_STATIC;
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
- (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
- }
- break;
-
- case 109:
-#line 628 "a.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 110:
-#line 632 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 111:
-#line 636 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 113:
-#line 643 "a.y"
- {
- (yyval.lval) = NAME_AUTO;
- }
- break;
-
- case 116:
-#line 651 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
- }
- break;
-
- case 117:
-#line 655 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 118:
-#line 659 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 119:
-#line 663 "a.y"
- {
- (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 120:
-#line 667 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 122:
-#line 674 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 123:
-#line 678 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 124:
-#line 682 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 125:
-#line 686 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 126:
-#line 690 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 127:
-#line 694 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 128:
-#line 698 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 129:
-#line 702 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 130:
-#line 706 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 131:
-#line 710 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 2565 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
deleted file mode 100644
index 3ab1bfa0f4..0000000000
--- a/src/cmd/8a/y.tab.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LTYPE0 = 258,
- LTYPE1 = 259,
- LTYPE2 = 260,
- LTYPE3 = 261,
- LTYPE4 = 262,
- LTYPEC = 263,
- LTYPED = 264,
- LTYPEN = 265,
- LTYPER = 266,
- LTYPET = 267,
- LTYPES = 268,
- LTYPEM = 269,
- LTYPEI = 270,
- LTYPEG = 271,
- LTYPEXC = 272,
- LTYPEX = 273,
- LTYPEPC = 274,
- LTYPEF = 275,
- LCONST = 276,
- LFP = 277,
- LPC = 278,
- LSB = 279,
- LBREG = 280,
- LLREG = 281,
- LSREG = 282,
- LFREG = 283,
- LXREG = 284,
- LFCONST = 285,
- LSCONST = 286,
- LSP = 287,
- LNAME = 288,
- LLAB = 289,
- LVAR = 290
- };
-#endif
-/* Tokens. */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPES 268
-#define LTYPEM 269
-#define LTYPEI 270
-#define LTYPEG 271
-#define LTYPEXC 272
-#define LTYPEX 273
-#define LTYPEPC 274
-#define LTYPEF 275
-#define LCONST 276
-#define LFP 277
-#define LPC 278
-#define LSB 279
-#define LBREG 280
-#define LLREG 281
-#define LSREG 282
-#define LFREG 283
-#define LXREG 284
-#define LFCONST 285
-#define LSCONST 286
-#define LSP 287
-#define LNAME 288
-#define LLAB 289
-#define LVAR 290
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- int32 lval;
- double dval;
- char sval[8];
- Addr addr;
- Addr2 addr2;
-}
-/* Line 1529 of yacc.c. */
-#line 128 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
deleted file mode 100644
index 3f528d7517..0000000000
--- a/src/cmd/8g/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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.
-
-include ../../Make.dist
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
deleted file mode 100644
index f06927c905..0000000000
--- a/src/cmd/8g/cgen.c
+++ /dev/null
@@ -1,1590 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc):
-// assume CLD?
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-void
-mgen(Node *n, Node *n1, Node *rg)
-{
- Node n2;
-
- n1->op = OEMPTY;
-
- if(n->addable) {
- *n1 = *n;
- if(n1->op == OREGISTER || n1->op == OINDREG)
- reg[n->val.u.reg]++;
- return;
- }
- tempname(n1, n->type);
- cgen(n, n1);
- if(n->type->width <= widthptr || isfloat[n->type->etype]) {
- n2 = *n1;
- regalloc(n1, n->type, rg);
- gmove(&n2, n1);
- }
-}
-
-void
-mfree(Node *n)
-{
- if(n->op == OREGISTER)
- regfree(n);
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- *
- * TODO:
- * sudoaddable
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r, n1, n2, nt;
- Prog *p1, *p2, *p3;
- int a;
-
- if(debug['g']) {
- dump("\ncgen-n", n);
- dump("cgen-res", res);
- }
-
- if(n == N || n->type == T)
- fatal("cgen: n nil");
- if(res == N || res->type == T)
- fatal("cgen: res nil");
-
- switch(n->op) {
- case OSLICE:
- case OSLICEARR:
- case OSLICESTR:
- case OSLICE3:
- case OSLICE3ARR:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_slice(n, &n1);
- cgen(&n1, res);
- } else
- cgen_slice(n, res);
- return;
- case OEFACE:
- if (res->op != ONAME || !res->addable) {
- tempname(&n1, n->type);
- cgen_eface(n, &n1);
- cgen(&n1, res);
- } else
- cgen_eface(n, res);
- return;
- }
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- // function calls on both sides? introduce temporary
- if(n->ullman >= UINF && res->ullman >= UINF) {
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // structs etc get handled specially
- if(isfat(n->type)) {
- if(n->type->width < 0)
- fatal("forgot to compute width for %T", n->type);
- sgen(n, res, n->type->width);
- return;
- }
-
- // update addressability for string, slice
- // can't do in walk because n->left->addable
- // changes if n->left is an escaping local variable.
- switch(n->op) {
- case OSPTR:
- case OLEN:
- if(isslice(n->left->type) || istype(n->left->type, TSTRING))
- n->addable = n->left->addable;
- break;
- case OCAP:
- if(isslice(n->left->type))
- n->addable = n->left->addable;
- break;
- case OITAB:
- n->addable = n->left->addable;
- break;
- }
-
- // if both are addressable, move
- if(n->addable && res->addable) {
- gmove(n, res);
- return;
- }
-
- // if both are not addressable, use a temporary.
- if(!n->addable && !res->addable) {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- tempname(&n1, n->type);
- cgen(n, &n1);
- cgen(&n1, res);
- return;
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
-
- // complex types
- if(complexop(n, res)) {
- complexgen(n, res);
- return;
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- // use ullman to pick operand to eval first.
- nl = n->left;
- nr = n->right;
- if(nl != N && nl->ullman >= UINF)
- if(nr != N && nr->ullman >= UINF) {
- // both are hard
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- n2 = *n;
- n2.left = &n1;
- cgen(&n2, res);
- return;
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
- switch(n->op) {
- // math goes to cgen64.
- case OMINUS:
- case OCOM:
- case OADD:
- case OSUB:
- case OMUL:
- case OLROT:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- cgen64(n, res);
- return;
- }
- }
-
- if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) {
- cgen_float(n, res);
- return;
- }
-
- switch(n->op) {
- default:
- dump("cgen", n);
- fatal("cgen %O", n->op);
- break;
-
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- fatal("unexpected complex");
- return;
-
- // 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(AJMP, T, 0);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n, 1, 0, p2);
- gmove(nodbool(0), res);
- patch(p3, pc);
- return;
-
- case OPLUS:
- cgen(nl, res);
- return;
-
- case OMINUS:
- case OCOM:
- 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);
- if(a == AIMULB) {
- cgen_bmul(n->op, nl, nr, res);
- break;
- }
- 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(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- break;
- }
-
- tempname(&n2, n->type);
- mgen(nl, &n1, res);
- gmove(&n1, &n2);
- gmove(&n2, res);
- mfree(&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:
- igen(nl, &n1, res);
- n1.type = ptrto(types[TUINTPTR]);
- 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(ALEAL, N, &n1);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- igen(nl, &n1, res);
- n1.type = n->type;
- gmove(&n1, res);
- regfree(&n1);
- break;
-
- case OLEN:
- if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- tempname(&n1, types[tptr]);
- cgen(nl, &n1);
- regalloc(&n2, types[tptr], N);
- gmove(&n1, &n2);
- n1 = n2;
-
- nodconst(&n2, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(istype(nl->type, TSTRING) || isslice(nl->type)) {
- // both slice and string have len one pointer into the struct.
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_nel;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OLEN: unknown type %lT", nl->type);
- break;
-
- case OCAP:
- if(istype(nl->type, TCHAN)) {
- // chan has cap in the second 32-bit word.
- // a zero pointer means zero length
- tempname(&n1, types[tptr]);
- cgen(nl, &n1);
- regalloc(&n2, types[tptr], N);
- gmove(&n1, &n2);
- n1 = n2;
-
- nodconst(&n2, types[tptr], 0);
- gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
- n2 = n1;
- n2.op = OINDREG;
- n2.xoffset = 4;
- n2.type = types[TINT32];
- gmove(&n2, &n1);
-
- patch(p1, pc);
-
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- if(isslice(nl->type)) {
- igen(nl, &n1, res);
- n1.type = types[TUINT32];
- n1.xoffset += Array_cap;
- gmove(&n1, res);
- regfree(&n1);
- break;
- }
- fatal("cgen: OCAP: unknown type %lT", nl->type);
- break;
-
- case OADDR:
- agen(nl, res);
- break;
-
- case OCALLMETH:
- 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:
- cgen_div(n->op, nl, nr, res);
- break;
-
- case OLSH:
- case ORSH:
- case OLROT:
- cgen_shift(n->op, n->bounded, nl, nr, res);
- break;
- }
- return;
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- if(smallintconst(nr)) {
- mgen(nl, &n1, res);
- regalloc(&n2, nl->type, &n1);
- gmove(&n1, &n2);
- gins(a, nr, &n2);
- gmove(&n2, res);
- regfree(&n2);
- mfree(&n1);
- } else if(nl->ullman >= nr->ullman) {
- tempname(&nt, nl->type);
- cgen(nl, &nt);
- mgen(nr, &n2, N);
- regalloc(&n1, nl->type, res);
- gmove(&nt, &n1);
- gins(a, &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- mfree(&n2);
- } else {
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- gins(a, &n2, &n1);
- regfree(&n2);
- gmove(&n1, res);
- regfree(&n1);
- }
- return;
-
-uop: // unary
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- gins(a, N, &n1);
- gmove(&n1, res);
- return;
-}
-
-/*
- * generate an addressable node in res, containing the value of n.
- * n is an array index, and might be any size; res width is <= 32-bit.
- * returns Prog* to patch to panic call.
- */
-static Prog*
-igenindex(Node *n, Node *res, int bounded)
-{
- Node tmp, lo, hi, zero;
-
- if(!is64(n->type)) {
- if(n->addable) {
- // nothing to do.
- *res = *n;
- } else {
- tempname(res, types[TUINT32]);
- cgen(n, res);
- }
- return nil;
- }
-
- tempname(&tmp, types[TINT64]);
- cgen(n, &tmp);
- split64(&tmp, &lo, &hi);
- tempname(res, types[TUINT32]);
- gmove(&lo, res);
- if(bounded) {
- splitclean();
- return nil;
- }
- nodconst(&zero, types[TINT32], 0);
- gins(ACMPL, &hi, &zero);
- splitclean();
- return gbranch(AJNE, T, +1);
-}
-
-/*
- * address gen
- * 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, tmp, nlen;
- Type *t;
- uint32 w;
- uint64 v;
- Prog *p1, *p2;
- int bounded;
-
- if(debug['g']) {
- dump("\nagen-res", res);
- dump("agen-r", n);
- }
- if(n == N || n->type == T || res == N || res->type == T)
- fatal("agen");
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- if(isconst(n, CTNIL) && n->type->width > widthptr) {
- // Use of a nil interface or nil slice.
- // Create a temporary we can take the address of and read.
- // The generated code is just going to panic, so it need not
- // be terribly efficient. See issue 3670.
- tempname(&n1, n->type);
- gvardef(&n1);
- clearfat(&n1);
- regalloc(&n2, types[tptr], res);
- gins(ALEAL, &n1, &n2);
- gmove(&n2, res);
- regfree(&n2);
- return;
- }
-
- // addressable var is easy
- if(n->addable) {
- if(n->op == OREGISTER)
- fatal("agen OREGISTER");
- regalloc(&n1, types[tptr], res);
- gins(ALEAL, n, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- // let's compute
- nl = n->left;
- nr = n->right;
-
- switch(n->op) {
- default:
- fatal("agen %O", n->op);
-
- case OCALLMETH:
- 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:
- p2 = nil; // to be patched to panicindex.
- w = n->type->width;
- bounded = debug['B'] || n->bounded;
- if(nr->addable) {
- // Generate &nl first, and move nr into register.
- if(!isconst(nl, CTSTR))
- igen(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
- p2 = igenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- } else if(nl->addable) {
- // Generate nr first, and move &nl into register.
- if(!isconst(nr, CTINT)) {
- p2 = igenindex(nr, &tmp, bounded);
- regalloc(&n1, tmp.type, N);
- gmove(&tmp, &n1);
- }
- if(!isconst(nl, CTSTR))
- igen(nl, &n3, res);
- } else {
- p2 = igenindex(nr, &tmp, bounded);
- nr = &tmp;
- if(!isconst(nl, CTSTR))
- igen(nl, &n3, res);
- regalloc(&n1, tmp.type, N);
- gins(optoas(OAS, tmp.type), &tmp, &n1);
- }
-
- // For fixed array we really want the pointer in n3.
- if(isfixedarray(nl->type)) {
- regalloc(&n2, types[tptr], &n3);
- agen(&n3, &n2);
- regfree(&n3);
- n3 = n2;
- }
-
- // &a[0] is in n3 (allocated in res)
- // i is in n1 (if not constant)
- // len(a) is in nlen (if needed)
- // w is width
-
- // constant index
- if(isconst(nr, CTINT)) {
- if(isconst(nl, CTSTR))
- fatal("constant string constant index"); // front end should handle
- v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- if(!debug['B'] && !n->bounded) {
- nlen = n3;
- nlen.type = types[TUINT32];
- nlen.xoffset += Array_nel;
- nodconst(&n2, types[TUINT32], v);
- gins(optoas(OCMP, types[TUINT32]), &nlen, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
- }
-
- // Load base pointer in n2 = n3.
- regalloc(&n2, types[tptr], &n3);
- n3.type = types[tptr];
- n3.xoffset += Array_array;
- gmove(&n3, &n2);
- regfree(&n3);
- if (v*w != 0) {
- nodconst(&n1, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n1, &n2);
- }
- gmove(&n2, res);
- regfree(&n2);
- break;
- }
-
- // i is in register n1, extend to 32 bits.
- t = types[TUINT32];
- if(issigned[n1.type->etype])
- t = types[TINT32];
-
- regalloc(&n2, t, &n1); // i
- gmove(&n1, &n2);
- regfree(&n1);
-
- if(!debug['B'] && !n->bounded) {
- // check bounds
- t = types[TUINT32];
- if(isconst(nl, CTSTR)) {
- nodconst(&nlen, t, nl->val.u.sval->len);
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- nlen = n3;
- nlen.type = t;
- nlen.xoffset += Array_nel;
- } else {
- nodconst(&nlen, t, nl->type->bound);
- }
- gins(optoas(OCMP, t), &n2, &nlen);
- p1 = gbranch(optoas(OLT, t), T, +1);
- if(p2)
- patch(p2, pc);
- ginscall(panicindex, -1);
- patch(p1, pc);
- }
-
- if(isconst(nl, CTSTR)) {
- regalloc(&n3, types[tptr], res);
- p1 = gins(ALEAL, N, &n3);
- datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- p1->from.scale = 1;
- p1->from.index = n2.val.u.reg;
- goto indexdone;
- }
-
- // Load base pointer in n3.
- regalloc(&tmp, types[tptr], &n3);
- if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n3.type = types[tptr];
- n3.xoffset += Array_array;
- gmove(&n3, &tmp);
- }
- regfree(&n3);
- n3 = tmp;
-
- if(w == 0) {
- // nothing to do
- } else if(w == 1 || w == 2 || w == 4 || w == 8) {
- // LEAL (n3)(n2*w), n3
- p1 = gins(ALEAL, &n2, &n3);
- p1->from.scale = w;
- p1->from.type = TYPE_MEM;
- p1->from.index = p1->from.reg;
- p1->from.reg = p1->to.reg;
- } else {
- nodconst(&tmp, types[TUINT32], w);
- gins(optoas(OMUL, types[TUINT32]), &tmp, &n2);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
- }
-
- indexdone:
- gmove(&n3, res);
- regfree(&n2);
- regfree(&n3);
- break;
-
- case ONAME:
- // should only get here with names in this func.
- if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
- dump("bad agen", n);
- fatal("agen: bad ONAME funcdepth %d != %d",
- n->funcdepth, funcdepth);
- }
-
- // should only get here for heap vars or paramref
- if(!(n->class & PHEAP) && n->class != PPARAMREF) {
- dump("bad agen", n);
- fatal("agen: bad ONAME class %#x", n->class);
- }
- cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
-
- case OIND:
- cgen(nl, res);
- cgen_checknil(res);
- break;
-
- case ODOT:
- agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
-
- case ODOTPTR:
- t = nl->type;
- if(!isptr[t->etype])
- fatal("agen: not ptr %N", n);
- cgen(nl, res);
- cgen_checknil(res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[tptr], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
- break;
- }
-}
-
-/*
- * 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 != REG_SP)
- reg[n->val.u.reg]++;
- *a = *n;
- return;
-
- case ODOT:
- igen(n->left, a, res);
- a->xoffset += n->xoffset;
- a->type = n->type;
- return;
-
- case ODOTPTR:
- switch(n->left->op) {
- case ODOT:
- case ODOTPTR:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- // igen-able nodes.
- igen(n->left, &n1, res);
- regalloc(a, types[tptr], &n1);
- gmove(&n1, a);
- regfree(&n1);
- break;
- default:
- regalloc(a, types[tptr], res);
- cgen(n->left, a);
- }
- cgen_checknil(a);
- a->op = OINDREG;
- a->xoffset += n->xoffset;
- a->type = n->type;
- return;
-
- case 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 = REG_SP;
- a->addable = 1;
- a->xoffset = fp->width;
- 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;
- return;
- }
- break;
- }
-
- // release register for now, to avoid
- // confusing tempname.
- if(res != N && res->op == OREGISTER)
- reg[res->val.u.reg]--;
- tempname(&n1, types[tptr]);
- agen(n, &n1);
- if(res != N && res->op == OREGISTER)
- reg[res->val.u.reg]++;
- regalloc(a, types[tptr], res);
- gmove(&n1, a);
- a->op = OINDREG;
- a->type = n->type;
-}
-
-/*
- * branch gen
- * if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, tmp;
- 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)
- return;
- }
-
- et = n->type->etype;
- if(et != TBOOL) {
- yyerror("cgen: bad type %T for %O", n->type, n->op);
- patch(gins(AEND, N, N), to);
- return;
- }
-
- while(n->op == OCONVNOP) {
- n = n->left;
- if(n->ninit != nil)
- genlist(n->ninit);
- }
-
- nl = n->left;
- nr = N;
-
- if(nl != N && isfloat[nl->type->etype]) {
- bgen_float(n, true, likely, to);
- return;
- }
-
- switch(n->op) {
- default:
- goto def;
-
- case OLITERAL:
- // need to ask if it is bool?
- if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T, 0), to);
- return;
-
- case ONAME:
- if(!n->addable)
- goto def;
- nodconst(&n1, n->type, 0);
- gins(optoas(OCMP, n->type), n, &n1);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- return;
-
- case OANDAND:
- case OOROR:
- if((n->op == OANDAND) == true) {
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- } else {
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
- }
- return;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- return;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- }
-
- switch(n->op) {
- case ONOT:
- bgen(nl, !true, likely, to);
- break;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- a = n->op;
- if(!true) {
- 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);
- gins(optoas(OCMP, types[tptr]), &n1, &tmp);
- 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);
- gins(optoas(OCMP, types[tptr]), &n1, &tmp);
- patch(gbranch(a, types[tptr], likely), to);
- regfree(&n1);
- break;
- }
-
- if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, likely, to);
- break;
- }
-
- if(is64(nr->type)) {
- if(!nl->addable || isconst(nl, CTINT)) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- cmp64(nl, nr, a, likely, to);
- break;
- }
-
- if(nr->ullman >= UINF) {
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- nr = &tmp;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- nr = &n2;
- goto cmp;
- }
-
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
-
- if(smallintconst(nr)) {
- gins(optoas(OCMP, nr->type), nl, nr);
- patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
- break;
- }
-
- if(!nr->addable) {
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- nr = &tmp;
- }
- regalloc(&n2, nr->type, N);
- gmove(nr, &n2);
- nr = &n2;
-
-cmp:
- gins(optoas(OCMP, nr->type), nl, nr);
- patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
-
- if(nl->op == OREGISTER)
- regfree(nl);
- regfree(nr);
- break;
- }
- return;
-
-def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- regfree(&n1);
- return;
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
- Type *t;
- Iter flist;
- int32 off;
-
- switch(n->op) {
- case OINDREG:
- return n->xoffset;
-
- case ODOT:
- t = n->left->type;
- if(isptr[t->etype])
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- return off + n->xoffset;
-
- case OINDEX:
- t = n->left->type;
- if(!isfixedarray(t))
- break;
- off = stkof(n->left);
- if(off == -1000 || off == 1000)
- return off;
- if(isconst(n->right, CTINT))
- return off + t->type->width * mpgetfix(n->right->val.u.xval);
- return 1000;
-
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- t = structfirst(&flist, getoutarg(t));
- if(t != T)
- return t->width;
- break;
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000;
-}
-
-/*
- * struct gen
- * memmove(&res, &n, w);
- */
-void
-sgen(Node *n, Node *res, int64 w)
-{
- Node dst, src, tdst, tsrc, cx;
- int32 c, q, odst, osrc;
- NodeList *l;
- Prog *p;
-
- if(debug['g']) {
- print("\nsgen w=%lld\n", w);
- dump("r", n);
- dump("res", res);
- }
- if(n->ullman >= UINF && res->ullman >= UINF)
- fatal("sgen UINF");
-
- if(w < 0 || (int32)w != w)
- fatal("sgen copy %lld", w);
-
- if(w == 0) {
- // evaluate side effects only.
- tempname(&tdst, types[tptr]);
- agen(res, &tdst);
- agen(n, &tdst);
- return;
- }
-
- // If copying .args, that's all the results, so record definition sites
- // for them for the liveness analysis.
- if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
- for(l = curfn->dcl; l != nil; l = l->next)
- if(l->n->class == PPARAMOUT)
- gvardef(l->n);
-
- // Avoid taking the address for simple enough types.
- if(componentgen(n, res))
- return;
-
- // 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(&tsrc, n->type);
- sgen(n, &tsrc, w);
- sgen(&tsrc, res, w);
- return;
- }
-
- nodreg(&dst, types[tptr], REG_DI);
- nodreg(&src, types[tptr], REG_SI);
-
- tempname(&tsrc, types[tptr]);
- tempname(&tdst, types[tptr]);
- if(!n->addable)
- agen(n, &tsrc);
- if(!res->addable)
- agen(res, &tdst);
- if(n->addable)
- agen(n, &src);
- else
- gmove(&tsrc, &src);
-
- if(res->op == ONAME)
- gvardef(res);
-
- if(res->addable)
- agen(res, &dst);
- else
- gmove(&tdst, &dst);
-
- c = w % 4; // bytes
- q = w / 4; // doublewords
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if(osrc < odst && odst < osrc+w) {
- // reverse direction
- gins(ASTD, N, N); // set direction flag
- if(c > 0) {
- gconreg(AADDL, w-1, REG_SI);
- gconreg(AADDL, w-1, REG_DI);
-
- gconreg(AMOVL, c, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
- }
-
- if(q > 0) {
- if(c > 0) {
- gconreg(AADDL, -3, REG_SI);
- gconreg(AADDL, -3, REG_DI);
- } else {
- gconreg(AADDL, w-4, REG_SI);
- gconreg(AADDL, w-4, REG_DI);
- }
- gconreg(AMOVL, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)-
- }
- // we leave with the flag clear
- gins(ACLD, N, N);
- } else {
- gins(ACLD, N, N); // paranoia. TODO(rsc): remove?
- // normal direction
- if(q > 128 || (q >= 4 && nacl)) {
- gconreg(AMOVL, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- } else if(q >= 4) {
- p = gins(ADUFFCOPY, N, N);
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
- // 10 and 128 = magic constants: see ../../runtime/asm_386.s
- p->to.offset = 10*(128-q);
- } else if(!nacl && c == 0) {
- nodreg(&cx, types[TINT32], REG_CX);
- // We don't need the MOVSL side-effect of updating SI and DI,
- // and issuing a sequence of MOVLs directly is faster.
- src.op = OINDREG;
- dst.op = OINDREG;
- while(q > 0) {
- gmove(&src, &cx); // MOVL x+(SI),CX
- gmove(&cx, &dst); // MOVL CX,x+(DI)
- src.xoffset += 4;
- dst.xoffset += 4;
- q--;
- }
- } else
- while(q > 0) {
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- q--;
- }
- while(c > 0) {
- gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
- c--;
- }
- }
-}
-
-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, tmp;
- Type *t;
- int freel, freer;
- vlong fldcount;
- vlong loffset, roffset;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- t = nl->type;
-
- // Slices are ok.
- if(isslice(t))
- break;
- // Small arrays are ok.
- if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
- break;
-
- goto no;
-
- case TSTRUCT:
- // Small structs with non-fat types are ok.
- // Zero-sized structs are treated separately elsewhere.
- fldcount = 0;
- for(t=nl->type->type; t; t=t->down) {
- if(isfat(t->type))
- goto no;
- if(t->etype != TFIELD)
- fatal("componentgen: not a TFIELD: %lT", t);
- fldcount++;
- }
- if(fldcount == 0 || fldcount > 4)
- goto no;
-
- break;
-
- case TSTRING:
- case TINTER:
- break;
- }
-
- nodl = *nl;
- if(!cadable(nl)) {
- if(nr != N && !cadable(nr))
- goto no;
- igen(nl, &nodl, N);
- freel = 1;
- }
-
- if(nr != N) {
- nodr = *nr;
- if(!cadable(nr)) {
- igen(nr, &nodr, N);
- freer = 1;
- }
- } else {
- // When zeroing, prepare a register containing zero.
- nodconst(&tmp, nl->type, 0);
- regalloc(&nodr, types[TUINT], N);
- gmove(&tmp, &nodr);
- freer = 1;
- }
-
- // nl and nr are 'cadable' which basically means they are names (variables) now.
- // If they are the same variable, don't generate any code, because the
- // VARDEF we generate will mark the old value as dead incorrectly.
- // (And also the assignments are useless.)
- if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
- goto yes;
-
- switch(nl->type->etype) {
- case TARRAY:
- // componentgen for arrays.
- if(nl->op == ONAME)
- gvardef(nl);
- t = nl->type;
- if(!isslice(t)) {
- nodl.type = t->type;
- nodr.type = nodl.type;
- for(fldcount=0; fldcount < t->bound; fldcount++) {
- if(nr == N)
- clearslim(&nodl);
- else
- gmove(&nodr, &nodl);
- nodl.xoffset += t->type->width;
- nodr.xoffset += t->type->width;
- }
- goto yes;
- }
-
- // componentgen for slices.
- nodl.xoffset += Array_array;
- nodl.type = ptrto(nl->type->type);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_cap-Array_nel;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRING:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TINTER:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRUCT:
- if(nl->op == ONAME)
- gvardef(nl);
- loffset = nodl.xoffset;
- roffset = nodr.xoffset;
- // funarg structs may not begin at offset zero.
- if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
- loffset -= nl->type->type->width;
- if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
- roffset -= nr->type->type->width;
-
- for(t=nl->type->type; t; t=t->down) {
- nodl.xoffset = loffset + t->width;
- nodl.type = t->type;
-
- if(nr == N)
- clearslim(&nodl);
- else {
- nodr.xoffset = roffset + t->width;
- nodr.type = nodl.type;
- gmove(&nodr, &nodl);
- }
- }
- goto yes;
- }
-
-no:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 0;
-
-yes:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 1;
-}
diff --git a/src/cmd/new8g/cgen.go b/src/cmd/8g/cgen.go
index 9f736b1745..9f736b1745 100644
--- a/src/cmd/new8g/cgen.go
+++ b/src/cmd/8g/cgen.go
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
deleted file mode 100644
index d9e812f384..0000000000
--- a/src/cmd/8g/cgen64.c
+++ /dev/null
@@ -1,549 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
- Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
- Node lo1, lo2, hi1, hi2;
- Prog *p1, *p2;
- uint64 v;
- uint32 lv, hv;
-
- if(res->op != OINDREG && res->op != ONAME) {
- dump("n", n);
- dump("res", res);
- fatal("cgen64 %O of %O", n->op, res->op);
- }
- switch(n->op) {
- default:
- fatal("cgen64 %O", n->op);
-
- case OMINUS:
- cgen(n->left, res);
- split64(res, &lo1, &hi1);
- gins(ANEGL, N, &lo1);
- gins(AADCL, ncon(0), &hi1);
- gins(ANEGL, N, &hi1);
- splitclean();
- return;
-
- case OCOM:
- cgen(n->left, res);
- split64(res, &lo1, &hi1);
- gins(ANOTL, N, &lo1);
- gins(ANOTL, N, &hi1);
- splitclean();
- return;
-
- case OADD:
- case OSUB:
- case OMUL:
- case OLROT:
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- // binary operators.
- // common setup below.
- break;
- }
-
- l = n->left;
- r = n->right;
- if(!l->addable) {
- tempname(&t1, l->type);
- cgen(l, &t1);
- l = &t1;
- }
- if(r != N && !r->addable) {
- tempname(&t2, r->type);
- cgen(r, &t2);
- r = &t2;
- }
-
- nodreg(&ax, types[TINT32], REG_AX);
- nodreg(&cx, types[TINT32], REG_CX);
- nodreg(&dx, types[TINT32], REG_DX);
-
- // Setup for binary operation.
- split64(l, &lo1, &hi1);
- if(is64(r->type))
- split64(r, &lo2, &hi2);
-
- // Do op. Leave result in DX:AX.
- switch(n->op) {
- case OADD:
- // TODO: Constants
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(AADDL, &lo2, &ax);
- gins(AADCL, &hi2, &dx);
- break;
-
- case OSUB:
- // TODO: Constants.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(ASUBL, &lo2, &ax);
- gins(ASBBL, &hi2, &dx);
- break;
-
- case OMUL:
- // let's call the next two EX and FX.
- regalloc(&ex, types[TPTR32], N);
- regalloc(&fx, types[TPTR32], N);
-
- // load args into DX:AX and EX:CX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(AMOVL, &lo2, &cx);
- gins(AMOVL, &hi2, &ex);
-
- // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
- gins(AMOVL, &dx, &fx);
- gins(AORL, &ex, &fx);
- p1 = gbranch(AJNE, T, 0);
- gins(AMULL, &cx, N); // implicit &ax
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
-
- // full 64x64 -> 64, from 32x32 -> 64.
- gins(AIMULL, &cx, &dx);
- gins(AMOVL, &ax, &fx);
- gins(AIMULL, &ex, &fx);
- gins(AADDL, &dx, &fx);
- gins(AMOVL, &cx, &dx);
- gins(AMULL, &dx, N); // implicit &ax
- gins(AADDL, &fx, &dx);
- patch(p2, pc);
-
- regfree(&ex);
- regfree(&fx);
- break;
-
- case OLROT:
- // We only rotate by a constant c in [0,64).
- // if c >= 32:
- // lo, hi = hi, lo
- // c -= 32
- // if c == 0:
- // no-op
- // else:
- // t = hi
- // shld hi:lo, c
- // shld lo:t, c
- v = mpgetfix(r->val.u.xval);
- if(v >= 32) {
- // reverse during load to do the first 32 bits of rotate
- v -= 32;
- gins(AMOVL, &lo1, &dx);
- gins(AMOVL, &hi1, &ax);
- } else {
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- }
- if(v == 0) {
- // done
- } else {
- gins(AMOVL, &dx, &cx);
- p1 = gins(ASHLL, ncon(v), &dx);
- p1->from.index = REG_AX; // double-width shift
- p1->from.scale = 0;
- p1 = gins(ASHLL, ncon(v), &ax);
- p1->from.index = REG_CX; // double-width shift
- p1->from.scale = 0;
- }
- break;
-
- case OLSH:
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(is64(r->type))
- splitclean();
- splitclean();
- split64(res, &lo2, &hi2);
- gins(AMOVL, ncon(0), &lo2);
- gins(AMOVL, ncon(0), &hi2);
- splitclean();
- goto out;
- }
- if(v >= 32) {
- if(is64(r->type))
- splitclean();
- split64(res, &lo2, &hi2);
- gmove(&lo1, &hi2);
- if(v > 32) {
- gins(ASHLL, ncon(v - 32), &hi2);
- }
- gins(AMOVL, ncon(0), &lo2);
- splitclean();
- splitclean();
- goto out;
- }
-
- // general shift
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- p1 = gins(ASHLL, ncon(v), &dx);
- p1->from.index = REG_AX; // double-width shift
- p1->from.scale = 0;
- gins(ASHLL, ncon(v), &ax);
- break;
- }
-
- // load value into DX:AX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
-
- // load shift value into register.
- // if high bits are set, zero value.
- p1 = P;
- if(is64(r->type)) {
- gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T, +1);
- gins(AMOVL, &lo2, &cx);
- } else {
- cx.type = types[TUINT32];
- gmove(r, &cx);
- }
-
- // if shift count is >=64, zero value
- gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- if(p1 != P)
- patch(p1, pc);
- gins(AXORL, &dx, &dx);
- gins(AXORL, &ax, &ax);
- patch(p2, pc);
-
- // if shift count is >= 32, zero low.
- gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- gins(AMOVL, &ax, &dx);
- gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
- gins(AXORL, &ax, &ax);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
-
- // general shift
- p1 = gins(ASHLL, &cx, &dx);
- p1->from.index = REG_AX; // double-width shift
- p1->from.scale = 0;
- gins(ASHLL, &cx, &ax);
- patch(p2, pc);
- break;
-
- case ORSH:
- if(r->op == OLITERAL) {
- v = mpgetfix(r->val.u.xval);
- if(v >= 64) {
- if(is64(r->type))
- splitclean();
- splitclean();
- split64(res, &lo2, &hi2);
- if(hi1.type->etype == TINT32) {
- gmove(&hi1, &lo2);
- gins(ASARL, ncon(31), &lo2);
- gmove(&hi1, &hi2);
- gins(ASARL, ncon(31), &hi2);
- } else {
- gins(AMOVL, ncon(0), &lo2);
- gins(AMOVL, ncon(0), &hi2);
- }
- splitclean();
- goto out;
- }
- if(v >= 32) {
- if(is64(r->type))
- splitclean();
- split64(res, &lo2, &hi2);
- gmove(&hi1, &lo2);
- if(v > 32)
- gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
- if(hi1.type->etype == TINT32) {
- gmove(&hi1, &hi2);
- gins(ASARL, ncon(31), &hi2);
- } else
- gins(AMOVL, ncon(0), &hi2);
- splitclean();
- splitclean();
- goto out;
- }
-
- // general shift
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- p1 = gins(ASHRL, ncon(v), &ax);
- p1->from.index = REG_DX; // double-width shift
- p1->from.scale = 0;
- gins(optoas(ORSH, hi1.type), ncon(v), &dx);
- break;
- }
-
- // load value into DX:AX.
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
-
- // load shift value into register.
- // if high bits are set, zero value.
- p1 = P;
- if(is64(r->type)) {
- gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T, +1);
- gins(AMOVL, &lo2, &cx);
- } else {
- cx.type = types[TUINT32];
- gmove(r, &cx);
- }
-
- // if shift count is >=64, zero or sign-extend value
- gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- if(p1 != P)
- patch(p1, pc);
- if(hi1.type->etype == TINT32) {
- gins(ASARL, ncon(31), &dx);
- gins(AMOVL, &dx, &ax);
- } else {
- gins(AXORL, &dx, &dx);
- gins(AXORL, &ax, &ax);
- }
- patch(p2, pc);
-
- // if shift count is >= 32, sign-extend hi.
- gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- gins(AMOVL, &dx, &ax);
- if(hi1.type->etype == TINT32) {
- gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
- gins(ASARL, ncon(31), &dx);
- } else {
- gins(ASHRL, &cx, &ax);
- gins(AXORL, &dx, &dx);
- }
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
-
- // general shift
- p1 = gins(ASHRL, &cx, &ax);
- p1->from.index = REG_DX; // double-width shift
- p1->from.scale = 0;
- gins(optoas(ORSH, hi1.type), &cx, &dx);
- patch(p2, pc);
- break;
-
- case OXOR:
- case OAND:
- case OOR:
- // make constant the right side (it usually is anyway).
- if(lo1.op == OLITERAL) {
- nswap(&lo1, &lo2);
- nswap(&hi1, &hi2);
- }
- if(lo2.op == OLITERAL) {
- // special cases for constants.
- lv = mpgetfix(lo2.val.u.xval);
- hv = mpgetfix(hi2.val.u.xval);
- splitclean(); // right side
- split64(res, &lo2, &hi2);
- switch(n->op) {
- case OXOR:
- gmove(&lo1, &lo2);
- gmove(&hi1, &hi2);
- switch(lv) {
- case 0:
- break;
- case 0xffffffffu:
- gins(ANOTL, N, &lo2);
- break;
- default:
- gins(AXORL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- break;
- case 0xffffffffu:
- gins(ANOTL, N, &hi2);
- break;
- default:
- gins(AXORL, ncon(hv), &hi2);
- break;
- }
- break;
-
- case OAND:
- switch(lv) {
- case 0:
- gins(AMOVL, ncon(0), &lo2);
- break;
- default:
- gmove(&lo1, &lo2);
- if(lv != 0xffffffffu)
- gins(AANDL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- gins(AMOVL, ncon(0), &hi2);
- break;
- default:
- gmove(&hi1, &hi2);
- if(hv != 0xffffffffu)
- gins(AANDL, ncon(hv), &hi2);
- break;
- }
- break;
-
- case OOR:
- switch(lv) {
- case 0:
- gmove(&lo1, &lo2);
- break;
- case 0xffffffffu:
- gins(AMOVL, ncon(0xffffffffu), &lo2);
- break;
- default:
- gmove(&lo1, &lo2);
- gins(AORL, ncon(lv), &lo2);
- break;
- }
- switch(hv) {
- case 0:
- gmove(&hi1, &hi2);
- break;
- case 0xffffffffu:
- gins(AMOVL, ncon(0xffffffffu), &hi2);
- break;
- default:
- gmove(&hi1, &hi2);
- gins(AORL, ncon(hv), &hi2);
- break;
- }
- break;
- }
- splitclean();
- splitclean();
- goto out;
- }
- gins(AMOVL, &lo1, &ax);
- gins(AMOVL, &hi1, &dx);
- gins(optoas(n->op, lo1.type), &lo2, &ax);
- gins(optoas(n->op, lo1.type), &hi2, &dx);
- break;
- }
- if(is64(r->type))
- splitclean();
- splitclean();
-
- split64(res, &lo1, &hi1);
- gins(AMOVL, &ax, &lo1);
- gins(AMOVL, &dx, &hi1);
- splitclean();
-
-out:;
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
-{
- Node lo1, hi1, lo2, hi2, rr;
- Prog *br;
- Type *t;
-
- split64(nl, &lo1, &hi1);
- split64(nr, &lo2, &hi2);
-
- // compare most significant word;
- // if they differ, we're done.
- t = hi1.type;
- if(nl->op == OLITERAL || nr->op == OLITERAL)
- gins(ACMPL, &hi1, &hi2);
- else {
- regalloc(&rr, types[TINT32], N);
- gins(AMOVL, &hi1, &rr);
- gins(ACMPL, &rr, &hi2);
- regfree(&rr);
- }
- br = P;
- switch(op) {
- default:
- fatal("cmp64 %O %T", op, t);
- case OEQ:
- // cmp hi
- // jne L
- // cmp lo
- // jeq to
- // L:
- br = gbranch(AJNE, T, -likely);
- break;
- case ONE:
- // cmp hi
- // jne to
- // cmp lo
- // jne to
- patch(gbranch(AJNE, T, likely), to);
- break;
- case OGE:
- case OGT:
- // cmp hi
- // jgt to
- // jlt L
- // cmp lo
- // jge to (or jgt to)
- // L:
- patch(gbranch(optoas(OGT, t), T, likely), to);
- br = gbranch(optoas(OLT, t), T, -likely);
- break;
- case OLE:
- case OLT:
- // cmp hi
- // jlt to
- // jgt L
- // cmp lo
- // jle to (or jlt to)
- // L:
- patch(gbranch(optoas(OLT, t), T, likely), to);
- br = gbranch(optoas(OGT, t), T, -likely);
- break;
- }
-
- // compare least significant word
- t = lo1.type;
- if(nl->op == OLITERAL || nr->op == OLITERAL)
- gins(ACMPL, &lo1, &lo2);
- else {
- regalloc(&rr, types[TINT32], N);
- gins(AMOVL, &lo1, &rr);
- gins(ACMPL, &rr, &lo2);
- regfree(&rr);
- }
-
- // jump again
- patch(gbranch(optoas(op, t), T, likely), to);
-
- // point first branch down here if appropriate
- if(br != P)
- patch(br, pc);
-
- splitclean();
- splitclean();
-}
-
diff --git a/src/cmd/new8g/cgen64.go b/src/cmd/8g/cgen64.go
index 1937ae0941..1937ae0941 100644
--- a/src/cmd/new8g/cgen64.go
+++ b/src/cmd/8g/cgen64.go
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
deleted file mode 100644
index 9e46dcad8f..0000000000
--- a/src/cmd/8g/doc.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-8g is the version of the gc compiler for the x86.
-The $GOARCH for these tools is 386.
-
-It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
deleted file mode 100644
index 33951adfd2..0000000000
--- a/src/cmd/8g/galign.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int thechar = '8';
-char* thestring = "386";
-LinkArch* thelinkarch = &link386;
-
-void
-linkarchinit(void)
-{
-}
-
-vlong MAXWIDTH = (1LL<<32) - 1;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- {"int", TINT, TINT32},
- {"uint", TUINT, TUINT32},
- {"uintptr", TUINTPTR, TUINT32},
- {0}
-};
-
-void
-betypeinit(void)
-{
- widthptr = 4;
- widthint = 4;
- widthreg = 4;
-
- listinit8();
-}
-
-void
-main(int argc, char **argv)
-{
- thearch.thechar = thechar;
- thearch.thestring = thestring;
- thearch.thelinkarch = thelinkarch;
- thearch.typedefs = typedefs;
- thearch.REGSP = REGSP;
- thearch.REGCTXT = REGCTXT;
- thearch.MAXWIDTH = MAXWIDTH;
- thearch.anyregalloc = anyregalloc;
- thearch.betypeinit = betypeinit;
- thearch.bgen = bgen;
- thearch.cgen = cgen;
- thearch.cgen_call = cgen_call;
- thearch.cgen_callinter = cgen_callinter;
- thearch.cgen_ret = cgen_ret;
- thearch.clearfat = clearfat;
- thearch.defframe = defframe;
- thearch.excise = excise;
- thearch.expandchecks = expandchecks;
- thearch.gclean = gclean;
- thearch.ginit = ginit;
- thearch.gins = gins;
- thearch.ginscall = ginscall;
- thearch.igen = igen;
- thearch.linkarchinit = linkarchinit;
- thearch.peep = peep;
- thearch.proginfo = proginfo;
- thearch.regalloc = regalloc;
- thearch.regfree = regfree;
- thearch.regtyp = regtyp;
- thearch.sameaddr = sameaddr;
- thearch.smallindir = smallindir;
- thearch.stackaddr = stackaddr;
- thearch.excludedregs = excludedregs;
- thearch.RtoB = RtoB;
- thearch.FtoB = FtoB;
- thearch.BtoR = BtoR;
- thearch.BtoF = BtoF;
- thearch.optoas = optoas;
- thearch.doregbits = doregbits;
- thearch.regnames = regnames;
-
- gcmain(argc, argv);
-}
diff --git a/src/cmd/new8g/galign.go b/src/cmd/8g/galign.go
index 45ef1302f3..45ef1302f3 100644
--- a/src/cmd/new8g/galign.go
+++ b/src/cmd/8g/galign.go
diff --git a/src/cmd/new8g/gg.go b/src/cmd/8g/gg.go
index 4aeff92952..4aeff92952 100644
--- a/src/cmd/new8g/gg.go
+++ b/src/cmd/8g/gg.go
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
deleted file mode 100644
index 872d946592..0000000000
--- a/src/cmd/8g/gg.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#include "../gc/go.h"
-#include "../8l/8.out.h"
-
-// foptoas flags
-enum
-{
- Frev = 1<<0,
- Fpop = 1<<1,
- Fpop2 = 1<<2,
-};
-
-EXTERN uchar reg[MAXREG];
-EXTERN Node* panicdiv;
-extern uint32 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_bmul(int, Node*, Node*, Node*);
-void cgen_hmul(Node*, Node*, Node*);
-void cgen_shift(int, int, Node*, Node*, Node*);
-void cgen_float(Node*, Node*);
-void bgen_float(Node *n, int true, int likely, Prog *to);
-void cgen_dcl(Node*);
-int needconvert(Type*, Type*);
-void genconv(Type*, Type*);
-void allocparams(void);
-void checklabels(void);
-void ginscall(Node*, int);
-
-/*
- * cgen.c
- */
-void agen(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*);
-int samaddr(Node*, Node*);
-void naddr(Node*, Addr*, int);
-void cgen_aret(Node*, Node*);
-Node* ncon(uint32);
-void mgen(Node*, Node*, Node*);
-void mfree(Node*);
-int componentgen(Node*, Node*);
-
-/*
- * cgen64.c
- */
-void cmp64(Node*, Node*, int, int, Prog*);
-void cgen64(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*);
-int foptoas(int, Type*, int);
-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 nodconst(Node*, Type*, int64);
-void gconreg(int, vlong, int);
-void buildtxt(void);
-Plist* newplist(void);
-int isfat(Type*);
-void sudoclean(void);
-int sudoaddable(int, Node*, Addr*);
-int dotaddable(Node*, Node*);
-void afunclit(Addr*, Node*);
-void split64(Node*, Node*, Node*);
-void splitclean(void);
-void nswap(Node*, Node*);
-void gtrack(Sym*);
-/*
- * 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);
-
-void afunclit(Addr*, Node*);
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node*, int, int, Prog*);
-void cgen(Node*, Node*);
-void cgen_call(Node*, int);
-void cgen_callinter(Node*, Node*, int);
-void cgen_ret(Node*);
-void clearfat(Node*);
-void clearp(Prog*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int, char*);
-int dgostrlitptr(Sym*, int, Strlit*);
-int dsname(Sym*, int, char*, int);
-int dsymptr(Sym*, int, Sym*, int);
-void dumpdata(void);
-void dumpit(char*, Flow*, int);
-void excise(Flow*);
-void expandchecks(Prog*);
-void fixautoused(Prog*);
-void gclean(void);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void ggloblnod(Node *nam);
-void ggloblsym(Sym *s, int32 width, int8 flags);
-void ginit(void);
-Prog* gins(int, Node*, Node*);
-void ginscall(Node*, int);
-Prog* gjmp(Prog*);
-void gtrack(Sym*);
-void gused(Node*);
-void igen(Node*, Node*, Node*);
-int isfat(Type*);
-void linkarchinit(void);
-void markautoused(Prog*);
-void naddr(Node*, Addr*, int);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void patch(Prog*, Prog*);
-void proginfo(ProgInfo*, Prog*);
-void regalloc(Node*, Type*, Node*);
-void regfree(Node*);
-void regopt(Prog*);
-int regtyp(Addr*);
-int sameaddr(Addr*, Addr*);
-int smallindir(Addr*, Addr*);
-int stackaddr(Addr*);
-Prog* unpatch(Prog*);
-
-/*
- * reg.c
- */
-uint64 excludedregs(void);
-uint64 RtoB(int);
-uint64 FtoB(int);
-int BtoR(uint64);
-int BtoF(uint64);
-uint64 doregbits(int);
-char** regnames(int*);
-
-/*
- * peep.c
- */
-void peep(Prog*);
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
deleted file mode 100644
index 8188348282..0000000000
--- a/src/cmd/8g/ggen.c
+++ /dev/null
@@ -1,1165 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#undef EXTERN
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
-
-void
-defframe(Prog *ptxt)
-{
- uint32 frame, ax;
- Prog *p;
- vlong lo, hi;
- NodeList *l;
- Node *n;
-
- // fill in argument size, stack size
- ptxt->to.type = TYPE_TEXTSIZE;
- ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
- frame = rnd(stksize+maxarg, widthreg);
- ptxt->to.offset = frame;
-
- // insert code to zero ambiguously live variables
- // so that the garbage collector only sees initialized values
- // when it looks for pointers.
- p = ptxt;
- hi = 0;
- lo = hi;
- ax = 0;
- for(l=curfn->dcl; l != nil; l = l->next) {
- n = l->n;
- if(!n->needzero)
- continue;
- if(n->class != PAUTO)
- fatal("needzero class %d", n->class);
- if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
- fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
- if(lo != hi && n->xoffset + n->type->width == lo - 2*widthptr) {
- // merge with range we already have
- lo = n->xoffset;
- continue;
- }
- // zero old range
- p = zerorange(p, frame, lo, hi, &ax);
-
- // set new range
- hi = n->xoffset + n->type->width;
- lo = n->xoffset;
- }
- // zero final range
- zerorange(p, frame, lo, hi, &ax);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
-{
- vlong cnt, i;
-
- cnt = hi - lo;
- if(cnt == 0)
- return p;
- if(*ax == 0) {
- p = appendpp(p, AMOVL, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0);
- *ax = 1;
- }
- if(cnt <= 4*widthreg) {
- for(i = 0; i < cnt; i += widthreg) {
- p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i);
- }
- } else if(!nacl && cnt <= 128*widthreg) {
- p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
- p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 1*(128-cnt/widthreg));
- p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
- } else {
- p = appendpp(p, AMOVL, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0);
- p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0);
- p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
- p = appendpp(p, ASTOSL, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0);
- }
- return p;
-}
-
-static Prog*
-appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset)
-{
- Prog *q;
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.reg = freg;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.reg = treg;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-void
-clearfat(Node *nl)
-{
- uint32 w, c, q;
- Node n1, z;
- Prog *p;
-
- /* clear a fat object */
- if(debug['g'])
- dump("\nclearfat", nl);
-
- w = nl->type->width;
- // Avoid taking the address for simple enough types.
- if(componentgen(N, nl))
- return;
-
- c = w % 4; // bytes
- q = w / 4; // quads
-
- if(q < 4) {
- // Write sequence of MOV 0, off(base) instead of using STOSL.
- // The hope is that although the code will be slightly longer,
- // the MOVs will have no dependencies and pipeline better
- // than the unrolled STOSL loop.
- // NOTE: Must use agen, not igen, so that optimizer sees address
- // being taken. We are not writing on field boundaries.
- regalloc(&n1, types[tptr], N);
- agen(nl, &n1);
- n1.op = OINDREG;
- nodconst(&z, types[TUINT64], 0);
- while(q-- > 0) {
- n1.type = z.type;
- gins(AMOVL, &z, &n1);
- n1.xoffset += 4;
- }
- nodconst(&z, types[TUINT8], 0);
- while(c-- > 0) {
- n1.type = z.type;
- gins(AMOVB, &z, &n1);
- n1.xoffset++;
- }
- regfree(&n1);
- return;
- }
-
- nodreg(&n1, types[tptr], REG_DI);
- agen(nl, &n1);
- gconreg(AMOVL, 0, REG_AX);
-
- if(q > 128 || (q >= 4 && nacl)) {
- gconreg(AMOVL, q, REG_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSL, N, N); // STOL AL,*(DI)+
- } else if(q >= 4) {
- p = gins(ADUFFZERO, N, N);
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
- // 1 and 128 = magic constants: see ../../runtime/asm_386.s
- p->to.offset = 1*(128-q);
- } else
- while(q > 0) {
- gins(ASTOSL, N, N); // STOL AL,*(DI)+
- q--;
- }
-
- while(c > 0) {
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- c--;
- }
-}
-
-/*
- * generate:
- * call f
- * proc=-1 normal call but no return
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- * proc=3 normal call to C pointer (not Go func value)
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node reg, r1, con, stk;
- int32 extra;
-
- if(f->type != T) {
- extra = 0;
- if(proc == 1 || proc == 2)
- extra = 2 * widthptr;
- setmaxarg(f->type, extra);
- }
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- case -1: // normal call but no return
- if(f->op == ONAME && f->class == PFUNC) {
- if(f == deferreturn) {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an x86 NOP that we will have the right line number.
- // x86 NOP 0x90 is really XCHG AX, AX; use that description
- // because the NOP pseudo-instruction will be removed by
- // the linker.
- nodreg(&reg, types[TINT], REG_AX);
- gins(AXCHGL, &reg, &reg);
- }
- p = gins(ACALL, N, f);
- afunclit(&p->to, f);
- if(proc == -1 || noreturn(p))
- gins(AUNDEF, N, N);
- break;
- }
- nodreg(&reg, types[tptr], REG_DX);
- nodreg(&r1, types[tptr], REG_BX);
- gmove(f, &reg);
- reg.op = OINDREG;
- gmove(&reg, &r1);
- reg.op = OREGISTER;
- gins(ACALL, &reg, &r1);
- break;
-
- case 3: // normal call of c function pointer
- gins(ACALL, N, f);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- memset(&stk, 0, sizeof(stk));
- stk.op = OINDREG;
- stk.val.u.reg = REG_SP;
- stk.xoffset = 0;
-
- // size of arguments at 0(SP)
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(AMOVL, &con, &stk);
-
- // FuncVal* at 4(SP)
- stk.xoffset = widthptr;
- gins(AMOVL, f, &stk);
-
- if(proc == 1)
- ginscall(newproc, 0);
- else
- ginscall(deferproc, 0);
- if(proc == 2) {
- nodreg(&reg, types[TINT32], REG_AX);
- gins(ATESTL, &reg, &reg);
- p = gbranch(AJEQ, T, +1);
- cgen_ret(N);
- patch(p, pc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- Node *i, *f;
- Node tmpi, nodi, nodo, nodr, nodsp;
-
- i = n->left;
- if(i->op != ODOTINTER)
- fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
- f = i->right; // field
- if(f->op != ONAME)
- fatal("cgen_callinter: not ONAME %O", f->op);
-
- i = i->left; // interface
-
- if(!i->addable) {
- tempname(&tmpi, i->type);
- cgen(i, &tmpi);
- i = &tmpi;
- }
-
- genlist(n->list); // assign the args
-
- // i is now addable, prepare an indirected
- // register to hold its address.
- igen(i, &nodi, res); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], REG_SP);
- nodsp.xoffset = 0;
- if(proc != 0)
- nodsp.xoffset += 2 * widthptr; // leave room for size & fn
- nodi.type = types[tptr];
- nodi.xoffset += widthptr;
- cgen(&nodi, &nodsp); // {0 or 8}(SP) = 4(REG) -- i.data
-
- regalloc(&nodo, types[tptr], res);
- nodi.type = types[tptr];
- nodi.xoffset -= widthptr;
- cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab
- regfree(&nodi);
-
- regalloc(&nodr, types[tptr], &nodo);
- if(n->left->xoffset == BADWIDTH)
- fatal("cgen_callinter: badwidth");
- cgen_checknil(&nodo);
- nodo.op = OINDREG;
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
-
- if(proc == 0) {
- // plain call: use direct c function pointer - more efficient
- cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
- proc = 3;
- } else {
- // go/defer. generate go func value.
- gins(ALEAL, &nodo, &nodr); // REG = &(20+offset(REG)) -- i.tab->fun[f]
- }
-
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-}
-
-/*
- * generate function call;
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_call(Node *n, int proc)
-{
- Type *t;
- Node nod, afun;
-
- if(n == N)
- return;
-
- if(n->left->ullman >= UINF) {
- // if name involves a fn call
- // precompute the address of the fn
- tempname(&afun, types[tptr]);
- cgen(n->left, &afun);
- }
-
- genlist(n->list); // assign the args
- t = n->left->type;
-
- // call tempname pointer
- if(n->left->ullman >= UINF) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, &afun);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call pointer
- if(n->left->op != ONAME || n->left->class != PFUNC) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, n->left);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = return value from call.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
- Node nod;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(t->etype == TPTR32 || t->etype == TPTR64)
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_callret: nil");
-
- memset(&nod, 0, sizeof(nod));
- nod.op = OINDREG;
- nod.val.u.reg = REG_SP;
- nod.addable = 1;
-
- nod.xoffset = fp->width;
- nod.type = fp->type;
- cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
- Node nod1, nod2;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_aret: nil");
-
- memset(&nod1, 0, sizeof(nod1));
- nod1.op = OINDREG;
- nod1.val.u.reg = REG_SP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width;
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- gins(ALEAL, &nod1, &nod2);
- gins(AMOVL, &nod2, res);
- regfree(&nod2);
- } else
- gins(ALEAL, &nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- Prog *p;
-
- if(n != N)
- genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- genlist(curfn->exit);
- p = gins(ARET, N, N);
- if(n != N && n->op == ORETJMP) {
- p->to.type = TYPE_MEM;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(n->left->sym);
- }
-}
-
-/*
- * generate division.
- * caller must set:
- * ax = allocated AX register
- * dx = allocated DX register
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
-{
- int check;
- Node n1, t1, t2, t3, t4, n4, nz;
- Type *t, *t0;
- Prog *p1, *p2;
-
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will trap.
- // Also the byte divide instruction needs AH,
- // which we otherwise don't have to deal with.
- // Easiest way to avoid for int8, int16: use int32.
- // For int32 and int64, use explicit test.
- // Could use int64 hw for int32.
- t = nl->type;
- t0 = t;
- check = 0;
- if(issigned[t->etype]) {
- check = 1;
- if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
- check = 0;
- else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
- check = 0;
- }
- if(t->width < 4) {
- if(issigned[t->etype])
- t = types[TINT32];
- else
- t = types[TUINT32];
- check = 0;
- }
-
- tempname(&t1, t);
- tempname(&t2, t);
- if(t0 != t) {
- tempname(&t3, t0);
- tempname(&t4, t0);
- cgen(nl, &t3);
- cgen(nr, &t4);
- // Convert.
- gmove(&t3, &t1);
- gmove(&t4, &t2);
- } else {
- cgen(nl, &t1);
- cgen(nr, &t2);
- }
-
- if(!samereg(ax, res) && !samereg(dx, res))
- regalloc(&n1, t, res);
- else
- regalloc(&n1, t, N);
- gmove(&t2, &n1);
- gmove(&t1, ax);
- p2 = P;
- if(nacl) {
- // Native Client does not relay the divide-by-zero trap
- // to the executing program, so we must insert a check
- // for ourselves.
- nodconst(&n4, t, 0);
- gins(optoas(OCMP, t), &n1, &n4);
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(panicdiv == N)
- panicdiv = sysfunc("panicdivide");
- ginscall(panicdiv, -1);
- patch(p1, pc);
- }
- if(check) {
- nodconst(&n4, t, -1);
- gins(optoas(OCMP, t), &n1, &n4);
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(op == ODIV) {
- // a / (-1) is -a.
- gins(optoas(OMINUS, t), N, ax);
- gmove(ax, res);
- } else {
- // a % (-1) is 0.
- nodconst(&n4, t, 0);
- gmove(&n4, res);
- }
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- }
- if(!issigned[t->etype]) {
- nodconst(&nz, t, 0);
- gmove(&nz, dx);
- } else
- gins(optoas(OEXTEND, t), N, N);
- gins(optoas(op, t), &n1, N);
- regfree(&n1);
-
- if(op == ODIV)
- gmove(ax, res);
- else
- gmove(dx, res);
- if(check)
- patch(p2, pc);
-}
-
-static void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
- int r;
-
- r = reg[dr];
- nodreg(x, types[TINT32], dr);
-
- // save current ax and dx if they are live
- // and not the destination
- memset(oldx, 0, sizeof *oldx);
- if(r > 0 && !samereg(x, res)) {
- tempname(oldx, types[TINT32]);
- gmove(x, oldx);
- }
-
- regalloc(x, t, x);
-}
-
-static void
-restx(Node *x, Node *oldx)
-{
- regfree(x);
-
- if(oldx->op != 0) {
- x->type = types[TINT32];
- gmove(oldx, x);
- }
-}
-
-/*
- * generate division according to op, one of:
- * res = nl / nr
- * res = nl % nr
- */
-void
-cgen_div(int op, Node *nl, Node *nr, Node *res)
-{
- Node ax, dx, oldax, olddx;
- Type *t;
-
- if(is64(nl->type))
- fatal("cgen_div %T", nl->type);
-
- if(issigned[nl->type->etype])
- t = types[TINT32];
- else
- t = types[TUINT32];
- savex(REG_AX, &ax, &oldax, res, t);
- savex(REG_DX, &dx, &olddx, res, t);
- dodiv(op, nl, nr, res, &ax, &dx);
- restx(&dx, &olddx);
- restx(&ax, &oldax);
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, nt, cx, oldcx, hi, lo;
- int a, w;
- Prog *p1, *p2;
- uvlong sc;
-
- if(nl->type->width > 4)
- fatal("cgen_shift %T", nl->type);
-
- w = nl->type->width * 8;
-
- a = optoas(op, nl->type);
-
- if(nr->op == OLITERAL) {
- tempname(&n2, nl->type);
- cgen(nl, &n2);
- regalloc(&n1, nl->type, res);
- gmove(&n2, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc >= nl->type->width*8) {
- // large shift gets 2 shifts by width-1
- gins(a, ncon(w-1), &n1);
- gins(a, ncon(w-1), &n1);
- } else
- gins(a, nr, &n1);
- gmove(&n1, res);
- regfree(&n1);
- return;
- }
-
- memset(&oldcx, 0, sizeof oldcx);
- nodreg(&cx, types[TUINT32], REG_CX);
- if(reg[REG_CX] > 1 && !samereg(&cx, res)) {
- tempname(&oldcx, types[TUINT32]);
- gmove(&cx, &oldcx);
- }
-
- if(nr->type->width > 4) {
- tempname(&nt, nr->type);
- n1 = nt;
- } else {
- nodreg(&n1, types[TUINT32], REG_CX);
- regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
- }
-
- if(samereg(&cx, res))
- regalloc(&n2, nl->type, N);
- else
- regalloc(&n2, nl->type, res);
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &n2);
- cgen(nr, &n1);
- } else {
- cgen(nr, &n1);
- cgen(nl, &n2);
- }
-
- // test and fix up large shifts
- if(bounded) {
- if(nr->type->width > 4) {
- // delayed reg alloc
- nodreg(&n1, types[TUINT32], REG_CX);
- regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX
- split64(&nt, &lo, &hi);
- gmove(&lo, &n1);
- splitclean();
- }
- } else {
- if(nr->type->width > 4) {
- // delayed reg alloc
- nodreg(&n1, types[TUINT32], REG_CX);
- regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX
- split64(&nt, &lo, &hi);
- gmove(&lo, &n1);
- gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
- p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1);
- gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- splitclean();
- patch(p2, pc);
- } else {
- gins(optoas(OCMP, nr->type), &n1, ncon(w));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
- }
- if(op == ORSH && issigned[nl->type->etype]) {
- gins(a, ncon(w-1), &n2);
- } else {
- gmove(ncon(0), &n2);
- }
- patch(p1, pc);
- }
- gins(a, &n1, &n2);
-
- if(oldcx.op != 0)
- gmove(&oldcx, &cx);
-
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, nt, *tmp;
- Type *t;
- int a;
-
- // copy from byte to full registers
- t = types[TUINT32];
- if(issigned[nl->type->etype])
- t = types[TINT32];
-
- // largest ullman on left.
- if(nl->ullman < nr->ullman) {
- tmp = nl;
- nl = nr;
- nr = tmp;
- }
-
- tempname(&nt, nl->type);
- cgen(nl, &nt);
- regalloc(&n1, t, res);
- cgen(nr, &n1);
- regalloc(&n2, t, N);
- gmove(&nt, &n2);
- a = optoas(op, t);
- gins(a, &n2, &n1);
- regfree(&n2);
- gmove(&n1, res);
- regfree(&n1);
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
- Type *t;
- int a;
- Node n1, n2, ax, dx;
-
- t = nl->type;
- a = optoas(OHMUL, t);
- // gen nl in n1.
- tempname(&n1, t);
- cgen(nl, &n1);
- // gen nr in n2.
- regalloc(&n2, t, res);
- cgen(nr, &n2);
-
- // multiply.
- nodreg(&ax, t, REG_AX);
- gmove(&n2, &ax);
- gins(a, &n1, N);
- regfree(&n2);
-
- if(t->width == 1) {
- // byte multiply behaves differently.
- nodreg(&ax, t, REG_AH);
- nodreg(&dx, t, REG_DX);
- gmove(&ax, &dx);
- }
- nodreg(&dx, t, REG_DX);
- gmove(&dx, res);
-}
-
-static void cgen_float387(Node *n, Node *res);
-static void cgen_floatsse(Node *n, Node *res);
-
-/*
- * generate floating-point operation.
- */
-void
-cgen_float(Node *n, Node *res)
-{
- Node *nl;
- Node n1, n2;
- Prog *p1, *p2, *p3;
-
- nl = n->left;
- switch(n->op) {
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- p1 = gbranch(AJMP, T, 0);
- p2 = pc;
- gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n, 1, 0, p2);
- gmove(nodbool(0), res);
- patch(p3, pc);
- return;
-
- case OPLUS:
- cgen(nl, res);
- return;
-
- case OCONV:
- if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
- cgen(nl, res);
- return;
- }
-
- tempname(&n2, n->type);
- mgen(nl, &n1, res);
- gmove(&n1, &n2);
- gmove(&n2, res);
- mfree(&n1);
- return;
- }
-
- if(use_sse)
- cgen_floatsse(n, res);
- else
- cgen_float387(n, res);
-}
-
-// floating-point. 387 (not SSE2)
-static void
-cgen_float387(Node *n, Node *res)
-{
- Node f0, f1;
- Node *nl, *nr;
-
- nl = n->left;
- nr = n->right;
- nodreg(&f0, nl->type, REG_F0);
- nodreg(&f1, n->type, REG_F0+1);
- if(nr != N)
- goto flt2;
-
- // unary
- cgen(nl, &f0);
- if(n->op != OCONV && n->op != OPLUS)
- gins(foptoas(n->op, n->type, 0), N, N);
- gmove(&f0, res);
- return;
-
-flt2: // binary
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &f0);
- if(nr->addable)
- gins(foptoas(n->op, n->type, 0), nr, &f0);
- else {
- cgen(nr, &f0);
- gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
- }
- } else {
- cgen(nr, &f0);
- if(nl->addable)
- gins(foptoas(n->op, n->type, Frev), nl, &f0);
- else {
- cgen(nl, &f0);
- gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
- }
- }
- gmove(&f0, res);
- return;
-
-}
-
-static void
-cgen_floatsse(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2, nt;
- int a;
-
- nl = n->left;
- nr = n->right;
- switch(n->op) {
- default:
- dump("cgen_floatsse", n);
- fatal("cgen_floatsse %O", n->op);
- return;
-
- case OMINUS:
- case OCOM:
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- a = foptoas(OMUL, nl->type, 0);
- goto sbop;
-
- // symmetric binary
- case OADD:
- case OMUL:
- a = foptoas(n->op, nl->type, 0);
- goto sbop;
-
- // asymmetric binary
- case OSUB:
- case OMOD:
- case ODIV:
- a = foptoas(n->op, nl->type, 0);
- goto abop;
- }
-
-sbop: // symmetric binary
- if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
- r = nl;
- nl = nr;
- nr = r;
- }
-
-abop: // asymmetric binary
- if(nl->ullman >= nr->ullman) {
- tempname(&nt, nl->type);
- cgen(nl, &nt);
- mgen(nr, &n2, N);
- regalloc(&n1, nl->type, res);
- gmove(&nt, &n1);
- gins(a, &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- mfree(&n2);
- } else {
- regalloc(&n2, nr->type, res);
- cgen(nr, &n2);
- regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
- gins(a, &n2, &n1);
- regfree(&n2);
- gmove(&n1, res);
- regfree(&n1);
- }
- return;
-}
-
-void
-bgen_float(Node *n, int true, int likely, Prog *to)
-{
- int et, a;
- Node *nl, *nr, *r;
- Node n1, n2, n3, tmp, t1, t2, ax;
- Prog *p1, *p2;
-
- nl = n->left;
- nr = n->right;
- a = n->op;
- if(!true) {
- // brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- // No need to avoid re-genning ninit.
- bgen_float(n, 1, -likely, p2);
- patch(gbranch(AJMP, T, 0), to);
- patch(p2, pc);
- return;
- }
-
- if(use_sse)
- goto sse;
- else
- goto x87;
-
-x87:
- a = brrev(a); // because the args are stacked
- if(a == OGE || a == OGT) {
- // only < and <= work right with NaN; reverse if needed
- r = nr;
- nr = nl;
- nl = r;
- a = brrev(a);
- }
-
- nodreg(&tmp, nr->type, REG_F0);
- nodreg(&n2, nr->type, REG_F0 + 1);
- nodreg(&ax, types[TUINT16], REG_AX);
- et = simsimtype(nr->type);
- if(et == TFLOAT64) {
- if(nl->ullman > nr->ullman) {
- cgen(nl, &tmp);
- cgen(nr, &tmp);
- gins(AFXCHD, &tmp, &n2);
- } else {
- cgen(nr, &tmp);
- cgen(nl, &tmp);
- }
- gins(AFUCOMIP, &tmp, &n2);
- gins(AFMOVDP, &tmp, &tmp); // annoying pop but still better than STSW+SAHF
- } else {
- // TODO(rsc): The moves back and forth to memory
- // here are for truncating the value to 32 bits.
- // This handles 32-bit comparison but presumably
- // all the other ops have the same problem.
- // We need to figure out what the right general
- // solution is, besides telling people to use float64.
- tempname(&t1, types[TFLOAT32]);
- tempname(&t2, types[TFLOAT32]);
- cgen(nr, &t1);
- cgen(nl, &t2);
- gmove(&t2, &tmp);
- gins(AFCOMFP, &t1, &tmp);
- gins(AFSTSW, N, &ax);
- gins(ASAHF, N, N);
- }
-
- goto ret;
-
-sse:
- if(!nl->addable) {
- tempname(&n1, nl->type);
- cgen(nl, &n1);
- nl = &n1;
- }
- if(!nr->addable) {
- tempname(&tmp, nr->type);
- cgen(nr, &tmp);
- nr = &tmp;
- }
- regalloc(&n2, nr->type, N);
- gmove(nr, &n2);
- nr = &n2;
-
- if(nl->op != OREGISTER) {
- regalloc(&n3, nl->type, N);
- gmove(nl, &n3);
- nl = &n3;
- }
-
- if(a == OGE || a == OGT) {
- // only < and <= work right with NaN; reverse if needed
- r = nr;
- nr = nl;
- nl = r;
- a = brrev(a);
- }
-
- gins(foptoas(OCMP, nr->type, 0), nl, nr);
- if(nl->op == OREGISTER)
- regfree(nl);
- regfree(nr);
-
-ret:
- if(a == OEQ) {
- // neither NE nor P
- p1 = gbranch(AJNE, T, -likely);
- p2 = gbranch(AJPS, T, -likely);
- patch(gbranch(AJMP, T, 0), to);
- patch(p1, pc);
- patch(p2, pc);
- } else if(a == ONE) {
- // either NE or P
- patch(gbranch(AJNE, T, likely), to);
- patch(gbranch(AJPS, T, likely), to);
- } else
- patch(gbranch(optoas(a, nr->type), T, likely), to);
-
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
- Prog *p, *p1, *p2;
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as != ACHECKNIL)
- continue;
- if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
- warnl(p->lineno, "generated nil check");
- // check is
- // CMP arg, $0
- // JNE 2(PC) (likely)
- // MOV AX, 0
- p1 = mal(sizeof *p1);
- p2 = mal(sizeof *p2);
- clearp(p1);
- clearp(p2);
- p1->link = p2;
- p2->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
- p2->lineno = p->lineno;
- p1->pc = 9999;
- p2->pc = 9999;
- p->as = ACMPL;
- p->to.type = TYPE_CONST;
- p->to.offset = 0;
- p1->as = AJNE;
- p1->from.type = TYPE_CONST;
- p1->from.offset = 1; // likely
- p1->to.type = TYPE_BRANCH;
- p1->to.u.branch = p2->link;
- // crash by write to memory address 0.
- // if possible, since we know arg is 0, use 0(arg),
- // which will be shorter to encode than plain 0.
- p2->as = AMOVL;
- p2->from.type = TYPE_REG;
- p2->from.reg = REG_AX;
- if(regtyp(&p->from)) {
- p2->to.type = TYPE_MEM;
- p2->to.reg = p->from.reg;
- } else
- p2->to.type = TYPE_MEM;
- p2->to.offset = 0;
- }
-}
diff --git a/src/cmd/new8g/ggen.go b/src/cmd/8g/ggen.go
index f72beda21a..f72beda21a 100644
--- a/src/cmd/new8g/ggen.go
+++ b/src/cmd/8g/ggen.go
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
deleted file mode 100644
index b82f7622ef..0000000000
--- a/src/cmd/8g/gsubr.c
+++ /dev/null
@@ -1,1874 +0,0 @@
-// Derived from Inferno utils/8c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "../../runtime/funcdata.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 8l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-uint32 unmappedzero = 4096;
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int);*/
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
- int a;
-
- if(t == T)
- fatal("optoas: t is nil");
-
- a = AXXX;
- switch(CASE(op, simtype[t->etype])) {
- default:
- fatal("optoas: no entry %O-%T", op, t);
- break;
-
- case CASE(OADDR, TPTR32):
- a = ALEAL;
- 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 = AJEQ;
- 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 = AJNE;
- break;
-
- case CASE(OLT, TINT8):
- case CASE(OLT, TINT16):
- case CASE(OLT, TINT32):
- case CASE(OLT, TINT64):
- a = AJLT;
- break;
-
- case CASE(OLT, TUINT8):
- case CASE(OLT, TUINT16):
- case CASE(OLT, TUINT32):
- case CASE(OLT, TUINT64):
- a = AJCS;
- break;
-
- case CASE(OLE, TINT8):
- case CASE(OLE, TINT16):
- case CASE(OLE, TINT32):
- case CASE(OLE, TINT64):
- a = AJLE;
- break;
-
- case CASE(OLE, TUINT8):
- case CASE(OLE, TUINT16):
- case CASE(OLE, TUINT32):
- case CASE(OLE, TUINT64):
- a = AJLS;
- break;
-
- case CASE(OGT, TINT8):
- case CASE(OGT, TINT16):
- case CASE(OGT, TINT32):
- case CASE(OGT, TINT64):
- a = AJGT;
- break;
-
- case CASE(OGT, TUINT8):
- case CASE(OGT, TUINT16):
- case CASE(OGT, TUINT32):
- case CASE(OGT, TUINT64):
- case CASE(OLT, TFLOAT32):
- case CASE(OLT, TFLOAT64):
- a = AJHI;
- break;
-
- case CASE(OGE, TINT8):
- case CASE(OGE, TINT16):
- case CASE(OGE, TINT32):
- case CASE(OGE, TINT64):
- a = AJGE;
- break;
-
- case CASE(OGE, TUINT8):
- case CASE(OGE, TUINT16):
- case CASE(OGE, TUINT32):
- case CASE(OGE, TUINT64):
- case CASE(OLE, TFLOAT32):
- case CASE(OLE, TFLOAT64):
- a = AJCC;
- break;
-
- case CASE(OCMP, TBOOL):
- case CASE(OCMP, TINT8):
- case CASE(OCMP, TUINT8):
- a = ACMPB;
- break;
-
- case CASE(OCMP, TINT16):
- case CASE(OCMP, TUINT16):
- a = ACMPW;
- break;
-
- case CASE(OCMP, TINT32):
- case CASE(OCMP, TUINT32):
- case CASE(OCMP, TPTR32):
- a = ACMPL;
- break;
-
- case CASE(OAS, TBOOL):
- case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(OAS, TINT32):
- case CASE(OAS, TUINT32):
- case CASE(OAS, TPTR32):
- a = AMOVL;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(OADD, TINT8):
- case CASE(OADD, TUINT8):
- a = AADDB;
- break;
-
- case CASE(OADD, TINT16):
- case CASE(OADD, TUINT16):
- a = AADDW;
- break;
-
- case CASE(OADD, TINT32):
- case CASE(OADD, TUINT32):
- case CASE(OADD, TPTR32):
- a = AADDL;
- break;
-
- case CASE(OSUB, TINT8):
- case CASE(OSUB, TUINT8):
- a = ASUBB;
- break;
-
- case CASE(OSUB, TINT16):
- case CASE(OSUB, TUINT16):
- a = ASUBW;
- break;
-
- case CASE(OSUB, TINT32):
- case CASE(OSUB, TUINT32):
- case CASE(OSUB, TPTR32):
- a = ASUBL;
- break;
-
- case CASE(OINC, TINT8):
- case CASE(OINC, TUINT8):
- a = AINCB;
- break;
-
- case CASE(OINC, TINT16):
- case CASE(OINC, TUINT16):
- a = AINCW;
- break;
-
- case CASE(OINC, TINT32):
- case CASE(OINC, TUINT32):
- case CASE(OINC, TPTR32):
- a = AINCL;
- break;
-
- case CASE(ODEC, TINT8):
- case CASE(ODEC, TUINT8):
- a = ADECB;
- break;
-
- case CASE(ODEC, TINT16):
- case CASE(ODEC, TUINT16):
- a = ADECW;
- break;
-
- case CASE(ODEC, TINT32):
- case CASE(ODEC, TUINT32):
- case CASE(ODEC, TPTR32):
- a = ADECL;
- break;
-
- case CASE(OCOM, TINT8):
- case CASE(OCOM, TUINT8):
- a = ANOTB;
- break;
-
- case CASE(OCOM, TINT16):
- case CASE(OCOM, TUINT16):
- a = ANOTW;
- break;
-
- case CASE(OCOM, TINT32):
- case CASE(OCOM, TUINT32):
- case CASE(OCOM, TPTR32):
- a = ANOTL;
- break;
-
- case CASE(OMINUS, TINT8):
- case CASE(OMINUS, TUINT8):
- a = ANEGB;
- break;
-
- case CASE(OMINUS, TINT16):
- case CASE(OMINUS, TUINT16):
- a = ANEGW;
- break;
-
- case CASE(OMINUS, TINT32):
- case CASE(OMINUS, TUINT32):
- case CASE(OMINUS, TPTR32):
- a = ANEGL;
- break;
-
- case CASE(OAND, TINT8):
- case CASE(OAND, TUINT8):
- a = AANDB;
- break;
-
- case CASE(OAND, TINT16):
- case CASE(OAND, TUINT16):
- a = AANDW;
- break;
-
- case CASE(OAND, TINT32):
- case CASE(OAND, TUINT32):
- case CASE(OAND, TPTR32):
- a = AANDL;
- break;
-
- case CASE(OOR, TINT8):
- case CASE(OOR, TUINT8):
- a = AORB;
- break;
-
- case CASE(OOR, TINT16):
- case CASE(OOR, TUINT16):
- a = AORW;
- break;
-
- case CASE(OOR, TINT32):
- case CASE(OOR, TUINT32):
- case CASE(OOR, TPTR32):
- a = AORL;
- break;
-
- case CASE(OXOR, TINT8):
- case CASE(OXOR, TUINT8):
- a = AXORB;
- break;
-
- case CASE(OXOR, TINT16):
- case CASE(OXOR, TUINT16):
- a = AXORW;
- break;
-
- case CASE(OXOR, TINT32):
- case CASE(OXOR, TUINT32):
- case CASE(OXOR, TPTR32):
- a = AXORL;
- break;
-
- case CASE(OLROT, TINT8):
- case CASE(OLROT, TUINT8):
- a = AROLB;
- break;
-
- case CASE(OLROT, TINT16):
- case CASE(OLROT, TUINT16):
- a = AROLW;
- break;
-
- case CASE(OLROT, TINT32):
- case CASE(OLROT, TUINT32):
- case CASE(OLROT, TPTR32):
- a = AROLL;
- break;
-
- case CASE(OLSH, TINT8):
- case CASE(OLSH, TUINT8):
- a = ASHLB;
- break;
-
- case CASE(OLSH, TINT16):
- case CASE(OLSH, TUINT16):
- a = ASHLW;
- break;
-
- case CASE(OLSH, TINT32):
- case CASE(OLSH, TUINT32):
- case CASE(OLSH, TPTR32):
- a = ASHLL;
- break;
-
- case CASE(ORSH, TUINT8):
- a = ASHRB;
- break;
-
- case CASE(ORSH, TUINT16):
- a = ASHRW;
- break;
-
- case CASE(ORSH, TUINT32):
- case CASE(ORSH, TPTR32):
- a = ASHRL;
- break;
-
- case CASE(ORSH, TINT8):
- a = ASARB;
- break;
-
- case CASE(ORSH, TINT16):
- a = ASARW;
- break;
-
- case CASE(ORSH, TINT32):
- a = ASARL;
- break;
-
- case CASE(OHMUL, TINT8):
- case CASE(OMUL, TINT8):
- case CASE(OMUL, TUINT8):
- a = AIMULB;
- break;
-
- case CASE(OHMUL, TINT16):
- case CASE(OMUL, TINT16):
- case CASE(OMUL, TUINT16):
- a = AIMULW;
- break;
-
- case CASE(OHMUL, TINT32):
- case CASE(OMUL, TINT32):
- case CASE(OMUL, TUINT32):
- case CASE(OMUL, TPTR32):
- a = AIMULL;
- break;
-
- case CASE(OHMUL, TUINT8):
- a = AMULB;
- break;
-
- case CASE(OHMUL, TUINT16):
- a = AMULW;
- break;
-
- case CASE(OHMUL, TUINT32):
- case CASE(OHMUL, TPTR32):
- a = AMULL;
- break;
-
- case CASE(ODIV, TINT8):
- case CASE(OMOD, TINT8):
- a = AIDIVB;
- break;
-
- case CASE(ODIV, TUINT8):
- case CASE(OMOD, TUINT8):
- a = ADIVB;
- break;
-
- case CASE(ODIV, TINT16):
- case CASE(OMOD, TINT16):
- a = AIDIVW;
- break;
-
- case CASE(ODIV, TUINT16):
- case CASE(OMOD, TUINT16):
- a = ADIVW;
- break;
-
- case CASE(ODIV, TINT32):
- case CASE(OMOD, TINT32):
- a = AIDIVL;
- break;
-
- case CASE(ODIV, TUINT32):
- case CASE(ODIV, TPTR32):
- case CASE(OMOD, TUINT32):
- case CASE(OMOD, TPTR32):
- a = ADIVL;
- break;
-
- case CASE(OEXTEND, TINT16):
- a = ACWD;
- break;
-
- case CASE(OEXTEND, TINT32):
- a = ACDQ;
- break;
- }
- return a;
-}
-
-#define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c))
-/*c2go int FCASE(int, int, int); */
-int
-foptoas(int op, Type *t, int flg)
-{
- int et, a;
-
- a = AXXX;
- et = simtype[t->etype];
-
- if(use_sse)
- goto sse;
-
- // If we need Fpop, it means we're working on
- // two different floating-point registers, not memory.
- // There the instruction only has a float64 form.
- if(flg & Fpop)
- et = TFLOAT64;
-
- // clear Frev if unneeded
- switch(op) {
- case OADD:
- case OMUL:
- flg &= ~Frev;
- break;
- }
-
- switch(FCASE(op, et, flg)) {
- case FCASE(OADD, TFLOAT32, 0):
- return AFADDF;
- case FCASE(OADD, TFLOAT64, 0):
- return AFADDD;
- case FCASE(OADD, TFLOAT64, Fpop):
- return AFADDDP;
-
- case FCASE(OSUB, TFLOAT32, 0):
- return AFSUBF;
- case FCASE(OSUB, TFLOAT32, Frev):
- return AFSUBRF;
-
- case FCASE(OSUB, TFLOAT64, 0):
- return AFSUBD;
- case FCASE(OSUB, TFLOAT64, Frev):
- return AFSUBRD;
- case FCASE(OSUB, TFLOAT64, Fpop):
- return AFSUBDP;
- case FCASE(OSUB, TFLOAT64, Fpop|Frev):
- return AFSUBRDP;
-
- case FCASE(OMUL, TFLOAT32, 0):
- return AFMULF;
- case FCASE(OMUL, TFLOAT64, 0):
- return AFMULD;
- case FCASE(OMUL, TFLOAT64, Fpop):
- return AFMULDP;
-
- case FCASE(ODIV, TFLOAT32, 0):
- return AFDIVF;
- case FCASE(ODIV, TFLOAT32, Frev):
- return AFDIVRF;
-
- case FCASE(ODIV, TFLOAT64, 0):
- return AFDIVD;
- case FCASE(ODIV, TFLOAT64, Frev):
- return AFDIVRD;
- case FCASE(ODIV, TFLOAT64, Fpop):
- return AFDIVDP;
- case FCASE(ODIV, TFLOAT64, Fpop|Frev):
- return AFDIVRDP;
-
- case FCASE(OCMP, TFLOAT32, 0):
- return AFCOMF;
- case FCASE(OCMP, TFLOAT32, Fpop):
- return AFCOMFP;
- case FCASE(OCMP, TFLOAT64, 0):
- return AFCOMD;
- case FCASE(OCMP, TFLOAT64, Fpop):
- return AFCOMDP;
- case FCASE(OCMP, TFLOAT64, Fpop2):
- return AFCOMDPP;
-
- case FCASE(OMINUS, TFLOAT32, 0):
- return AFCHS;
- case FCASE(OMINUS, TFLOAT64, 0):
- return AFCHS;
- }
-
- fatal("foptoas %O %T %#x", op, t, flg);
- return 0;
-
-sse:
- switch(CASE(op, et)) {
- default:
- fatal("foptoas-sse: no entry %O-%T", op, t);
- break;
-
- case CASE(OCMP, TFLOAT32):
- a = AUCOMISS;
- break;
-
- case CASE(OCMP, TFLOAT64):
- a = AUCOMISD;
- break;
-
- case CASE(OAS, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(OAS, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(OADD, TFLOAT32):
- a = AADDSS;
- break;
-
- case CASE(OADD, TFLOAT64):
- a = AADDSD;
- break;
-
- case CASE(OSUB, TFLOAT32):
- a = ASUBSS;
- break;
-
- case CASE(OSUB, TFLOAT64):
- a = ASUBSD;
- break;
-
- case CASE(OMUL, TFLOAT32):
- a = AMULSS;
- break;
-
- case CASE(OMUL, TFLOAT64):
- a = AMULSD;
- break;
-
- case CASE(ODIV, TFLOAT32):
- a = ADIVSS;
- break;
-
- case CASE(ODIV, TFLOAT64):
- a = ADIVSD;
- break;
- }
- return a;
-}
-
-
-static int resvd[] =
-{
-// REG_DI, // for movstring
-// REG_SI, // for movstring
-
- REG_AX, // for divide
- REG_CX, // for shift
- REG_DX, // for divide
- REG_SP, // for stack
-
- REG_BL, // because REG_BX can be allocated
- REG_BH,
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 1;
- for(i=REG_AX; i<=REG_DI; i++)
- reg[i] = 0;
- for(i=REG_X0; i<=REG_X7; i++)
- reg[i] = 0;
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]++;
-}
-
-uintptr regpc[MAXREG];
-
-void
-gclean(void)
-{
- int i;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i]]--;
-
- for(i=REG_AX; i<=REG_DI; i++)
- if(reg[i])
- yyerror("reg %R left allocated at %ux", i, regpc[i]);
- for(i=REG_X0; i<=REG_X7; i++)
- if(reg[i])
- yyerror("reg %R left allocated\n", i);
-}
-
-int
-anyregalloc(void)
-{
- int i, j;
-
- for(i=REG_AX; i<=REG_DI; i++) {
- if(reg[i] == 0)
- goto ok;
- for(j=0; j<nelem(resvd); j++)
- if(resvd[j] == i)
- goto ok;
- return 1;
- ok:;
- }
- for(i=REG_X0; i<=REG_X7; i++)
- if(reg[i])
- return 1;
- 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;
-
- if(t == T)
- fatal("regalloc: t nil");
- et = simtype[t->etype];
-
- switch(et) {
- case TINT64:
- case TUINT64:
- fatal("regalloc64");
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TPTR32:
- case TPTR64:
- case TBOOL:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REG_AX && i <= REG_DI)
- goto out;
- }
- for(i=REG_AX; i<=REG_DI; i++)
- if(reg[i] == 0)
- goto out;
-
- print("registers allocated at\n");
- for(i=REG_AX; i<=REG_DI; i++)
- print("\t%R\t%#lux\n", i, regpc[i]);
- fatal("out of fixed registers");
- goto err;
-
- case TFLOAT32:
- case TFLOAT64:
- if(!use_sse) {
- i = REG_F0;
- goto out;
- }
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= REG_X0 && i <= REG_X7)
- goto out;
- }
- for(i=REG_X0; i<=REG_X7; i++)
- if(reg[i] == 0)
- goto out;
- print("registers allocated at\n");
- for(i=REG_X0; i<=REG_X7; i++)
- print("\t%R\t%#lux\n", i, regpc[i]);
- fatal("out of floating registers");
- }
- yyerror("regalloc: unknown type %T", t);
-
-err:
- nodreg(n, t, 0);
- return;
-
-out:
- if(i == REG_SP)
- print("alloc SP\n");
- if(reg[i] == 0) {
- regpc[i] = (uintptr)getcallerpc(&n);
- if(i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP) {
- dump("regalloc-o", o);
- fatal("regalloc %R", i);
- }
- }
- 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 == REG_SP)
- 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 && (i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP))
- fatal("regfree %R", i);
-}
-
-/*
- * generate
- * as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
- Node n1, n2;
-
- nodconst(&n1, types[TINT64], c);
- nodreg(&n2, types[TINT64], reg);
- gins(as, &n1, &n2);
-}
-
-/*
- * swap node contents
- */
-void
-nswap(Node *a, Node *b)
-{
- Node t;
-
- t = *a;
- *a = *b;
- *b = t;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
- static Node n;
-
- if(n.type == T)
- nodconst(&n, types[TUINT32], 0);
- mpmovecfix(n.val.u.xval, i);
- return &n;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
- Node n1;
- int64 i;
-
- if(!is64(n->type))
- fatal("split64 %T", n->type);
-
- if(nsclean >= nelem(sclean))
- fatal("split64 clean");
- sclean[nsclean].op = OEMPTY;
- nsclean++;
- switch(n->op) {
- default:
- switch(n->op) {
- default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- break;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- n = &n1;
- }
- break;
- case OINDREG:
- // nothing
- break;
- }
- *lo = *n;
- *hi = *n;
- lo->type = types[TUINT32];
- if(n->type->etype == TINT64)
- hi->type = types[TINT32];
- else
- hi->type = types[TUINT32];
- hi->xoffset += 4;
- break;
-
- case OLITERAL:
- convconst(&n1, n->type, &n->val);
- i = mpgetfix(n1.val.u.xval);
- nodconst(lo, types[TUINT32], (uint32)i);
- i >>= 32;
- if(n->type->etype == TINT64)
- nodconst(hi, types[TINT32], (int32)i);
- else
- nodconst(hi, types[TUINT32], (uint32)i);
- break;
- }
-}
-
-void
-splitclean(void)
-{
- if(nsclean <= 0)
- fatal("splitclean");
- nsclean--;
- if(sclean[nsclean].op != OEMPTY)
- regfree(&sclean[nsclean]);
-}
-
-/*
- * set up nodes representing fp constants
- */
-Node zerof;
-Node two64f;
-Node two63f;
-
-void
-bignodes(void)
-{
- static int did;
-
- if(did)
- return;
- did = 1;
-
- two64f = *ncon(0);
- two64f.type = types[TFLOAT64];
- two64f.val.ctype = CTFLT;
- two64f.val.u.fval = mal(sizeof *two64f.val.u.fval);
- mpmovecflt(two64f.val.u.fval, 18446744073709551616.);
-
- two63f = two64f;
- two63f.val.u.fval = mal(sizeof *two63f.val.u.fval);
- mpmovecflt(two63f.val.u.fval, 9223372036854775808.);
-
- zerof = two64f;
- zerof.val.u.fval = mal(sizeof *zerof.val.u.fval);
- mpmovecflt(zerof.val.u.fval, 0);
-}
-
-void
-memname(Node *n, Type *t)
-{
- tempname(n, t);
- strcpy(namebuf, n->sym->name);
- namebuf[0] = '.'; // keep optimizer from registerizing
- n->sym = lookup(namebuf);
- n->orig->sym = n->sym;
-}
-
-static void floatmove(Node *f, Node *t);
-static void floatmove_387(Node *f, Node *t);
-static void floatmove_sse(Node *f, Node *t);
-
-void
-gmove(Node *f, Node *t)
-{
- int a, ft, tt;
- Type *cvt;
- Node r1, r2, flo, fhi, tlo, thi, con;
-
- if(debug['M'])
- print("gmove %N -> %N\n", f, t);
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- cvt = t->type;
-
- if(iscomplex[ft] || iscomplex[tt]) {
- complexmove(f, t);
- return;
- }
- if(isfloat[ft] || isfloat[tt]) {
- floatmove(f, t);
- return;
- }
-
- // cannot have two integer memory operands;
- // except 64-bit, which always copies via registers anyway.
- if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
- goto hard;
-
- // convert constant to desired type
- if(f->op == OLITERAL) {
- convconst(&con, t->type, &f->val);
- f = &con;
- ft = simsimtype(con.type);
- }
-
- // 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:
- goto fatal;
-
- /*
- * integer copy and truncate
- */
- case CASE(TINT8, TINT8): // same size
- case CASE(TINT8, TUINT8):
- case CASE(TUINT8, TINT8):
- case CASE(TUINT8, TUINT8):
- a = AMOVB;
- break;
-
- case CASE(TINT16, TINT8): // truncate
- case CASE(TUINT16, TINT8):
- case CASE(TINT32, TINT8):
- case CASE(TUINT32, TINT8):
- case CASE(TINT16, TUINT8):
- case CASE(TUINT16, TUINT8):
- case CASE(TINT32, TUINT8):
- case CASE(TUINT32, TUINT8):
- a = AMOVB;
- goto rsrc;
-
- case CASE(TINT64, TINT8): // truncate low word
- case CASE(TUINT64, TINT8):
- case CASE(TINT64, TUINT8):
- case CASE(TUINT64, TUINT8):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, REG_AX);
- gmove(&flo, &r1);
- gins(AMOVB, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT16, TINT16): // same size
- case CASE(TINT16, TUINT16):
- case CASE(TUINT16, TINT16):
- case CASE(TUINT16, TUINT16):
- a = AMOVW;
- break;
-
- case CASE(TINT32, TINT16): // truncate
- case CASE(TUINT32, TINT16):
- case CASE(TINT32, TUINT16):
- case CASE(TUINT32, TUINT16):
- a = AMOVW;
- goto rsrc;
-
- case CASE(TINT64, TINT16): // truncate low word
- case CASE(TUINT64, TINT16):
- case CASE(TINT64, TUINT16):
- case CASE(TUINT64, TUINT16):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, REG_AX);
- gmove(&flo, &r1);
- gins(AMOVW, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT32, TINT32): // same size
- case CASE(TINT32, TUINT32):
- case CASE(TUINT32, TINT32):
- case CASE(TUINT32, TUINT32):
- a = AMOVL;
- break;
-
- case CASE(TINT64, TINT32): // truncate
- case CASE(TUINT64, TINT32):
- case CASE(TINT64, TUINT32):
- case CASE(TUINT64, TUINT32):
- split64(f, &flo, &fhi);
- nodreg(&r1, t->type, REG_AX);
- gmove(&flo, &r1);
- gins(AMOVL, &r1, t);
- splitclean();
- return;
-
- case CASE(TINT64, TINT64): // same size
- case CASE(TINT64, TUINT64):
- case CASE(TUINT64, TINT64):
- case CASE(TUINT64, TUINT64):
- split64(f, &flo, &fhi);
- split64(t, &tlo, &thi);
- if(f->op == OLITERAL) {
- gins(AMOVL, &flo, &tlo);
- gins(AMOVL, &fhi, &thi);
- } else {
- nodreg(&r1, types[TUINT32], REG_AX);
- nodreg(&r2, types[TUINT32], REG_DX);
- gins(AMOVL, &flo, &r1);
- gins(AMOVL, &fhi, &r2);
- gins(AMOVL, &r1, &tlo);
- gins(AMOVL, &r2, &thi);
- }
- splitclean();
- splitclean();
- return;
-
- /*
- * integer up-conversions
- */
- case CASE(TINT8, TINT16): // sign extend int8
- case CASE(TINT8, TUINT16):
- a = AMOVBWSX;
- goto rdst;
- case CASE(TINT8, TINT32):
- case CASE(TINT8, TUINT32):
- a = AMOVBLSX;
- goto rdst;
- case CASE(TINT8, TINT64): // convert via int32
- case CASE(TINT8, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT8, TINT16): // zero extend uint8
- case CASE(TUINT8, TUINT16):
- a = AMOVBWZX;
- goto rdst;
- case CASE(TUINT8, TINT32):
- case CASE(TUINT8, TUINT32):
- a = AMOVBLZX;
- goto rdst;
- case CASE(TUINT8, TINT64): // convert via uint32
- case CASE(TUINT8, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT16, TINT32): // sign extend int16
- case CASE(TINT16, TUINT32):
- a = AMOVWLSX;
- goto rdst;
- case CASE(TINT16, TINT64): // convert via int32
- case CASE(TINT16, TUINT64):
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT16, TINT32): // zero extend uint16
- case CASE(TUINT16, TUINT32):
- a = AMOVWLZX;
- goto rdst;
- case CASE(TUINT16, TINT64): // convert via uint32
- case CASE(TUINT16, TUINT64):
- cvt = types[TUINT32];
- goto hard;
-
- case CASE(TINT32, TINT64): // sign extend int32
- case CASE(TINT32, TUINT64):
- split64(t, &tlo, &thi);
- nodreg(&flo, tlo.type, REG_AX);
- nodreg(&fhi, thi.type, REG_DX);
- gmove(f, &flo);
- gins(ACDQ, N, N);
- gins(AMOVL, &flo, &tlo);
- gins(AMOVL, &fhi, &thi);
- splitclean();
- return;
-
- case CASE(TUINT32, TINT64): // zero extend uint32
- case CASE(TUINT32, TUINT64):
- split64(t, &tlo, &thi);
- gmove(f, &tlo);
- gins(AMOVL, ncon(0), &thi);
- splitclean();
- return;
- }
-
- gins(a, f, t);
- return;
-
-rsrc:
- // requires register source
- regalloc(&r1, f->type, t);
- gmove(f, &r1);
- gins(a, &r1, t);
- regfree(&r1);
- 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;
-
-fatal:
- // should not happen
- fatal("gmove %N -> %N", f, t);
-}
-
-static void
-floatmove(Node *f, Node *t)
-{
- Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx;
- Type *cvt;
- int ft, tt;
- Prog *p1, *p2, *p3;
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- cvt = t->type;
-
- // cannot have two floating point memory operands.
- if(isfloat[ft] && isfloat[tt] && ismem(f) && ismem(t))
- goto hard;
-
- // convert constant to desired type
- if(f->op == OLITERAL) {
- convconst(&con, t->type, &f->val);
- f = &con;
- ft = simsimtype(con.type);
-
- // some constants can't move directly to memory.
- if(ismem(t)) {
- // float constants come from memory.
- if(isfloat[tt])
- 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:
- if(use_sse)
- floatmove_sse(f, t);
- else
- floatmove_387(f, t);
- return;
-
- // float to very long integer.
- case CASE(TFLOAT32, TINT64):
- case CASE(TFLOAT64, TINT64):
- if(f->op == OREGISTER) {
- cvt = f->type;
- goto hardmem;
- }
- nodreg(&r1, types[ft], REG_F0);
- if(ft == TFLOAT32)
- gins(AFMOVF, f, &r1);
- else
- gins(AFMOVD, f, &r1);
-
- // set round to zero mode during conversion
- memname(&t1, types[TUINT16]);
- memname(&t2, types[TUINT16]);
- gins(AFSTCW, N, &t1);
- gins(AMOVW, ncon(0xf7f), &t2);
- gins(AFLDCW, &t2, N);
- if(tt == TINT16)
- gins(AFMOVWP, &r1, t);
- else if(tt == TINT32)
- gins(AFMOVLP, &r1, t);
- else
- gins(AFMOVVP, &r1, t);
- gins(AFLDCW, &t1, N);
- return;
-
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- if(!ismem(f)) {
- cvt = f->type;
- goto hardmem;
- }
- bignodes();
- nodreg(&f0, types[ft], REG_F0);
- nodreg(&f1, types[ft], REG_F0 + 1);
- nodreg(&ax, types[TUINT16], REG_AX);
-
- if(ft == TFLOAT32)
- gins(AFMOVF, f, &f0);
- else
- gins(AFMOVD, f, &f0);
-
- // if 0 > v { answer = 0 }
- gins(AFMOVD, &zerof, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p1 = gbranch(optoas(OGT, types[tt]), T, 0);
- // if 1<<64 <= v { answer = 0 too }
- gins(AFMOVD, &two64f, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OGT, types[tt]), T, 0);
- patch(p1, pc);
- gins(AFMOVVP, &f0, t); // don't care about t, but will pop the stack
- split64(t, &tlo, &thi);
- gins(AMOVL, ncon(0), &tlo);
- gins(AMOVL, ncon(0), &thi);
- splitclean();
- p1 = gbranch(AJMP, T, 0);
- patch(p2, pc);
-
- // in range; algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
-
- // set round to zero mode during conversion
- memname(&t1, types[TUINT16]);
- memname(&t2, types[TUINT16]);
- gins(AFSTCW, N, &t1);
- gins(AMOVW, ncon(0xf7f), &t2);
- gins(AFLDCW, &t2, N);
-
- // actual work
- gins(AFMOVD, &two63f, &f0);
- gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OLE, types[tt]), T, 0);
- gins(AFMOVVP, &f0, t);
- p3 = gbranch(AJMP, T, 0);
- patch(p2, pc);
- gins(AFMOVD, &two63f, &f0);
- gins(AFSUBDP, &f0, &f1);
- gins(AFMOVVP, &f0, t);
- split64(t, &tlo, &thi);
- gins(AXORL, ncon(0x80000000), &thi); // + 2^63
- patch(p3, pc);
- splitclean();
- // restore rounding mode
- gins(AFLDCW, &t1, N);
-
- patch(p1, pc);
- return;
-
- /*
- * integer to float
- */
- case CASE(TINT64, TFLOAT32):
- case CASE(TINT64, TFLOAT64):
- if(t->op == OREGISTER)
- goto hardmem;
- nodreg(&f0, t->type, REG_F0);
- gins(AFMOVV, f, &f0);
- if(tt == TFLOAT32)
- gins(AFMOVFP, &f0, t);
- else
- gins(AFMOVDP, &f0, t);
- return;
-
- case CASE(TUINT64, TFLOAT32):
- case CASE(TUINT64, TFLOAT64):
- // algorithm is:
- // if small enough, use native int64 -> float64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- nodreg(&ax, types[TUINT32], REG_AX);
- nodreg(&dx, types[TUINT32], REG_DX);
- nodreg(&cx, types[TUINT32], REG_CX);
- tempname(&t1, f->type);
- split64(&t1, &tlo, &thi);
- gmove(f, &t1);
- gins(ACMPL, &thi, ncon(0));
- p1 = gbranch(AJLT, T, 0);
- // native
- nodreg(&r1, types[tt], REG_F0);
- gins(AFMOVV, &t1, &r1);
- if(tt == TFLOAT32)
- gins(AFMOVFP, &r1, t);
- else
- gins(AFMOVDP, &r1, t);
- p2 = gbranch(AJMP, T, 0);
- // simulated
- patch(p1, pc);
- gmove(&tlo, &ax);
- gmove(&thi, &dx);
- p1 = gins(ASHRL, ncon(1), &ax);
- p1->from.index = REG_DX; // double-width shift DX -> AX
- p1->from.scale = 0;
- gins(AMOVL, ncon(0), &cx);
- gins(ASETCC, N, &cx);
- gins(AORL, &cx, &ax);
- gins(ASHRL, ncon(1), &dx);
- gmove(&dx, &thi);
- gmove(&ax, &tlo);
- nodreg(&r1, types[tt], REG_F0);
- nodreg(&r2, types[tt], REG_F0 + 1);
- gins(AFMOVV, &t1, &r1);
- gins(AFMOVD, &r1, &r1);
- gins(AFADDDP, &r1, &r2);
- if(tt == TFLOAT32)
- gins(AFMOVFP, &r1, t);
- else
- gins(AFMOVDP, &r1, t);
- patch(p2, pc);
- splitclean();
- return;
- }
-
-hard:
- // requires register intermediate
- regalloc(&r1, cvt, t);
- gmove(f, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-
-hardmem:
- // requires memory intermediate
- tempname(&r1, cvt);
- gmove(f, &r1);
- gmove(&r1, t);
- return;
-}
-
-static void
-floatmove_387(Node *f, Node *t)
-{
- Node r1, t1, t2;
- Type *cvt;
- Prog *p1, *p2, *p3;
- int a, ft, tt;
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- cvt = t->type;
-
- switch(CASE(ft, tt)) {
- default:
- goto fatal;
-
- /*
- * float to integer
- */
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TINT32):
- case CASE(TFLOAT32, TINT64):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TINT32):
- case CASE(TFLOAT64, TINT64):
- if(t->op == OREGISTER)
- goto hardmem;
- nodreg(&r1, types[ft], REG_F0);
- if(f->op != OREGISTER) {
- if(ft == TFLOAT32)
- gins(AFMOVF, f, &r1);
- else
- gins(AFMOVD, f, &r1);
- }
-
- // set round to zero mode during conversion
- memname(&t1, types[TUINT16]);
- memname(&t2, types[TUINT16]);
- gins(AFSTCW, N, &t1);
- gins(AMOVW, ncon(0xf7f), &t2);
- gins(AFLDCW, &t2, N);
- if(tt == TINT16)
- gins(AFMOVWP, &r1, t);
- else if(tt == TINT32)
- gins(AFMOVLP, &r1, t);
- else
- gins(AFMOVVP, &r1, t);
- gins(AFLDCW, &t1, N);
- return;
-
- case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TUINT16):
- case CASE(TFLOAT32, TUINT8):
- case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TUINT16):
- case CASE(TFLOAT64, TUINT8):
- // convert via int32.
- tempname(&t1, types[TINT32]);
- gmove(f, &t1);
- switch(tt) {
- default:
- fatal("gmove %N", t);
- case TINT8:
- gins(ACMPL, &t1, ncon(-0x80));
- p1 = gbranch(optoas(OLT, types[TINT32]), T, -1);
- gins(ACMPL, &t1, ncon(0x7f));
- p2 = gbranch(optoas(OGT, types[TINT32]), T, -1);
- p3 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- patch(p2, pc);
- gmove(ncon(-0x80), &t1);
- patch(p3, pc);
- gmove(&t1, t);
- break;
- case TUINT8:
- gins(ATESTL, ncon(0xffffff00), &t1);
- p1 = gbranch(AJEQ, T, +1);
- gins(AMOVL, ncon(0), &t1);
- patch(p1, pc);
- gmove(&t1, t);
- break;
- case TUINT16:
- gins(ATESTL, ncon(0xffff0000), &t1);
- p1 = gbranch(AJEQ, T, +1);
- gins(AMOVL, ncon(0), &t1);
- patch(p1, pc);
- gmove(&t1, t);
- break;
- }
- return;
-
- case CASE(TFLOAT32, TUINT32):
- case CASE(TFLOAT64, TUINT32):
- // convert via int64.
- cvt = types[TINT64];
- goto hardmem;
-
- /*
- * integer to float
- */
- case CASE(TINT16, TFLOAT32):
- case CASE(TINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT32):
- case CASE(TINT32, TFLOAT64):
- case CASE(TINT64, TFLOAT32):
- case CASE(TINT64, TFLOAT64):
- if(t->op != OREGISTER)
- goto hard;
- if(f->op == OREGISTER) {
- cvt = f->type;
- goto hardmem;
- }
- switch(ft) {
- case TINT16:
- a = AFMOVW;
- break;
- case TINT32:
- a = AFMOVL;
- break;
- default:
- a = AFMOVV;
- break;
- }
- break;
-
- case CASE(TINT8, TFLOAT32):
- case CASE(TINT8, TFLOAT64):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT64):
- case CASE(TUINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT64):
- // convert via int32 memory
- cvt = types[TINT32];
- goto hardmem;
-
- case CASE(TUINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT64):
- // convert via int64 memory
- cvt = types[TINT64];
- goto hardmem;
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- case CASE(TFLOAT64, TFLOAT64):
- // The way the code generator uses floating-point
- // registers, a move from F0 to F0 is intended as a no-op.
- // On the x86, it's not: it pushes a second copy of F0
- // on the floating point stack. So toss it away here.
- // Also, F0 is the *only* register we ever evaluate
- // into, so we should only see register/register as F0/F0.
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0)
- goto fatal;
- return;
- }
- a = AFMOVF;
- if(ft == TFLOAT64)
- a = AFMOVD;
- if(ismem(t)) {
- if(f->op != OREGISTER || f->val.u.reg != REG_F0)
- fatal("gmove %N", f);
- a = AFMOVFP;
- if(ft == TFLOAT64)
- a = AFMOVDP;
- }
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0)
- goto fatal;
- return;
- }
- if(f->op == OREGISTER)
- gins(AFMOVDP, f, t);
- else
- gins(AFMOVF, f, t);
- return;
-
- case CASE(TFLOAT64, TFLOAT32):
- if(ismem(f) && ismem(t))
- goto hard;
- if(f->op == OREGISTER && t->op == OREGISTER) {
- tempname(&r1, types[TFLOAT32]);
- gins(AFMOVFP, f, &r1);
- gins(AFMOVF, &r1, t);
- return;
- }
- if(f->op == OREGISTER)
- gins(AFMOVFP, f, t);
- else
- gins(AFMOVD, f, t);
- return;
- }
-
- gins(a, f, t);
- return;
-
-hard:
- // requires register intermediate
- regalloc(&r1, cvt, t);
- gmove(f, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-
-hardmem:
- // requires memory intermediate
- tempname(&r1, cvt);
- gmove(f, &r1);
- gmove(&r1, t);
- return;
-
-fatal:
- // should not happen
- fatal("gmove %lN -> %lN", f, t);
- return;
-}
-
-static void
-floatmove_sse(Node *f, Node *t)
-{
- Node r1;
- Type *cvt;
- int a, ft, tt;
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
-
- switch(CASE(ft, tt)) {
- default:
- // should not happen
- fatal("gmove %N -> %N", f, t);
- return;
- /*
- * float to integer
- */
- 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):
- // convert via int32.
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TFLOAT32, TUINT32):
- case CASE(TFLOAT64, TUINT32):
- // convert via int64.
- cvt = types[TINT64];
- goto hardmem;
-
- case CASE(TFLOAT32, TINT32):
- a = ACVTTSS2SL;
- goto rdst;
-
- case CASE(TFLOAT64, TINT32):
- a = ACVTTSD2SL;
- goto rdst;
-
- /*
- * integer to float
- */
- case CASE(TINT8, TFLOAT32):
- case CASE(TINT8, TFLOAT64):
- case CASE(TINT16, TFLOAT32):
- case CASE(TINT16, TFLOAT64):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT64):
- case CASE(TUINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT64):
- // convert via int32 memory
- cvt = types[TINT32];
- goto hard;
-
- case CASE(TUINT32, TFLOAT32):
- case CASE(TUINT32, TFLOAT64):
- // convert via int64 memory
- cvt = types[TINT64];
- goto hardmem;
-
- case CASE(TINT32, TFLOAT32):
- a = ACVTSL2SS;
- goto rdst;
-
- case CASE(TINT32, TFLOAT64):
- a = ACVTSL2SD;
- goto rdst;
-
- /*
- * float to float
- */
- case CASE(TFLOAT32, TFLOAT32):
- a = AMOVSS;
- break;
-
- case CASE(TFLOAT64, TFLOAT64):
- a = AMOVSD;
- break;
-
- case CASE(TFLOAT32, TFLOAT64):
- a = ACVTSS2SD;
- goto rdst;
-
- case CASE(TFLOAT64, TFLOAT32):
- a = ACVTSD2SS;
- goto rdst;
- }
-
- gins(a, f, t);
- return;
-
-hard:
- // requires register intermediate
- regalloc(&r1, cvt, t);
- gmove(f, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-
-hardmem:
- // requires memory intermediate
- tempname(&r1, cvt);
- gmove(f, &r1);
- gmove(&r1, t);
- return;
-
-rdst:
- // requires register destination
- regalloc(&r1, t->type, t);
- gins(a, f, &r1);
- gmove(&r1, t);
- regfree(&r1);
- return;
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
- if(f->op != t->op)
- return 0;
-
- switch(f->op) {
- case OREGISTER:
- if(f->val.u.reg != t->val.u.reg)
- break;
- return 1;
- }
- return 0;
-}
-/*
- * generate one instruction:
- * as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
- Prog *p;
- Addr af, at;
- int w;
-
- if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
- fatal("gins MOVF reg, reg");
- if(as == ACVTSD2SS && f && f->op == OLITERAL)
- fatal("gins CVTSD2SS const");
- if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == REG_F0)
- fatal("gins MOVSD into F0");
-
- switch(as) {
- case AMOVB:
- case AMOVW:
- case AMOVL:
- if(f != N && t != N && samaddr(f, t))
- return nil;
- break;
-
- case ALEAL:
- if(f != N && isconst(f, CTNIL))
- fatal("gins LEAL nil %T", f->type);
- break;
- }
-
- 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(debug['g'])
- print("%P\n", p);
-
- w = 0;
- switch(as) {
- case AMOVB:
- w = 1;
- break;
- case AMOVW:
- w = 2;
- break;
- case AMOVL:
- w = 4;
- break;
- }
-
- if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
- dump("bad width from:", f);
- dump("bad width to:", t);
- fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
- }
- if(p->to.type == TYPE_ADDR && w > 0)
- fatal("bad use of addr: %P", p);
-
- return p;
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
- int o;
- int64 oary[10];
- Node *nn;
-
- if(n->op != ODOT)
- return 0;
-
- o = dotoffset(n, oary, &nn);
- if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
- *n1 = *nn;
- n1->type = n->type;
- n1->xoffset += oary[0];
- return 1;
- }
- return 0;
-}
-
-void
-sudoclean(void)
-{
-}
-
-int
-sudoaddable(int as, Node *n, Addr *a)
-{
- USED(as);
- USED(n);
-
- memset(a, 0, sizeof *a);
- return 0;
-}
diff --git a/src/cmd/new8g/gsubr.go b/src/cmd/8g/gsubr.go
index 2728c2a276..2728c2a276 100644
--- a/src/cmd/new8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
deleted file mode 100644
index 712c8fe11b..0000000000
--- a/src/cmd/8g/peep.c
+++ /dev/null
@@ -1,773 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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 "../gc/popt.h"
-
-enum {
- REGEXT = 0,
- exregoffset = REG_DI,
-};
-
-static void conprop(Flow *r);
-static void elimshortmov(Graph*);
-static int subprop(Flow*);
-static int copyprop(Graph*, Flow*);
-static int copy1(Adr*, Adr*, Flow*, int);
-static int copyas(Adr*, Adr*);
-static int copyau(Adr*, Adr*);
-static int copysub(Adr*, Adr*, Adr*, int);
-static int copyu(Prog*, Adr*, Adr*);
-
-static uint32 gactive;
-
-// do we need the carry bit
-static int
-needc(Prog *p)
-{
- ProgInfo info;
-
- while(p != P) {
- proginfo(&info, p);
- if(info.flags & UseCarry)
- return 1;
- if(info.flags & (SetCarry|KillCarry))
- return 0;
- p = p->link;
- }
- return 0;
-}
-
-static Flow*
-rnops(Flow *r)
-{
- Prog *p;
- Flow *r1;
-
- if(r != nil)
- for(;;) {
- p = r->prog;
- if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE)
- break;
- r1 = uniqs(r);
- if(r1 == nil)
- break;
- r = r1;
- }
- return r;
-}
-
-void
-peep(Prog *firstp)
-{
- Flow *r, *r1;
- Graph *g;
- Prog *p, *p1;
- int t;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
- gactive = 0;
-
- // byte, word arithmetic elimination.
- elimshortmov(g);
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ALEAL:
- if(regtyp(&p->to))
- if(p->from.sym != nil)
- if(p->from.index == REG_NONE)
- conprop(r);
- break;
-
- case AMOVB:
- case AMOVW:
- case AMOVL:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST)
- conprop(r);
- break;
- }
- }
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", g->start, 0);
-
- t = 0;
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVL:
- case AMOVSS:
- case AMOVSD:
- if(regtyp(&p->to))
- if(regtyp(&p->from)) {
- if(copyprop(g, r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(g, r)) {
- excise(r);
- t++;
- }
- }
- break;
-
- case AMOVBLZX:
- case AMOVWLZX:
- case AMOVBLSX:
- case AMOVWLSX:
- if(regtyp(&p->to)) {
- r1 = rnops(uniqs(r));
- if(r1 != nil) {
- p1 = r1->prog;
- if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){
- p1->as = AMOVL;
- t++;
- }
- }
- }
- break;
-
- case AADDL:
- case AADDW:
- if(p->from.type != TYPE_CONST || needc(p->link))
- break;
- if(p->from.offset == -1){
- if(p->as == AADDL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == AADDL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- break;
- }
- break;
-
- case ASUBL:
- case ASUBW:
- if(p->from.type != TYPE_CONST || needc(p->link))
- break;
- if(p->from.offset == -1) {
- if(p->as == ASUBL)
- p->as = AINCL;
- else
- p->as = AINCW;
- p->from = zprog.from;
- break;
- }
- if(p->from.offset == 1){
- if(p->as == ASUBL)
- p->as = ADECL;
- else
- p->as = ADECW;
- p->from = zprog.from;
- break;
- }
- break;
- }
- }
- if(t)
- goto loop1;
-
- // MOVSD removal.
- // We never use packed registers, so a MOVSD between registers
- // can be replaced by MOVAPD, which moves the pair of float64s
- // instead of just the lower one. We only use the lower one, but
- // the processor can do better if we do moves using both.
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- if(p->as == AMOVSD)
- if(regtyp(&p->from))
- if(regtyp(&p->to))
- p->as = AMOVAPD;
- }
-
- flowend(g);
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
-
- nopout(p);
-
- ostats.ndelmov++;
-}
-
-int
-regtyp(Adr *a)
-{
- return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_DI || REG_X0 <= a->reg && a->reg <= REG_X7);
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible. a movb into a register
-// can smash the entire 64-bit register without
-// causing any trouble.
-static void
-elimshortmov(Graph *g)
-{
- Prog *p;
- Flow *r;
-
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- if(regtyp(&p->to)) {
- switch(p->as) {
- case AINCB:
- case AINCW:
- p->as = AINCL;
- break;
- case ADECB:
- case ADECW:
- p->as = ADECL;
- break;
- case ANEGB:
- case ANEGW:
- p->as = ANEGL;
- break;
- case ANOTB:
- case ANOTW:
- p->as = ANOTL;
- break;
- }
- if(regtyp(&p->from) || p->from.type == TYPE_CONST) {
- // move or artihmetic into partial register.
- // from another register or constant can be movl.
- // we don't switch to 32-bit arithmetic if it can
- // change how the carry bit is set (and the carry bit is needed).
- switch(p->as) {
- case AMOVB:
- case AMOVW:
- p->as = AMOVL;
- break;
- case AADDB:
- case AADDW:
- if(!needc(p->link))
- p->as = AADDL;
- break;
- case ASUBB:
- case ASUBW:
- if(!needc(p->link))
- p->as = ASUBL;
- break;
- case AMULB:
- case AMULW:
- p->as = AMULL;
- break;
- case AIMULB:
- case AIMULW:
- p->as = AIMULL;
- break;
- case AANDB:
- case AANDW:
- p->as = AANDL;
- break;
- case AORB:
- case AORW:
- p->as = AORL;
- break;
- case AXORB:
- case AXORW:
- p->as = AXORL;
- break;
- case ASHLB:
- case ASHLW:
- p->as = ASHLL;
- break;
- }
- } else {
- // explicit zero extension
- switch(p->as) {
- case AMOVB:
- p->as = AMOVBLZX;
- break;
- case AMOVW:
- p->as = AMOVWLZX;
- break;
- }
- }
- }
- }
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
- Prog *p;
- Adr *v1, *v2;
- Flow *r;
- int t;
- ProgInfo info;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- if(debug['P'] && debug['v'])
- print("\t? %P\n", r->prog);
- if(uniqs(r) == nil)
- break;
- p = r->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
- if(info.flags & Call)
- return 0;
-
- if(info.reguse | info.regset)
- return 0;
-
- if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg)
- goto gotit;
-
- if(copyau(&p->from, v2) || copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type && p->from.reg == v2->reg)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
- Prog *p;
- Adr *v1, *v2;
-
- USED(g);
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- gactive++;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active == gactive) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = gactive;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == nil) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub %D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, nil);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %D set and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-static int
-copyu(Prog *p, Adr *v, Adr *s)
-{
- ProgInfo info;
-
- switch(p->as) {
- case AJMP:
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARET:
- if(s != nil)
- return 1;
- return 3;
-
- case ACALL:
- if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
- return 2;
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
- return 2;
- if(v->type == p->from.type && v->reg == p->from.reg)
- return 2;
-
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ATEXT:
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
- return 3;
- return 0;
- }
-
- if(p->as == AVARDEF || p->as == AVARKILL)
- return 0;
- proginfo(&info, p);
-
- if((info.reguse|info.regset) & RtoB(v->reg))
- return 2;
-
- if(info.flags & LeftAddr)
- if(copyas(&p->from, v))
- return 2;
-
- if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
- if(copyas(&p->to, v))
- return 2;
-
- if(info.flags & RightWrite) {
- if(copyas(&p->to, v)) {
- if(s != nil)
- return copysub(&p->from, v, s, 1);
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- }
-
- if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- }
-
- return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
- if(REG_AL <= a->reg && a->reg <= REG_BL)
- fatal("use of byte register");
- if(REG_AL <= v->reg && v->reg <= REG_BL)
- fatal("use of byte register");
-
- if(a->type != v->type || a->name != v->name || a->reg != v->reg)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
- if(a->type != v->type || a->name != v->name || a->reg != v->reg)
- return 0;
- if(regtyp(v))
- return 1;
- if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM))
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(regtyp(v)) {
- if(a->type == TYPE_MEM && a->reg == v->reg)
- return 1;
- if(a->index == v->reg)
- return 1;
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
- int reg;
-
- if(copyas(a, v)) {
- reg = s->reg;
- if(reg >= REG_AX && reg <= REG_DI || reg >= REG_X0 && reg <= REG_X7) {
- if(f)
- a->reg = reg;
- }
- return 0;
- }
- if(regtyp(v)) {
- reg = v->reg;
- if(a->type == TYPE_MEM && a->reg == reg) {
- if((s->reg == REG_BP) && a->index != TYPE_NONE)
- return 1; /* can't use BP-base with index */
- if(f)
- a->reg = s->reg;
-// return 0;
- }
- if(a->index == reg) {
- if(f)
- a->index = s->reg;
- return 0;
- }
- return 0;
- }
- return 0;
-}
-
-static void
-conprop(Flow *r0)
-{
- Flow *r;
- Prog *p, *p0;
- int t;
- Adr *v0;
-
- p0 = r0->prog;
- v0 = &p0->to;
- r = r0;
-
-loop:
- r = uniqs(r);
- if(r == nil || r == r0)
- return;
- if(uniqp(r) == nil)
- return;
-
- p = r->prog;
- t = copyu(p, v0, nil);
- switch(t) {
- case 0: // miss
- case 1: // use
- goto loop;
-
- case 2: // rar
- case 4: // use and set
- break;
-
- case 3: // set
- if(p->as == p0->as)
- if(p->from.type == p0->from.type)
- if(p->from.reg == p0->from.reg)
- if(p->from.node == p0->from.node)
- if(p->from.offset == p0->from.offset)
- if(p->from.scale == p0->from.scale)
- if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval)
- if(p->from.index == p0->from.index) {
- excise(r);
- goto loop;
- }
- break;
- }
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
- return regtyp(reg) &&
- a->type == TYPE_MEM && a->reg == reg->reg &&
- a->index == REG_NONE &&
- 0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
- return a->type == TYPE_REG && a->reg == REG_SP;
-}
diff --git a/src/cmd/new8g/peep.go b/src/cmd/8g/peep.go
index 0838882e38..0838882e38 100644
--- a/src/cmd/new8g/peep.go
+++ b/src/cmd/8g/peep.go
diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c
deleted file mode 100644
index e77a026a93..0000000000
--- a/src/cmd/8g/prog.c
+++ /dev/null
@@ -1,349 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-// Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-REG_AX))
-
-enum {
- AX = RtoB(REG_AX),
- BX = RtoB(REG_BX),
- CX = RtoB(REG_CX),
- DX = RtoB(REG_DX),
- DI = RtoB(REG_DI),
- SI = RtoB(REG_SI),
-
- LeftRdwr = LeftRead | LeftWrite,
- RightRdwr = RightRead | RightWrite,
-};
-
-#undef RtoB
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-static ProgInfo progtable[ALAST] = {
- [ATYPE]= {Pseudo | Skip},
- [ATEXT]= {Pseudo},
- [AFUNCDATA]= {Pseudo},
- [APCDATA]= {Pseudo},
- [AUNDEF]= {Break},
- [AUSEFIELD]= {OK},
- [ACHECKNIL]= {LeftRead},
- [AVARDEF]= {Pseudo | RightWrite},
- [AVARKILL]= {Pseudo | RightWrite},
-
- // NOP is an internal no-op that also stands
- // for USED and SET annotations, not the Intel opcode.
- [ANOP]= {LeftRead | RightWrite},
-
- [AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
- [AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
- [AADDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AADDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AADDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [AADDSD]= {SizeD | LeftRead | RightRdwr},
- [AADDSS]= {SizeF | LeftRead | RightRdwr},
-
- [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [ACALL]= {RightAddr | Call | KillCarry},
-
- [ACDQ]= {OK, AX, AX | DX},
- [ACWD]= {OK, AX, AX | DX},
-
- [ACLD]= {OK},
- [ASTD]= {OK},
-
- [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry},
- [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry},
- [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry},
-
- [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry},
- [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry},
-
- [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv},
- [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv},
- [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv},
- [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv},
- [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
- [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
-
- [ADECB]= {SizeB | RightRdwr},
- [ADECL]= {SizeL | RightRdwr},
- [ADECW]= {SizeW | RightRdwr},
-
- [ADIVB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [ADIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
- [ADIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
- [ADIVSD]= {SizeD | LeftRead | RightRdwr},
- [ADIVSS]= {SizeF | LeftRead | RightRdwr},
-
- [AFLDCW]= {SizeW | LeftAddr},
- [AFSTCW]= {SizeW | RightAddr},
-
- [AFSTSW]= {SizeW | RightAddr | RightWrite},
-
- [AFADDD]= {SizeD | LeftAddr | RightRdwr},
- [AFADDDP]= {SizeD | LeftAddr | RightRdwr},
- [AFADDF]= {SizeF | LeftAddr | RightRdwr},
-
- [AFCOMD]= {SizeD | LeftAddr | RightRead},
- [AFCOMDP]= {SizeD | LeftAddr | RightRead},
- [AFCOMDPP]= {SizeD | LeftAddr | RightRead},
- [AFCOMF]= {SizeF | LeftAddr | RightRead},
- [AFCOMFP]= {SizeF | LeftAddr | RightRead},
- [AFUCOMIP]= {SizeF | LeftAddr | RightRead},
-
- [AFCHS]= {SizeD | RightRdwr}, // also SizeF
-
- [AFDIVDP]= {SizeD | LeftAddr | RightRdwr},
- [AFDIVF]= {SizeF | LeftAddr | RightRdwr},
- [AFDIVD]= {SizeD | LeftAddr | RightRdwr},
-
- [AFDIVRDP]= {SizeD | LeftAddr | RightRdwr},
- [AFDIVRF]= {SizeF | LeftAddr | RightRdwr},
- [AFDIVRD]= {SizeD | LeftAddr | RightRdwr},
-
- [AFXCHD]= {SizeD | LeftRdwr | RightRdwr},
-
- [AFSUBD]= {SizeD | LeftAddr | RightRdwr},
- [AFSUBDP]= {SizeD | LeftAddr | RightRdwr},
- [AFSUBF]= {SizeF | LeftAddr | RightRdwr},
- [AFSUBRD]= {SizeD | LeftAddr | RightRdwr},
- [AFSUBRDP]= {SizeD | LeftAddr | RightRdwr},
- [AFSUBRF]= {SizeF | LeftAddr | RightRdwr},
-
- [AFMOVD]= {SizeD | LeftAddr | RightWrite},
- [AFMOVF]= {SizeF | LeftAddr | RightWrite},
- [AFMOVL]= {SizeL | LeftAddr | RightWrite},
- [AFMOVW]= {SizeW | LeftAddr | RightWrite},
- [AFMOVV]= {SizeQ | LeftAddr | RightWrite},
-
- // These instructions are marked as RightAddr
- // so that the register optimizer does not try to replace the
- // memory references with integer register references.
- // But they do not use the previous value at the address, so
- // we also mark them RightWrite.
- [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr},
- [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr},
- [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr},
- [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr},
- [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr},
-
- [AFMULD]= {SizeD | LeftAddr | RightRdwr},
- [AFMULDP]= {SizeD | LeftAddr | RightRdwr},
- [AFMULF]= {SizeF | LeftAddr | RightRdwr},
-
- [AIDIVB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AIDIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
- [AIDIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
- [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry},
- [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry},
-
- [AINCB]= {SizeB | RightRdwr},
- [AINCL]= {SizeL | RightRdwr},
- [AINCW]= {SizeW | RightRdwr},
-
- [AJCC]= {Cjmp | UseCarry},
- [AJCS]= {Cjmp | UseCarry},
- [AJEQ]= {Cjmp | UseCarry},
- [AJGE]= {Cjmp | UseCarry},
- [AJGT]= {Cjmp | UseCarry},
- [AJHI]= {Cjmp | UseCarry},
- [AJLE]= {Cjmp | UseCarry},
- [AJLS]= {Cjmp | UseCarry},
- [AJLT]= {Cjmp | UseCarry},
- [AJMI]= {Cjmp | UseCarry},
- [AJNE]= {Cjmp | UseCarry},
- [AJOC]= {Cjmp | UseCarry},
- [AJOS]= {Cjmp | UseCarry},
- [AJPC]= {Cjmp | UseCarry},
- [AJPL]= {Cjmp | UseCarry},
- [AJPS]= {Cjmp | UseCarry},
-
- [AJMP]= {Jump | Break | KillCarry},
-
- [ALEAL]= {LeftAddr | RightWrite},
-
- [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv},
- [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv},
- [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv},
- [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv},
-
- [AMOVB]= {SizeB | LeftRead | RightWrite | Move},
- [AMOVL]= {SizeL | LeftRead | RightWrite | Move},
- [AMOVW]= {SizeW | LeftRead | RightWrite | Move},
-
- [AMOVSB]= {OK, DI|SI, DI|SI},
- [AMOVSL]= {OK, DI|SI, DI|SI},
- [AMOVSW]= {OK, DI|SI, DI|SI},
- [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX},
-
- [AMOVSD]= {SizeD | LeftRead | RightWrite | Move},
- [AMOVSS]= {SizeF | LeftRead | RightWrite | Move},
-
- // We use MOVAPD as a faster synonym for MOVSD.
- [AMOVAPD]= {SizeD | LeftRead | RightWrite | Move},
-
- [AMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
- [AMULL]= {SizeL | LeftRead | SetCarry, AX, AX|DX},
- [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX},
-
- [AMULSD]= {SizeD | LeftRead | RightRdwr},
- [AMULSS]= {SizeF | LeftRead | RightRdwr},
-
- [ANEGB]= {SizeB | RightRdwr | SetCarry},
- [ANEGL]= {SizeL | RightRdwr | SetCarry},
- [ANEGW]= {SizeW | RightRdwr | SetCarry},
-
- [ANOTB]= {SizeB | RightRdwr},
- [ANOTL]= {SizeL | RightRdwr},
- [ANOTW]= {SizeW | RightRdwr},
-
- [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [APOPL]= {SizeL | RightWrite},
- [APUSHL]= {SizeL | LeftRead},
-
- [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
- [ARCRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
- [ARCRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
- [AREP]= {OK, CX, CX},
- [AREPN]= {OK, CX, CX},
-
- [ARET]= {Break | KillCarry},
-
- [AROLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [AROLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASAHF]= {OK, AX, AX},
-
- [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
- [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
- [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
- [ASETCC]= {SizeB | RightRdwr | UseCarry},
- [ASETCS]= {SizeB | RightRdwr | UseCarry},
- [ASETEQ]= {SizeB | RightRdwr | UseCarry},
- [ASETGE]= {SizeB | RightRdwr | UseCarry},
- [ASETGT]= {SizeB | RightRdwr | UseCarry},
- [ASETHI]= {SizeB | RightRdwr | UseCarry},
- [ASETLE]= {SizeB | RightRdwr | UseCarry},
- [ASETLS]= {SizeB | RightRdwr | UseCarry},
- [ASETLT]= {SizeB | RightRdwr | UseCarry},
- [ASETMI]= {SizeB | RightRdwr | UseCarry},
- [ASETNE]= {SizeB | RightRdwr | UseCarry},
- [ASETOC]= {SizeB | RightRdwr | UseCarry},
- [ASETOS]= {SizeB | RightRdwr | UseCarry},
- [ASETPC]= {SizeB | RightRdwr | UseCarry},
- [ASETPL]= {SizeB | RightRdwr | UseCarry},
- [ASETPS]= {SizeB | RightRdwr | UseCarry},
-
- [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
- [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
- [ASTOSB]= {OK, AX|DI, DI},
- [ASTOSL]= {OK, AX|DI, DI},
- [ASTOSW]= {OK, AX|DI, DI},
- [ADUFFZERO]= {OK, AX|DI, DI},
-
- [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-
- [ASUBSD]= {SizeD | LeftRead | RightRdwr},
- [ASUBSS]= {SizeF | LeftRead | RightRdwr},
-
- [ATESTB]= {SizeB | LeftRead | RightRead | SetCarry},
- [ATESTL]= {SizeL | LeftRead | RightRead | SetCarry},
- [ATESTW]= {SizeW | LeftRead | RightRead | SetCarry},
-
- [AUCOMISD]= {SizeD | LeftRead | RightRead},
- [AUCOMISS]= {SizeF | LeftRead | RightRead},
-
- [AXCHGB]= {SizeB | LeftRdwr | RightRdwr},
- [AXCHGL]= {SizeL | LeftRdwr | RightRdwr},
- [AXCHGW]= {SizeW | LeftRdwr | RightRdwr},
-
- [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
- [AXORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
- [AXORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
- *info = progtable[p->as];
- if(info->flags == 0)
- fatal("unknown instruction %P", p);
-
- if((info->flags & ShiftCX) && p->from.type != TYPE_CONST)
- info->reguse |= CX;
-
- if(info->flags & ImulAXDX) {
- if(p->to.type == TYPE_NONE) {
- info->reguse |= AX;
- info->regset |= AX | DX;
- } else {
- info->flags |= RightRdwr;
- }
- }
-
- // Addressing makes some registers used.
- if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE)
- info->regindex |= RtoB(p->from.reg);
- if(p->from.index != REG_NONE)
- info->regindex |= RtoB(p->from.index);
- if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE)
- info->regindex |= RtoB(p->to.reg);
- if(p->to.index != REG_NONE)
- info->regindex |= RtoB(p->to.index);
-}
diff --git a/src/cmd/new8g/prog.go b/src/cmd/8g/prog.go
index d8e46e5108..d8e46e5108 100644
--- a/src/cmd/new8g/prog.go
+++ b/src/cmd/8g/prog.go
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
deleted file mode 100644
index 0470bdf7b5..0000000000
--- a/src/cmd/8g/reg.c
+++ /dev/null
@@ -1,112 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 "../gc/popt.h"
-
-enum {
- NREGVAR = 16, /* 8 integer + 8 floating */
-};
-
-static char* regname[] = {
- ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di",
- ".x0", ".x1", ".x2", ".x3", ".x4", ".x5", ".x6", ".x7",
-};
-
-char**
-regnames(int *n)
-{
- *n = NREGVAR;
- return regname;
-}
-
-uint64
-excludedregs(void)
-{
- return RtoB(REG_SP);
-}
-
-uint64
-doregbits(int r)
-{
- uint64 b;
-
- b = 0;
- if(r >= REG_AX && r <= REG_DI)
- b |= RtoB(r);
- else
- if(r >= REG_AL && r <= REG_BL)
- b |= RtoB(r-REG_AL+REG_AX);
- else
- if(r >= REG_AH && r <= REG_BH)
- b |= RtoB(r-REG_AH+REG_AX);
- else
- if(r >= REG_X0 && r <= REG_X0+7)
- b |= FtoB(r);
- return b;
-}
-
-uint64
-RtoB(int r)
-{
-
- if(r < REG_AX || r > REG_DI)
- return 0;
- return 1ULL << (r-REG_AX);
-}
-
-int
-BtoR(uint64 b)
-{
-
- b &= 0xffL;
- if(b == 0)
- return 0;
- return bitno(b) + REG_AX;
-}
-
-uint64
-FtoB(int f)
-{
- if(f < REG_X0 || f > REG_X7)
- return 0;
- return 1ULL << (f - REG_X0 + 8);
-}
-
-int
-BtoF(uint64 b)
-{
- b &= 0xFF00L;
- if(b == 0)
- return 0;
- return bitno(b) - 8 + REG_X0;
-}
diff --git a/src/cmd/new8g/reg.go b/src/cmd/8g/reg.go
index 76bd260f54..76bd260f54 100644
--- a/src/cmd/new8g/reg.go
+++ b/src/cmd/8g/reg.go
diff --git a/src/cmd/new8g/util.go b/src/cmd/8g/util.go
index bb5eedb15a..bb5eedb15a 100644
--- a/src/cmd/new8g/util.go
+++ b/src/cmd/8g/util.go
diff --git a/src/cmd/9a/Makefile b/src/cmd/9a/Makefile
deleted file mode 100644
index 27290ddd71..0000000000
--- a/src/cmd/9a/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
- LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/9a/a.h b/src/cmd/9a/a.h
deleted file mode 100644
index d4f2fee119..0000000000
--- a/src/cmd/9a/a.h
+++ /dev/null
@@ -1,172 +0,0 @@
-// cmd/9a/a.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 <bio.h>
-#include <link.h>
-#include "../9l/9.out.h"
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef getc
-#undef ungetc
-#undef BUFSIZ
-
-#define getc ccgetc
-#define ungetc ccungetc
-
-typedef struct Sym Sym;
-typedef struct Io Io;
-
-#define MAXALIGN 7
-#define FPCHIP 1
-#define NSYMB 8192
-#define BUFSIZ 8192
-#define HISTSZ 20
-#define NINCLUDE 10
-#define NHUNK 10000
-#ifndef EOF
-#define EOF (-1)
-#endif
-#define IGN (-2)
-#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define NHASH 503
-#define STRINGSZ 200
-#define NMACRO 10
-
-struct Sym
-{
- Sym* link;
- char* macro;
- vlong value;
- ushort type;
- char *name;
- char* labelname;
- char sym;
-};
-#define S ((Sym*)0)
-
-EXTERN struct
-{
- char* p;
- int c;
-} fi;
-
-struct Io
-{
- Io* link;
- char b[BUFSIZ];
- char* p;
- short c;
- short f;
-};
-#define I ((Io*)0)
-
-enum
-{
- CLAST,
- CMACARG,
- CMACRO,
- CPREPROC,
-};
-
-EXTERN int debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN char** Dlist;
-EXTERN int nDlist;
-EXTERN int newflag;
-EXTERN char* hunk;
-EXTERN char** include;
-EXTERN Io* iofree;
-EXTERN Io* ionext;
-EXTERN Io* iostack;
-EXTERN int32 lineno;
-EXTERN int nerrors;
-EXTERN int32 nhunk;
-EXTERN int nosched;
-EXTERN int ninclude;
-EXTERN int32 nsymb;
-EXTERN Addr nullgen;
-EXTERN char* outfile;
-EXTERN int pass;
-EXTERN int32 pc;
-EXTERN int peekc;
-EXTERN int32 stmtline;
-EXTERN int sym;
-EXTERN char* symb;
-EXTERN int thechar;
-EXTERN char* thestring;
-EXTERN int32 thunk;
-EXTERN Biobuf obuf;
-EXTERN Link* ctxt;
-EXTERN Biobuf bstdout;
-EXTERN Prog* lastpc;
-
-void* alloc(int32);
-void* allocn(void*, int32, int32);
-void ensuresymb(int32);
-void errorexit(void);
-void pushio(void);
-void newio(void);
-void newfile(char*, int);
-Sym* slookup(char*);
-Sym* lookup(void);
-Sym* labellookup(Sym*);
-void settext(LSym*);
-void syminit(Sym*);
-int32 yylex(void);
-int getc(void);
-int getnsc(void);
-void unget(int);
-int escchar(int);
-void cinit(void);
-void pinit(char*);
-void cclean(void);
-void outcode(int, Addr*, int, Addr*);
-void outgcode(int, Addr*, int, Addr*, Addr*);
-int filbuf(void);
-Sym* getsym(void);
-void domacro(void);
-void macund(void);
-void macdef(void);
-void macexpand(Sym*, char*);
-void macinc(void);
-void macprag(void);
-void maclin(void);
-void macif(int);
-void macend(void);
-void dodefine(char*);
-void prfile(int32);
-void linehist(char*, int);
-void gethunk(void);
-void yyerror(char*, ...);
-int yyparse(void);
-void setinclude(char*);
-int assemble(char*);
diff --git a/src/cmd/9a/a.y b/src/cmd/9a/a.y
index ccc3bcc3a6..db733c5987 100644
--- a/src/cmd/9a/a.y
+++ b/src/cmd/9a/a.y
@@ -28,20 +28,24 @@
// THE SOFTWARE.
%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
+package main
+
+import (
+ "cmd/internal/asm"
+ "cmd/internal/obj"
+ . "cmd/internal/obj/ppc64"
+)
%}
+
%union
{
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
+ sym *asm.Sym
+ lval int64
+ dval float64
+ sval string
+ addr obj.Addr
}
+
%left '|'
%left '^'
%left '&'
@@ -50,7 +54,7 @@
%left '*' '/' '%'
%token <lval> LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
%token <lval> LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
-%token <lval> LNOP LEND LRETT LWORD LTEXT LGLOBL LDATA LRETRN
+%token <lval> LNOP LEND LRETT LWORD LTEXT LDATA LGLOBL LRETRN
%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH
%token <lval> LREG LFREG LR LCR LF LFPSCR
%token <lval> LLR LCTR LSPR LSPREG LSEG LMSR
@@ -66,34 +70,36 @@
prog:
| prog
{
- stmtline = lineno;
+ stmtline = asm.Lineno
}
line
line:
LNAME ':'
{
- $1 = labellookup($1);
- if($1->type == LLAB && $1->value != pc)
- yyerror("redeclaration of %s", $1->labelname);
- $1->type = LLAB;
- $1->value = pc;
+ $1 = asm.LabelLookup($1);
+ if $1.Type == LLAB && $1.Value != int64(asm.PC) {
+ yyerror("redeclaration of %s", $1.Labelname)
+ }
+ $1.Type = LLAB;
+ $1.Value = int64(asm.PC);
}
line
| LNAME '=' expr ';'
{
- $1->type = LVAR;
- $1->value = $3;
+ $1.Type = LVAR;
+ $1.Value = $3;
}
| LVAR '=' expr ';'
{
- if($1->value != $3)
- yyerror("redeclaration of %s", $1->name);
- $1->value = $3;
+ if $1.Value != $3 {
+ yyerror("redeclaration of %s", $1.Name)
+ }
+ $1.Value = $3;
}
| LSCHED ';'
{
- nosched = $1;
+ nosched = int($1);
}
| ';'
| inst ';'
@@ -105,122 +111,122 @@ inst:
*/
LMOVW rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW addr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW regaddr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVB rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVB addr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVB regaddr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* load floats
*/
| LFMOV addr ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFMOV regaddr ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFMOV fimm ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFMOV freg ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFMOV freg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFMOV freg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* store ints and bytes
*/
| LMOVW rreg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW rreg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVB rreg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVB rreg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* store floats
*/
| LMOVW freg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW freg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* floating point status
*/
| LMOVW fpscr ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW freg ',' fpscr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW freg ',' imm ',' fpscr
{
- outgcode($1, &$2, 0, &$4, &$6);
+ outgcode(int($1), &$2, 0, &$4, &$6);
}
| LMOVW fpscr ',' creg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMTFSB imm ',' con
{
- outcode($1, &$2, $4, &nullgen);
+ outcode(int($1), &$2, int($4), &nullgen);
}
/*
* field moves (mtcrf)
*/
| LMOVW rreg ',' imm ',' lcr
{
- outgcode($1, &$2, 0, &$4, &$6);
+ outgcode(int($1), &$2, 0, &$4, &$6);
}
| LMOVW rreg ',' creg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW rreg ',' lcr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* integer operations
@@ -230,84 +236,84 @@ inst:
*/
| LADDW rreg ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
| LADDW imm ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
| LADDW rreg ',' imm ',' rreg
{
- outgcode($1, &$2, 0, &$4, &$6);
+ outgcode(int($1), &$2, 0, &$4, &$6);
}
| LADDW rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LADDW imm ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LLOGW rreg ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
| LLOGW rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LSHW rreg ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
| LSHW rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LSHW imm ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
| LSHW imm ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LABS rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LABS rreg
{
- outcode($1, &$2, 0, &$2);
+ outcode(int($1), &$2, 0, &$2);
}
/*
* multiply-accumulate
*/
| LMA rreg ',' sreg ',' rreg
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
/*
* move immediate: macro for cau+or, addi, addis, and other combinations
*/
| LMOVW imm ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW ximm ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* condition register operations
*/
| LCROP cbit ',' cbit
{
- outcode($1, &$2, $4.reg, &$4);
+ outcode(int($1), &$2, int($4.Reg), &$4);
}
| LCROP cbit ',' con ',' cbit
{
- outcode($1, &$2, $4, &$6);
+ outcode(int($1), &$2, int($4), &$6);
}
/*
* condition register moves
@@ -315,35 +321,35 @@ inst:
*/
| LMOVW creg ',' creg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW psr ',' creg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW lcr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW psr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW xlreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW rreg ',' xlreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW creg ',' psr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVW rreg ',' psr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* branch, branch conditional
@@ -352,170 +358,170 @@ inst:
*/
| LBRA rel
{
- outcode($1, &nullgen, 0, &$2);
+ outcode(int($1), &nullgen, 0, &$2);
}
| LBRA addr
{
- outcode($1, &nullgen, 0, &$2);
+ outcode(int($1), &nullgen, 0, &$2);
}
| LBRA '(' xlreg ')'
{
- outcode($1, &nullgen, 0, &$3);
+ outcode(int($1), &nullgen, 0, &$3);
}
| LBRA ',' rel
{
- outcode($1, &nullgen, 0, &$3);
+ outcode(int($1), &nullgen, 0, &$3);
}
| LBRA ',' addr
{
- outcode($1, &nullgen, 0, &$3);
+ outcode(int($1), &nullgen, 0, &$3);
}
| LBRA ',' '(' xlreg ')'
{
- outcode($1, &nullgen, 0, &$4);
+ outcode(int($1), &nullgen, 0, &$4);
}
| LBRA creg ',' rel
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LBRA creg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LBRA creg ',' '(' xlreg ')'
{
- outcode($1, &$2, 0, &$5);
+ outcode(int($1), &$2, 0, &$5);
}
| LBRA con ',' rel
{
- outcode($1, &nullgen, $2, &$4);
+ outcode(int($1), &nullgen, int($2), &$4);
}
| LBRA con ',' addr
{
- outcode($1, &nullgen, $2, &$4);
+ outcode(int($1), &nullgen, int($2), &$4);
}
| LBRA con ',' '(' xlreg ')'
{
- outcode($1, &nullgen, $2, &$5);
+ outcode(int($1), &nullgen, int($2), &$5);
}
| LBRA con ',' con ',' rel
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset = $2;
- outcode($1, &g, REG_R0+$4, &$6);
+ g.Type = obj.TYPE_CONST;
+ g.Offset = $2;
+ outcode(int($1), &g, int(REG_R0+$4), &$6);
}
| LBRA con ',' con ',' addr
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset = $2;
- outcode($1, &g, REG_R0+$4, &$6);
+ g.Type = obj.TYPE_CONST;
+ g.Offset = $2;
+ outcode(int($1), &g, int(REG_R0+$4), &$6);
}
| LBRA con ',' con ',' '(' xlreg ')'
{
- Addr g;
+ var g obj.Addr
g = nullgen;
- g.type = TYPE_CONST;
- g.offset = $2;
- outcode($1, &g, REG_R0+$4, &$7);
+ g.Type = obj.TYPE_CONST;
+ g.Offset = $2;
+ outcode(int($1), &g, int(REG_R0+$4), &$7);
}
/*
* conditional trap
*/
| LTRAP rreg ',' sreg
{
- outcode($1, &$2, $4, &nullgen);
+ outcode(int($1), &$2, int($4), &nullgen);
}
| LTRAP imm ',' sreg
{
- outcode($1, &$2, $4, &nullgen);
+ outcode(int($1), &$2, int($4), &nullgen);
}
| LTRAP rreg comma
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
| LTRAP comma
{
- outcode($1, &nullgen, 0, &nullgen);
+ outcode(int($1), &nullgen, 0, &nullgen);
}
/*
* floating point operate
*/
| LFCONV freg ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFADD freg ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFADD freg ',' freg ',' freg
{
- outcode($1, &$2, $4.reg, &$6);
+ outcode(int($1), &$2, int($4.Reg), &$6);
}
| LFMA freg ',' freg ',' freg ',' freg
{
- outgcode($1, &$2, $4.reg, &$6, &$8);
+ outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
}
| LFCMP freg ',' freg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LFCMP freg ',' freg ',' creg
{
- outcode($1, &$2, $6.reg, &$4);
+ outcode(int($1), &$2, int($6.Reg), &$4);
}
/*
* CMP
*/
| LCMP rreg ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LCMP rreg ',' imm
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LCMP rreg ',' rreg ',' creg
{
- outcode($1, &$2, $6.reg, &$4);
+ outcode(int($1), &$2, int($6.Reg), &$4);
}
| LCMP rreg ',' imm ',' creg
{
- outcode($1, &$2, $6.reg, &$4);
+ outcode(int($1), &$2, int($6.Reg), &$4);
}
/*
* rotate and mask
*/
| LRLWM imm ',' rreg ',' imm ',' rreg
{
- outgcode($1, &$2, $4.reg, &$6, &$8);
+ outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
}
| LRLWM imm ',' rreg ',' mask ',' rreg
{
- outgcode($1, &$2, $4.reg, &$6, &$8);
+ outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
}
| LRLWM rreg ',' rreg ',' imm ',' rreg
{
- outgcode($1, &$2, $4.reg, &$6, &$8);
+ outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
}
| LRLWM rreg ',' rreg ',' mask ',' rreg
{
- outgcode($1, &$2, $4.reg, &$6, &$8);
+ outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
}
/*
* load/store multiple
*/
| LMOVMW addr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LMOVMW rreg ',' addr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
/*
* various indexed load/store
@@ -523,112 +529,115 @@ inst:
*/
| LXLD regaddr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LXLD regaddr ',' imm ',' rreg
{
- outgcode($1, &$2, 0, &$4, &$6);
+ outgcode(int($1), &$2, 0, &$4, &$6);
}
| LXST rreg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LXST rreg ',' imm ',' regaddr
{
- outgcode($1, &$2, 0, &$4, &$6);
+ outgcode(int($1), &$2, 0, &$4, &$6);
}
| LXMV regaddr ',' rreg
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LXMV rreg ',' regaddr
{
- outcode($1, &$2, 0, &$4);
+ outcode(int($1), &$2, 0, &$4);
}
| LXOP regaddr
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
/*
* NOP
*/
| LNOP comma
{
- outcode($1, &nullgen, 0, &nullgen);
+ outcode(int($1), &nullgen, 0, &nullgen);
}
| LNOP rreg comma
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
| LNOP freg comma
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
| LNOP ',' rreg
{
- outcode($1, &nullgen, 0, &$3);
+ outcode(int($1), &nullgen, 0, &$3);
}
| LNOP ',' freg
{
- outcode($1, &nullgen, 0, &$3);
+ outcode(int($1), &nullgen, 0, &$3);
}
| LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
/*
* word
*/
| LWORD imm comma
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
| LWORD ximm comma
{
- outcode($1, &$2, 0, &nullgen);
+ outcode(int($1), &$2, 0, &nullgen);
}
/*
* PCDATA
*/
| LPCDAT imm ',' imm
{
- if($2.type != TYPE_CONST || $4.type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
- outcode($1, &$2, 0, &$4);
+ if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST {
+ yyerror("arguments to PCDATA must be integer constants")
+ }
+ outcode(int($1), &$2, 0, &$4);
}
/*
* FUNCDATA
*/
| LFUNCDAT imm ',' addr
{
- if($2.type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM)
- yyerror("value for FUNCDATA must be symbol reference");
- outcode($1, &$2, 0, &$4);
+ if $2.Type != obj.TYPE_CONST {
+ yyerror("index for FUNCDATA must be integer constant")
+ }
+ if $4.Type != obj.TYPE_MEM || ($4.Name != obj.NAME_EXTERN && $4.Name != obj.NAME_STATIC) {
+ yyerror("value for FUNCDATA must be symbol reference")
+ }
+ outcode(int($1), &$2, 0, &$4);
}
/*
* END
*/
| LEND comma
{
- outcode($1, &nullgen, 0, &nullgen);
+ outcode(int($1), &nullgen, 0, &nullgen);
}
/*
* TEXT
*/
| LTEXT name ',' '$' textsize
{
- settext($2.sym);
- outcode($1, &$2, 0, &$5);
+ asm.Settext($2.Sym);
+ outcode(int($1), &$2, 0, &$5);
}
| LTEXT name ',' con ',' '$' textsize
{
- settext($2.sym);
- outcode($1, &$2, 0, &$7);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym);
+ outcode(int($1), &$2, int($4), &$7);
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
/*
@@ -636,16 +645,16 @@ inst:
*/
| LGLOBL name ',' imm
{
- settext($2.sym);
- outcode($1, &$2, 0, &$4);
+ asm.Settext($2.Sym)
+ outcode(int($1), &$2, 0, &$4)
}
| LGLOBL name ',' con ',' imm
{
- settext($2.sym);
- outcode($1, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ asm.Settext($2.Sym)
+ outcode(int($1), &$2, 0, &$6)
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
@@ -654,26 +663,26 @@ inst:
*/
| LDATA name '/' con ',' imm
{
- outcode($1, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ outcode(int($1), &$2, 0, &$6);
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
| LDATA name '/' con ',' ximm
{
- outcode($1, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ outcode(int($1), &$2, 0, &$6);
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
| LDATA name '/' con ',' fimm
{
- outcode($1, &$2, 0, &$6);
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = $4;
+ outcode(int($1), &$2, 0, &$6);
+ if asm.Pass > 1 {
+ lastpc.From3.Type = obj.TYPE_CONST
+ lastpc.From3.Offset = $4
}
}
/*
@@ -681,32 +690,33 @@ inst:
*/
| LRETRN comma
{
- outcode($1, &nullgen, 0, &nullgen);
+ outcode(int($1), &nullgen, 0, &nullgen);
}
rel:
con '(' LPC ')'
{
$$ = nullgen;
- $$.type = TYPE_BRANCH;
- $$.offset = $1 + pc;
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1 + int64(asm.PC);
}
| LNAME offset
{
- $1 = labellookup($1);
+ $1 = asm.LabelLookup($1);
$$ = nullgen;
- if(pass == 2 && $1->type != LLAB)
- yyerror("undefined label: %s", $1->labelname);
- $$.type = TYPE_BRANCH;
- $$.offset = $1->value + $2;
+ if asm.Pass == 2 && $1.Type != LLAB {
+ yyerror("undefined label: %s", $1.Labelname)
+ }
+ $$.Type = obj.TYPE_BRANCH;
+ $$.Offset = $1.Value + $2;
}
rreg:
sreg
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
xlreg:
@@ -717,48 +727,49 @@ lr:
LLR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
lcr:
LCR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1; /* whole register */
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1); /* whole register */
}
ctr:
LCTR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
msr:
LMSR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1)
}
psr:
LSPREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
| LSPR '(' con ')'
{
- if($3 < 0 || $3 >= 1024)
- yyerror("SPR/DCR out of range");
+ if $3 < 0 || $3 >= 1024 {
+ yyerror("SPR/DCR out of range")
+ }
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1 + $3;
+ $$.Type = obj.TYPE_REG
+ $$.Reg = int16($1 + $3);
}
| msr
@@ -766,137 +777,140 @@ fpscr:
LFPSCR
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
freg:
LFREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
| LF '(' con ')'
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = REG_F0 + $3;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16(REG_F0 + $3);
}
creg:
LCREG
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
| LCR '(' con ')'
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = REG_C0 + $3;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16(REG_C0 + $3);
}
cbit: con
{
$$ = nullgen;
- $$.type = TYPE_REG;
- $$.reg = $1;
+ $$.Type = obj.TYPE_REG;
+ $$.Reg = int16($1);
}
mask:
con ',' con
{
- int mb, me;
- uint32 v;
+ var mb, me int
+ var v uint32
$$ = nullgen;
- $$.type = TYPE_CONST;
- mb = $1;
- me = $3;
+ $$.Type = obj.TYPE_CONST;
+ mb = int($1);
+ me = int($3);
if(mb < 0 || mb > 31 || me < 0 || me > 31){
yyerror("illegal mask start/end value(s)");
- mb = me = 0;
+ mb = 0
+ me = 0;
+ }
+ if mb <= me {
+ v = (^uint32(0)>>uint(mb)) & (^uint32(0)<<uint(31-me))
+ } else {
+ v = (^uint32(0)>>uint(me+1)) & (^uint32(0)<<uint(31-(mb-1)))
}
- if(mb <= me)
- v = ((uint32)~0L>>mb) & (~0L<<(31-me));
- else
- v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
- $$.offset = v;
+ $$.Offset = int64(v);
}
textsize:
LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = int64($1)
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = ArgsSizeUnknown;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -int64($2)
+ $$.U.Argsize = obj.ArgsSizeUnknown;
}
| LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = $1;
- $$.u.argsize = $3;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = int64($1)
+ $$.U.Argsize = int32($3);
}
| '-' LCONST '-' LCONST
{
$$ = nullgen;
- $$.type = TYPE_TEXTSIZE;
- $$.offset = -$2;
- $$.u.argsize = $4;
+ $$.Type = obj.TYPE_TEXTSIZE;
+ $$.Offset = -int64($2)
+ $$.U.Argsize = int32($4);
}
ximm:
'$' addr
{
$$ = $2;
- $$.type = TYPE_ADDR;
+ $$.Type = obj.TYPE_ADDR;
}
| '$' LSCONST
{
$$ = nullgen;
- $$.type = TYPE_SCONST;
- memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ $$.Type = obj.TYPE_SCONST;
+ $$.U.Sval = $2
}
fimm:
'$' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = $2;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
- $$.type = TYPE_FCONST;
- $$.u.dval = -$3;
+ $$.Type = obj.TYPE_FCONST;
+ $$.U.Dval = -$3;
}
imm: '$' con
{
$$ = nullgen;
- $$.type = TYPE_CONST;
- $$.offset = $2;
+ $$.Type = obj.TYPE_CONST;
+ $$.Offset = $2;
}
sreg:
LREG
| LR '(' con ')'
{
- if($$ < 0 || $$ >= NREG)
- print("register value out of range\n");
+ if $$ < 0 || $$ >= NREG {
+ print("register value out of range\n")
+ }
$$ = REG_R0 + $3;
}
@@ -904,17 +918,17 @@ regaddr:
'(' sreg ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
- $$.offset = 0;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($2);
+ $$.Offset = 0;
}
| '(' sreg '+' sreg ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $2;
- $$.scale = $4;
- $$.offset = 0;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($2);
+ $$.Scale = int8($4);
+ $$.Offset = 0;
}
addr:
@@ -922,35 +936,35 @@ addr:
| con '(' sreg ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.reg = $3;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM;
+ $$.Reg = int16($3);
+ $$.Offset = $1;
}
name:
con '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $3;
- $$.sym = nil;
- $$.offset = $1;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = int8($3);
+ $$.Sym = nil;
+ $$.Offset = $1;
}
| LNAME offset '(' pointer ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = $4;
- $$.sym = linklookup(ctxt, $1->name, 0);
- $$.offset = $2;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = int8($4);
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
+ $$.Offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
- $$.type = TYPE_MEM;
- $$.name = NAME_STATIC;
- $$.sym = linklookup(ctxt, $1->name, 1);
- $$.offset = $4;
+ $$.Type = obj.TYPE_MEM;
+ $$.Name = obj.NAME_STATIC;
+ $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
+ $$.Offset = $4;
}
comma:
@@ -978,7 +992,7 @@ con:
LCONST
| LVAR
{
- $$ = $1->value;
+ $$ = $1.Value;
}
| '-' con
{
@@ -990,7 +1004,7 @@ con:
}
| '~' con
{
- $$ = ~$2;
+ $$ = ^$2;
}
| '(' expr ')'
{
@@ -1021,11 +1035,11 @@ expr:
}
| expr '<' '<' expr
{
- $$ = $1 << $4;
+ $$ = $1 << uint($4);
}
| expr '>' '>' expr
{
- $$ = $1 >> $4;
+ $$ = $1 >> uint($4);
}
| expr '&' expr
{
diff --git a/src/cmd/9a/doc.go b/src/cmd/9a/doc.go
deleted file mode 100644
index f6eed6d86e..0000000000
--- a/src/cmd/9a/doc.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-9a is a version of the Plan 9 assembler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
- http://golang.org/doc/asm
-
-Its target architecture is 64-bit PowerPC and Power Architecture processors,
-referred to by these tools as ppc64 (big endian) or ppc64le (little endian).
-
-*/
-package main
diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c
deleted file mode 100644
index ad552370d4..0000000000
--- a/src/cmd/9a/lex.c
+++ /dev/null
@@ -1,726 +0,0 @@
-// cmd/9a/lex.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.
-
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
- Plan9 = 1<<0,
- Unix = 1<<1,
- Windows = 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
- return sys&Windows;
-#else
- return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
- return '/';
-}
-
-int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
- if(nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
-}
-
-LinkArch* thelinkarch = &linkppc64;
-
-void
-usage(void)
-{
- print("usage: %ca [options] file.c...\n", thechar);
- flagprint(1);
- errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
- char *p;
-
- thechar = '9';
- thestring = "ppc64";
-
- // Allow GOARCH=thestring or GOARCH=thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
- if(strcmp(p, "ppc64le") == 0)
- thelinkarch = &linkppc64le;
-
- ctxt = linknew(thelinkarch);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- ctxt->enforce_data_order = 1;
- Binit(&bstdout, 1, OWRITE);
- listinit9();
- fmtinstall('L', Lconv);
-
- ensuresymb(NSYMB);
- memset(debug, 0, sizeof(debug));
- cinit();
- outfile = 0;
- setinclude(".");
-
- flagfn1("D", "name[=value]: add #define", dodef);
- flagfn1("I", "dir: add dir to include path", setinclude);
- flagcount("S", "print assembly and machine code", &debug['S']);
- flagcount("m", "debug preprocessor macros", &debug['m']);
- flagstr("o", "file: set output file", &outfile);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
-
- if(argc < 1)
- usage();
- if(argc > 1){
- print("can't assemble multiple files\n");
- errorexit();
- }
-
- if(assemble(argv[0]))
- errorexit();
- Bflush(&bstdout);
- if(nerrors > 0)
- errorexit();
- exits(0);
-}
-
-int
-assemble(char *file)
-{
- char *ofile, *p;
- int i, of;
-
- ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
- strcpy(ofile, file);
- p = utfrrune(ofile, pathchar());
- if(p) {
- include[0] = ofile;
- *p++ = 0;
- } else
- p = ofile;
- if(outfile == 0) {
- outfile = p;
- if(outfile){
- p = utfrrune(outfile, '.');
- if(p)
- if(p[1] == 's' && p[2] == 0)
- p[0] = 0;
- p = utfrune(outfile, 0);
- p[0] = '.';
- p[1] = thechar;
- p[2] = 0;
- } else
- outfile = "/dev/null";
- }
-
- of = create(outfile, OWRITE, 0664);
- if(of < 0) {
- yyerror("%ca: cannot create %s", thechar, outfile);
- errorexit();
- }
- Binit(&obuf, of, OWRITE);
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- Bprint(&obuf, "!\n");
-
- for(pass = 1; pass <= 2; pass++) {
- nosched = 0;
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- if(nerrors)
- return nerrors;
- }
-
- writeobj(ctxt, &obuf);
- Bflush(&obuf);
- return 0;
-}
-
-struct
-{
- char *name;
- ushort type;
- ushort value;
-} itab[] =
-{
- "SP", LSP, NAME_AUTO,
- "SB", LSB, NAME_EXTERN,
- "FP", LFP, NAME_PARAM,
- "PC", LPC, TYPE_BRANCH,
-
- "LR", LLR, REG_LR,
- "CTR", LCTR, REG_CTR,
-
- "XER", LSPREG, REG_XER,
- "MSR", LMSR, REG_MSR,
- "FPSCR", LFPSCR, REG_FPSCR,
- "SPR", LSPR, REG_SPR0,
- "DCR", LSPR, REG_DCR0,
-
- "CR", LCR, REG_CR,
- "CR0", LCREG, REG_C0,
- "CR1", LCREG, REG_C1,
- "CR2", LCREG, REG_C2,
- "CR3", LCREG, REG_C3,
- "CR4", LCREG, REG_C4,
- "CR5", LCREG, REG_C5,
- "CR6", LCREG, REG_C6,
- "CR7", LCREG, REG_C7,
-
- "R", LR, 0,
- "R0", LREG, REG_R0,
- "R1", LREG, REG_R1,
- "R2", LREG, REG_R2,
- "R3", LREG, REG_R3,
- "R4", LREG, REG_R4,
- "R5", LREG, REG_R5,
- "R6", LREG, REG_R6,
- "R7", LREG, REG_R7,
- "R8", LREG, REG_R8,
- "R9", LREG, REG_R9,
- "R10", LREG, REG_R10,
- "R11", LREG, REG_R11,
- "R12", LREG, REG_R12,
- "R13", LREG, REG_R13,
- "R14", LREG, REG_R14,
- "R15", LREG, REG_R15,
- "R16", LREG, REG_R16,
- "R17", LREG, REG_R17,
- "R18", LREG, REG_R18,
- "R19", LREG, REG_R19,
- "R20", LREG, REG_R20,
- "R21", LREG, REG_R21,
- "R22", LREG, REG_R22,
- "R23", LREG, REG_R23,
- "R24", LREG, REG_R24,
- "R25", LREG, REG_R25,
- "R26", LREG, REG_R26,
- "R27", LREG, REG_R27,
- "R28", LREG, REG_R28,
- "R29", LREG, REG_R29,
- "g", LREG, REG_R30, // avoid unintentionally clobbering g using R30
- "R31", LREG, REG_R31,
-
- "F", LF, 0,
- "F0", LFREG, REG_F0,
- "F1", LFREG, REG_F1,
- "F2", LFREG, REG_F2,
- "F3", LFREG, REG_F3,
- "F4", LFREG, REG_F4,
- "F5", LFREG, REG_F5,
- "F6", LFREG, REG_F6,
- "F7", LFREG, REG_F7,
- "F8", LFREG, REG_F8,
- "F9", LFREG, REG_F9,
- "F10", LFREG, REG_F10,
- "F11", LFREG, REG_F11,
- "F12", LFREG, REG_F12,
- "F13", LFREG, REG_F13,
- "F14", LFREG, REG_F14,
- "F15", LFREG, REG_F15,
- "F16", LFREG, REG_F16,
- "F17", LFREG, REG_F17,
- "F18", LFREG, REG_F18,
- "F19", LFREG, REG_F19,
- "F20", LFREG, REG_F20,
- "F21", LFREG, REG_F21,
- "F22", LFREG, REG_F22,
- "F23", LFREG, REG_F23,
- "F24", LFREG, REG_F24,
- "F25", LFREG, REG_F25,
- "F26", LFREG, REG_F26,
- "F27", LFREG, REG_F27,
- "F28", LFREG, REG_F28,
- "F29", LFREG, REG_F29,
- "F30", LFREG, REG_F30,
- "F31", LFREG, REG_F31,
-
- "CREQV", LCROP, ACREQV,
- "CRXOR", LCROP, ACRXOR,
- "CRAND", LCROP, ACRAND,
- "CROR", LCROP, ACROR,
- "CRANDN", LCROP, ACRANDN,
- "CRORN", LCROP, ACRORN,
- "CRNAND", LCROP, ACRNAND,
- "CRNOR", LCROP, ACRNOR,
-
- "ADD", LADDW, AADD,
- "ADDV", LADDW, AADDV,
- "ADDCC", LADDW, AADDCC,
- "ADDVCC", LADDW, AADDVCC,
- "ADDC", LADDW, AADDC,
- "ADDCV", LADDW, AADDCV,
- "ADDCCC", LADDW, AADDCCC,
- "ADDCVCC", LADDW, AADDCVCC,
- "ADDE", LLOGW, AADDE,
- "ADDEV", LLOGW, AADDEV,
- "ADDECC", LLOGW, AADDECC,
- "ADDEVCC", LLOGW, AADDEVCC,
-
- "ADDME", LABS, AADDME,
- "ADDMEV", LABS, AADDMEV,
- "ADDMECC", LABS, AADDMECC,
- "ADDMEVCC", LABS, AADDMEVCC,
- "ADDZE", LABS, AADDZE,
- "ADDZEV", LABS, AADDZEV,
- "ADDZECC", LABS, AADDZECC,
- "ADDZEVCC", LABS, AADDZEVCC,
-
- "SUB", LADDW, ASUB,
- "SUBV", LADDW, ASUBV,
- "SUBCC", LADDW, ASUBCC,
- "SUBVCC", LADDW, ASUBVCC,
- "SUBE", LLOGW, ASUBE,
- "SUBECC", LLOGW, ASUBECC,
- "SUBEV", LLOGW, ASUBEV,
- "SUBEVCC", LLOGW, ASUBEVCC,
- "SUBC", LADDW, ASUBC,
- "SUBCCC", LADDW, ASUBCCC,
- "SUBCV", LADDW, ASUBCV,
- "SUBCVCC", LADDW, ASUBCVCC,
-
- "SUBME", LABS, ASUBME,
- "SUBMEV", LABS, ASUBMEV,
- "SUBMECC", LABS, ASUBMECC,
- "SUBMEVCC", LABS, ASUBMEVCC,
- "SUBZE", LABS, ASUBZE,
- "SUBZEV", LABS, ASUBZEV,
- "SUBZECC", LABS, ASUBZECC,
- "SUBZEVCC", LABS, ASUBZEVCC,
-
- "AND", LADDW, AAND,
- "ANDCC", LADDW, AANDCC, /* includes andil & andiu */
- "ANDN", LLOGW, AANDN,
- "ANDNCC", LLOGW, AANDNCC,
- "EQV", LLOGW, AEQV,
- "EQVCC", LLOGW, AEQVCC,
- "NAND", LLOGW, ANAND,
- "NANDCC", LLOGW, ANANDCC,
- "NOR", LLOGW, ANOR,
- "NORCC", LLOGW, ANORCC,
- "OR", LADDW, AOR, /* includes oril & oriu */
- "ORCC", LADDW, AORCC,
- "ORN", LLOGW, AORN,
- "ORNCC", LLOGW, AORNCC,
- "XOR", LADDW, AXOR, /* includes xoril & xoriu */
- "XORCC", LLOGW, AXORCC,
-
- "EXTSB", LABS, AEXTSB,
- "EXTSBCC", LABS, AEXTSBCC,
- "EXTSH", LABS, AEXTSH,
- "EXTSHCC", LABS, AEXTSHCC,
-
- "CNTLZW", LABS, ACNTLZW,
- "CNTLZWCC", LABS, ACNTLZWCC,
-
- "RLWMI", LRLWM, ARLWMI,
- "RLWMICC", LRLWM, ARLWMICC,
- "RLWNM", LRLWM, ARLWNM,
- "RLWNMCC", LRLWM, ARLWNMCC,
-
- "SLW", LSHW, ASLW,
- "SLWCC", LSHW, ASLWCC,
- "SRW", LSHW, ASRW,
- "SRWCC", LSHW, ASRWCC,
- "SRAW", LSHW, ASRAW,
- "SRAWCC", LSHW, ASRAWCC,
-
- "BR", LBRA, ABR,
- "BC", LBRA, ABC,
- "BCL", LBRA, ABC,
- "BL", LBRA, ABL,
- "BEQ", LBRA, ABEQ,
- "BNE", LBRA, ABNE,
- "BGT", LBRA, ABGT,
- "BGE", LBRA, ABGE,
- "BLT", LBRA, ABLT,
- "BLE", LBRA, ABLE,
- "BVC", LBRA, ABVC,
- "BVS", LBRA, ABVS,
-
- "CMP", LCMP, ACMP,
- "CMPU", LCMP, ACMPU,
- "CMPW", LCMP, ACMPW,
- "CMPWU", LCMP, ACMPWU,
-
- "DIVW", LLOGW, ADIVW,
- "DIVWV", LLOGW, ADIVWV,
- "DIVWCC", LLOGW, ADIVWCC,
- "DIVWVCC", LLOGW, ADIVWVCC,
- "DIVWU", LLOGW, ADIVWU,
- "DIVWUV", LLOGW, ADIVWUV,
- "DIVWUCC", LLOGW, ADIVWUCC,
- "DIVWUVCC", LLOGW, ADIVWUVCC,
-
- "FABS", LFCONV, AFABS,
- "FABSCC", LFCONV, AFABSCC,
- "FNEG", LFCONV, AFNEG,
- "FNEGCC", LFCONV, AFNEGCC,
- "FNABS", LFCONV, AFNABS,
- "FNABSCC", LFCONV, AFNABSCC,
-
- "FADD", LFADD, AFADD,
- "FADDCC", LFADD, AFADDCC,
- "FSUB", LFADD, AFSUB,
- "FSUBCC", LFADD, AFSUBCC,
- "FMUL", LFADD, AFMUL,
- "FMULCC", LFADD, AFMULCC,
- "FDIV", LFADD, AFDIV,
- "FDIVCC", LFADD, AFDIVCC,
- "FRSP", LFCONV, AFRSP,
- "FRSPCC", LFCONV, AFRSPCC,
- "FCTIW", LFCONV, AFCTIW,
- "FCTIWCC", LFCONV, AFCTIWCC,
- "FCTIWZ", LFCONV, AFCTIWZ,
- "FCTIWZCC", LFCONV, AFCTIWZCC,
-
- "FMADD", LFMA, AFMADD,
- "FMADDCC", LFMA, AFMADDCC,
- "FMSUB", LFMA, AFMSUB,
- "FMSUBCC", LFMA, AFMSUBCC,
- "FNMADD", LFMA, AFNMADD,
- "FNMADDCC", LFMA, AFNMADDCC,
- "FNMSUB", LFMA, AFNMSUB,
- "FNMSUBCC", LFMA, AFNMSUBCC,
- "FMADDS", LFMA, AFMADDS,
- "FMADDSCC", LFMA, AFMADDSCC,
- "FMSUBS", LFMA, AFMSUBS,
- "FMSUBSCC", LFMA, AFMSUBSCC,
- "FNMADDS", LFMA, AFNMADDS,
- "FNMADDSCC", LFMA, AFNMADDSCC,
- "FNMSUBS", LFMA, AFNMSUBS,
- "FNMSUBSCC", LFMA, AFNMSUBSCC,
-
- "FCMPU", LFCMP, AFCMPU,
- "FCMPO", LFCMP, AFCMPO,
- "MTFSB0", LMTFSB, AMTFSB0,
- "MTFSB1", LMTFSB, AMTFSB1,
-
- "FMOVD", LFMOV, AFMOVD,
- "FMOVS", LFMOV, AFMOVS,
- "FMOVDCC", LFCONV, AFMOVDCC, /* fmr. */
-
- "GLOBL", LGLOBL, AGLOBL,
-
- "MOVB", LMOVB, AMOVB,
- "MOVBZ", LMOVB, AMOVBZ,
- "MOVBU", LMOVB, AMOVBU,
- "MOVBZU", LMOVB, AMOVBZU,
- "MOVH", LMOVB, AMOVH,
- "MOVHZ", LMOVB, AMOVHZ,
- "MOVHU", LMOVB, AMOVHU,
- "MOVHZU", LMOVB, AMOVHZU,
- "MOVHBR", LXMV, AMOVHBR,
- "MOVWBR", LXMV, AMOVWBR,
- "MOVW", LMOVW, AMOVW,
- "MOVWU", LMOVW, AMOVWU,
- "MOVMW", LMOVMW, AMOVMW,
- "MOVFL", LMOVW, AMOVFL,
-
- "MULLW", LADDW, AMULLW, /* includes multiply immediate 10-139 */
- "MULLWV", LLOGW, AMULLWV,
- "MULLWCC", LLOGW, AMULLWCC,
- "MULLWVCC", LLOGW, AMULLWVCC,
-
- "MULHW", LLOGW, AMULHW,
- "MULHWCC", LLOGW, AMULHWCC,
- "MULHWU", LLOGW, AMULHWU,
- "MULHWUCC", LLOGW, AMULHWUCC,
-
- "NEG", LABS, ANEG,
- "NEGV", LABS, ANEGV,
- "NEGCC", LABS, ANEGCC,
- "NEGVCC", LABS, ANEGVCC,
-
- "NOP", LNOP, ANOP, /* ori 0,0,0 */
- "SYSCALL", LNOP, ASYSCALL,
- "UNDEF", LNOP, AUNDEF,
-
- "RET", LRETRN, ARETURN,
- "RETURN", LRETRN, ARETURN,
- "RFI", LRETRN, ARFI,
- "RFCI", LRETRN, ARFCI,
-
- "DATA", LDATA, ADATA,
- "END", LEND, AEND,
- "TEXT", LTEXT, ATEXT,
-
- /* 64-bit instructions */
- "CNTLZD", LABS, ACNTLZD,
- "CNTLZDCC", LABS, ACNTLZDCC,
- "DIVD", LLOGW, ADIVD,
- "DIVDCC", LLOGW, ADIVDCC,
- "DIVDVCC", LLOGW, ADIVDVCC,
- "DIVDV", LLOGW, ADIVDV,
- "DIVDU", LLOGW, ADIVDU,
- "DIVDUCC", LLOGW, ADIVDUCC,
- "DIVDUVCC", LLOGW, ADIVDUVCC,
- "DIVDUV", LLOGW, ADIVDUV,
- "EXTSW", LABS, AEXTSW,
- "EXTSWCC", LABS, AEXTSWCC,
- "FCTID", LFCONV, AFCTID,
- "FCTIDCC", LFCONV, AFCTIDCC,
- "FCTIDZ", LFCONV, AFCTIDZ,
- "FCTIDZCC", LFCONV, AFCTIDZCC,
- "FCFID", LFCONV, AFCFID,
- "FCFIDCC", LFCONV, AFCFIDCC,
- "LDAR", LXLD, ALDAR,
- "MOVD", LMOVW, AMOVD,
- "MOVDU", LMOVW, AMOVDU,
- "MOVWZ", LMOVW, AMOVWZ,
- "MOVWZU", LMOVW, AMOVWZU,
- "MULHD", LLOGW, AMULHD,
- "MULHDCC", LLOGW, AMULHDCC,
- "MULHDU", LLOGW, AMULHDU,
- "MULHDUCC", LLOGW, AMULHDUCC,
- "MULLD", LADDW, AMULLD, /* includes multiply immediate? */
- "MULLDCC", LLOGW, AMULLDCC,
- "MULLDVCC", LLOGW, AMULLDVCC,
- "MULLDV", LLOGW, AMULLDV,
- "RFID", LRETRN, ARFID,
- "HRFID", LRETRN, AHRFID,
- "RLDMI", LRLWM, ARLDMI,
- "RLDMICC", LRLWM, ARLDMICC,
- "RLDC", LRLWM, ARLDC,
- "RLDCCC", LRLWM, ARLDCCC,
- "RLDCR", LRLWM, ARLDCR,
- "RLDCRCC", LRLWM, ARLDCRCC,
- "RLDCL", LRLWM, ARLDCL,
- "RLDCLCC", LRLWM, ARLDCLCC,
- "SLBIA", LNOP, ASLBIA,
- "SLBIE", LNOP, ASLBIE,
- "SLBMFEE", LABS, ASLBMFEE,
- "SLBMFEV", LABS, ASLBMFEV,
- "SLBMTE", LABS, ASLBMTE,
- "SLD", LSHW, ASLD,
- "SLDCC", LSHW, ASLDCC,
- "SRD", LSHW, ASRD,
- "SRAD", LSHW, ASRAD,
- "SRADCC", LSHW, ASRADCC,
- "SRDCC", LSHW, ASRDCC,
- "STDCCC", LXST, ASTDCCC,
- "TD", LADDW, ATD,
-
- /* pseudo instructions */
- "REM", LLOGW, AREM,
- "REMCC", LLOGW, AREMCC,
- "REMV", LLOGW, AREMV,
- "REMVCC", LLOGW, AREMVCC,
- "REMU", LLOGW, AREMU,
- "REMUCC", LLOGW, AREMUCC,
- "REMUV", LLOGW, AREMUV,
- "REMUVCC", LLOGW, AREMUVCC,
- "REMD", LLOGW, AREMD,
- "REMDCC", LLOGW, AREMDCC,
- "REMDV", LLOGW, AREMDV,
- "REMDVCC", LLOGW, AREMDVCC,
- "REMDU", LLOGW, AREMDU,
- "REMDUCC", LLOGW, AREMDUCC,
- "REMDUV", LLOGW, AREMDUV,
- "REMDUVCC", LLOGW, AREMDUVCC,
-
-/* special instructions */
- "DCBF", LXOP, ADCBF,
- "DCBI", LXOP, ADCBI,
- "DCBST", LXOP, ADCBST,
- "DCBT", LXOP, ADCBT,
- "DCBTST", LXOP, ADCBTST,
- "DCBZ", LXOP, ADCBZ,
- "ICBI", LXOP, AICBI,
-
- "ECIWX", LXLD, AECIWX,
- "ECOWX", LXST, AECOWX,
- "LWAR", LXLD, ALWAR,
- "LWAR", LXLD, ALWAR,
- "STWCCC", LXST, ASTWCCC,
- "EIEIO", LRETRN, AEIEIO,
- "TLBIE", LNOP, ATLBIE,
- "TLBIEL", LNOP, ATLBIEL,
- "LSW", LXLD, ALSW,
- "STSW", LXST, ASTSW,
-
- "ISYNC", LRETRN, AISYNC,
- "SYNC", LRETRN, ASYNC,
- "TLBSYNC", LRETRN, ATLBSYNC,
- "PTESYNC", LRETRN, APTESYNC,
-/* "TW", LADDW, ATW,*/
-
- "WORD", LWORD, AWORD,
- "DWORD", LWORD, ADWORD,
- "SCHED", LSCHED, 0,
- "NOSCHED", LSCHED, 0x80,
-
- "PCDATA", LPCDAT, APCDATA,
- "FUNCDATA", LFUNCDAT, AFUNCDATA,
-
- 0
-};
-
-void
-cinit(void)
-{
- Sym *s;
- int i;
-
- nullgen.type = TYPE_NONE;
- nullgen.name = NAME_NONE;
- nullgen.reg = 0;
- nullgen.scale = 0; // replaced Gen.xreg with Prog.scale
-
- nerrors = 0;
- iostack = I;
- iofree = I;
- peekc = IGN;
- nhunk = 0;
- for(i=0; i<NHASH; i++)
- hash[i] = S;
- for(i=0; itab[i].name; i++) {
- s = slookup(itab[i].name);
- s->type = itab[i].type;
- s->value = itab[i].value;
- }
-}
-
-void
-syminit(Sym *s)
-{
-
- s->type = LNAME;
- s->value = 0;
-}
-
-void
-cclean(void)
-{
-
- outcode(AEND, &nullgen, 0, &nullgen);
-}
-
-void
-outcode(int a, Addr *g1, int reg, Addr *g2)
-{
- Prog *p;
- Plist *pl;
-
- if(pass == 1)
- goto out;
-
- if(g1->scale != 0) {
- if(reg != 0 || g2->scale != 0)
- yyerror("bad addressing modes");
- reg = g1->scale;
- } else
- if(g2->scale != 0) {
- if(reg != 0)
- yyerror("bad addressing modes");
- reg = g2->scale;
- }
-
- p = emallocz(sizeof(Prog));
- p->as = a;
- p->lineno = stmtline;
- if(nosched)
- p->mark |= NOSCHED;
- p->from = *g1;
- p->reg = reg;
- p->to = *g2;
- p->pc = pc;
-
- if(lastpc == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastpc->link = p;
- lastpc = p;
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-void
-outgcode(int a, Addr *g1, int reg, Addr *g2, Addr *g3)
-{
- Prog *p;
- Plist *pl;
-
- if(pass == 1)
- goto out;
-
- p = emallocz(sizeof(Prog));
- p->as = a;
- p->lineno = stmtline;
- if(nosched)
- p->mark |= NOSCHED;
- p->from = *g1;
- p->reg = reg;
- p->from3 = *g2;
- p->to = *g3;
- p->pc = pc;
-
- if(lastpc == nil) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastpc->link = p;
- lastpc = p;
-out:
- if(a != AGLOBL && a != ADATA)
- pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/new9a/lex.go b/src/cmd/9a/lex.go
index d480e4540e..d480e4540e 100644
--- a/src/cmd/new9a/lex.go
+++ b/src/cmd/9a/lex.go
diff --git a/src/cmd/new9a/y.go b/src/cmd/9a/y.go
index 2e42378059..2e42378059 100644
--- a/src/cmd/new9a/y.go
+++ b/src/cmd/9a/y.go
diff --git a/src/cmd/9a/y.tab.c b/src/cmd/9a/y.tab.c
deleted file mode 100644
index 829f4d5de2..0000000000
--- a/src/cmd/9a/y.tab.c
+++ /dev/null
@@ -1,3466 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LMOVW = 258,
- LMOVB = 259,
- LABS = 260,
- LLOGW = 261,
- LSHW = 262,
- LADDW = 263,
- LCMP = 264,
- LCROP = 265,
- LBRA = 266,
- LFMOV = 267,
- LFCONV = 268,
- LFCMP = 269,
- LFADD = 270,
- LFMA = 271,
- LTRAP = 272,
- LXORW = 273,
- LNOP = 274,
- LEND = 275,
- LRETT = 276,
- LWORD = 277,
- LTEXT = 278,
- LGLOBL = 279,
- LDATA = 280,
- LRETRN = 281,
- LCONST = 282,
- LSP = 283,
- LSB = 284,
- LFP = 285,
- LPC = 286,
- LCREG = 287,
- LFLUSH = 288,
- LREG = 289,
- LFREG = 290,
- LR = 291,
- LCR = 292,
- LF = 293,
- LFPSCR = 294,
- LLR = 295,
- LCTR = 296,
- LSPR = 297,
- LSPREG = 298,
- LSEG = 299,
- LMSR = 300,
- LPCDAT = 301,
- LFUNCDAT = 302,
- LSCHED = 303,
- LXLD = 304,
- LXST = 305,
- LXOP = 306,
- LXMV = 307,
- LRLWM = 308,
- LMOVMW = 309,
- LMOVEM = 310,
- LMOVFL = 311,
- LMTFSB = 312,
- LMA = 313,
- LFCONST = 314,
- LSCONST = 315,
- LNAME = 316,
- LLAB = 317,
- LVAR = 318
- };
-#endif
-/* Tokens. */
-#define LMOVW 258
-#define LMOVB 259
-#define LABS 260
-#define LLOGW 261
-#define LSHW 262
-#define LADDW 263
-#define LCMP 264
-#define LCROP 265
-#define LBRA 266
-#define LFMOV 267
-#define LFCONV 268
-#define LFCMP 269
-#define LFADD 270
-#define LFMA 271
-#define LTRAP 272
-#define LXORW 273
-#define LNOP 274
-#define LEND 275
-#define LRETT 276
-#define LWORD 277
-#define LTEXT 278
-#define LGLOBL 279
-#define LDATA 280
-#define LRETRN 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LCREG 287
-#define LFLUSH 288
-#define LREG 289
-#define LFREG 290
-#define LR 291
-#define LCR 292
-#define LF 293
-#define LFPSCR 294
-#define LLR 295
-#define LCTR 296
-#define LSPR 297
-#define LSPREG 298
-#define LSEG 299
-#define LMSR 300
-#define LPCDAT 301
-#define LFUNCDAT 302
-#define LSCHED 303
-#define LXLD 304
-#define LXST 305
-#define LXOP 306
-#define LXMV 307
-#define LRLWM 308
-#define LMOVMW 309
-#define LMOVEM 310
-#define LMOVFL 311
-#define LMTFSB 312
-#define LMA 313
-#define LFCONST 314
-#define LSCONST 315
-#define LNAME 316
-#define LLAB 317
-#define LVAR 318
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 30 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
-}
-/* Line 193 of yacc.c. */
-#line 238 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 251 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 880
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 82
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 32
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 187
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 463
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 318
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 80, 12, 5, 2,
- 78, 79, 10, 8, 77, 9, 2, 11, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 74, 76,
- 6, 75, 7, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 2, 81, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
- 65, 66, 67, 68, 69, 70, 71, 72, 73
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 5, 9, 10, 15, 20, 25,
- 28, 30, 33, 36, 41, 46, 51, 56, 61, 66,
- 71, 76, 81, 86, 91, 96, 101, 106, 111, 116,
- 121, 126, 131, 136, 143, 148, 153, 160, 165, 170,
- 177, 184, 191, 196, 201, 208, 213, 220, 225, 232,
- 237, 242, 245, 252, 257, 262, 267, 274, 279, 284,
- 289, 294, 299, 304, 309, 314, 317, 320, 325, 329,
- 333, 339, 344, 349, 356, 361, 366, 373, 380, 387,
- 396, 401, 406, 410, 413, 418, 423, 430, 439, 444,
- 451, 456, 461, 468, 475, 484, 493, 502, 511, 516,
- 521, 526, 533, 538, 545, 550, 555, 558, 561, 565,
- 569, 573, 577, 580, 584, 588, 593, 598, 601, 607,
- 615, 620, 627, 634, 641, 648, 651, 656, 659, 661,
- 663, 665, 667, 669, 671, 673, 675, 680, 682, 684,
- 686, 691, 693, 698, 700, 704, 706, 709, 713, 718,
- 721, 724, 727, 731, 734, 736, 741, 745, 751, 753,
- 758, 763, 769, 777, 778, 780, 781, 784, 787, 789,
- 791, 793, 795, 797, 800, 803, 806, 810, 812, 816,
- 820, 824, 828, 832, 837, 842, 846, 850
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 83, 0, -1, -1, -1, 83, 84, 85, -1, -1,
- 71, 74, 86, 85, -1, 71, 75, 113, 76, -1,
- 73, 75, 113, 76, -1, 58, 76, -1, 76, -1,
- 87, 76, -1, 1, 76, -1, 13, 89, 77, 89,
- -1, 13, 107, 77, 89, -1, 13, 106, 77, 89,
- -1, 14, 89, 77, 89, -1, 14, 107, 77, 89,
- -1, 14, 106, 77, 89, -1, 22, 107, 77, 97,
- -1, 22, 106, 77, 97, -1, 22, 103, 77, 97,
- -1, 22, 97, 77, 97, -1, 22, 97, 77, 107,
- -1, 22, 97, 77, 106, -1, 13, 89, 77, 107,
- -1, 13, 89, 77, 106, -1, 14, 89, 77, 107,
- -1, 14, 89, 77, 106, -1, 13, 97, 77, 107,
- -1, 13, 97, 77, 106, -1, 13, 96, 77, 97,
- -1, 13, 97, 77, 96, -1, 13, 97, 77, 104,
- 77, 96, -1, 13, 96, 77, 98, -1, 67, 104,
- 77, 112, -1, 13, 89, 77, 104, 77, 92, -1,
- 13, 89, 77, 98, -1, 13, 89, 77, 92, -1,
- 18, 89, 77, 105, 77, 89, -1, 18, 104, 77,
- 105, 77, 89, -1, 18, 89, 77, 104, 77, 89,
- -1, 18, 89, 77, 89, -1, 18, 104, 77, 89,
- -1, 16, 89, 77, 105, 77, 89, -1, 16, 89,
- 77, 89, -1, 17, 89, 77, 105, 77, 89, -1,
- 17, 89, 77, 89, -1, 17, 104, 77, 105, 77,
- 89, -1, 17, 104, 77, 89, -1, 15, 89, 77,
- 89, -1, 15, 89, -1, 68, 89, 77, 105, 77,
- 89, -1, 13, 104, 77, 89, -1, 13, 102, 77,
- 89, -1, 20, 99, 77, 99, -1, 20, 99, 77,
- 112, 77, 99, -1, 13, 98, 77, 98, -1, 13,
- 95, 77, 98, -1, 13, 92, 77, 89, -1, 13,
- 95, 77, 89, -1, 13, 90, 77, 89, -1, 13,
- 89, 77, 90, -1, 13, 98, 77, 95, -1, 13,
- 89, 77, 95, -1, 21, 88, -1, 21, 107, -1,
- 21, 78, 90, 79, -1, 21, 77, 88, -1, 21,
- 77, 107, -1, 21, 77, 78, 90, 79, -1, 21,
- 98, 77, 88, -1, 21, 98, 77, 107, -1, 21,
- 98, 77, 78, 90, 79, -1, 21, 112, 77, 88,
- -1, 21, 112, 77, 107, -1, 21, 112, 77, 78,
- 90, 79, -1, 21, 112, 77, 112, 77, 88, -1,
- 21, 112, 77, 112, 77, 107, -1, 21, 112, 77,
- 112, 77, 78, 90, 79, -1, 27, 89, 77, 105,
- -1, 27, 104, 77, 105, -1, 27, 89, 109, -1,
- 27, 109, -1, 23, 97, 77, 97, -1, 25, 97,
- 77, 97, -1, 25, 97, 77, 97, 77, 97, -1,
- 26, 97, 77, 97, 77, 97, 77, 97, -1, 24,
- 97, 77, 97, -1, 24, 97, 77, 97, 77, 98,
- -1, 19, 89, 77, 89, -1, 19, 89, 77, 104,
- -1, 19, 89, 77, 89, 77, 98, -1, 19, 89,
- 77, 104, 77, 98, -1, 63, 104, 77, 89, 77,
- 104, 77, 89, -1, 63, 104, 77, 89, 77, 100,
- 77, 89, -1, 63, 89, 77, 89, 77, 104, 77,
- 89, -1, 63, 89, 77, 89, 77, 100, 77, 89,
- -1, 64, 107, 77, 89, -1, 64, 89, 77, 107,
- -1, 59, 106, 77, 89, -1, 59, 106, 77, 104,
- 77, 89, -1, 60, 89, 77, 106, -1, 60, 89,
- 77, 104, 77, 106, -1, 62, 106, 77, 89, -1,
- 62, 89, 77, 106, -1, 61, 106, -1, 29, 109,
- -1, 29, 89, 109, -1, 29, 97, 109, -1, 29,
- 77, 89, -1, 29, 77, 97, -1, 29, 104, -1,
- 32, 104, 109, -1, 32, 102, 109, -1, 56, 104,
- 77, 104, -1, 57, 104, 77, 107, -1, 30, 109,
- -1, 33, 108, 77, 80, 101, -1, 33, 108, 77,
- 112, 77, 80, 101, -1, 34, 108, 77, 104, -1,
- 34, 108, 77, 112, 77, 104, -1, 35, 108, 11,
- 112, 77, 104, -1, 35, 108, 11, 112, 77, 102,
- -1, 35, 108, 11, 112, 77, 103, -1, 36, 109,
- -1, 112, 78, 41, 79, -1, 71, 110, -1, 105,
- -1, 91, -1, 93, -1, 50, -1, 47, -1, 51,
- -1, 55, -1, 53, -1, 52, 78, 112, 79, -1,
- 94, -1, 49, -1, 45, -1, 48, 78, 112, 79,
- -1, 42, -1, 47, 78, 112, 79, -1, 112, -1,
- 112, 77, 112, -1, 37, -1, 9, 37, -1, 37,
- 9, 37, -1, 9, 37, 9, 37, -1, 80, 107,
- -1, 80, 70, -1, 80, 69, -1, 80, 9, 69,
- -1, 80, 112, -1, 44, -1, 46, 78, 112, 79,
- -1, 78, 105, 79, -1, 78, 105, 8, 105, 79,
- -1, 108, -1, 112, 78, 105, 79, -1, 112, 78,
- 111, 79, -1, 71, 110, 78, 111, 79, -1, 71,
- 6, 7, 110, 78, 39, 79, -1, -1, 77, -1,
- -1, 8, 112, -1, 9, 112, -1, 39, -1, 38,
- -1, 40, -1, 37, -1, 73, -1, 9, 112, -1,
- 8, 112, -1, 81, 112, -1, 78, 113, 79, -1,
- 112, -1, 113, 8, 113, -1, 113, 9, 113, -1,
- 113, 10, 113, -1, 113, 11, 113, -1, 113, 12,
- 113, -1, 113, 6, 6, 113, -1, 113, 7, 7,
- 113, -1, 113, 5, 113, -1, 113, 4, 113, -1,
- 113, 3, 113, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 66, 66, 68, 67, 75, 74, 83, 88, 94,
- 98, 99, 100, 106, 110, 114, 118, 122, 126, 133,
- 137, 141, 145, 149, 153, 160, 164, 168, 172, 179,
- 183, 190, 194, 198, 202, 206, 213, 217, 221, 231,
- 235, 239, 243, 247, 251, 255, 259, 263, 267, 271,
- 275, 279, 286, 293, 297, 304, 308, 316, 320, 324,
- 328, 332, 336, 340, 344, 353, 357, 361, 365, 369,
- 373, 377, 381, 385, 389, 393, 397, 401, 409, 417,
- 428, 432, 436, 440, 447, 451, 455, 459, 463, 467,
- 474, 478, 482, 486, 493, 497, 501, 505, 512, 516,
- 524, 528, 532, 536, 540, 544, 548, 555, 559, 563,
- 567, 571, 575, 582, 586, 593, 602, 613, 620, 625,
- 637, 642, 655, 663, 671, 682, 688, 694, 705, 713,
- 714, 717, 725, 733, 741, 749, 755, 763, 766, 774,
- 780, 788, 794, 802, 810, 831, 838, 845, 852, 861,
- 866, 874, 880, 887, 895, 896, 904, 911, 921, 922,
- 931, 939, 947, 956, 957, 960, 963, 967, 973, 974,
- 975, 978, 979, 983, 987, 991, 995, 1001, 1002, 1006,
- 1010, 1014, 1018, 1022, 1026, 1030, 1034, 1038
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
- "'-'", "'*'", "'/'", "'%'", "LMOVW", "LMOVB", "LABS", "LLOGW", "LSHW",
- "LADDW", "LCMP", "LCROP", "LBRA", "LFMOV", "LFCONV", "LFCMP", "LFADD",
- "LFMA", "LTRAP", "LXORW", "LNOP", "LEND", "LRETT", "LWORD", "LTEXT",
- "LGLOBL", "LDATA", "LRETRN", "LCONST", "LSP", "LSB", "LFP", "LPC",
- "LCREG", "LFLUSH", "LREG", "LFREG", "LR", "LCR", "LF", "LFPSCR", "LLR",
- "LCTR", "LSPR", "LSPREG", "LSEG", "LMSR", "LPCDAT", "LFUNCDAT", "LSCHED",
- "LXLD", "LXST", "LXOP", "LXMV", "LRLWM", "LMOVMW", "LMOVEM", "LMOVFL",
- "LMTFSB", "LMA", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'",
- "'='", "';'", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
- "line", "@2", "inst", "rel", "rreg", "xlreg", "lr", "lcr", "ctr", "msr",
- "psr", "fpscr", "freg", "creg", "cbit", "mask", "textsize", "ximm",
- "fimm", "imm", "sreg", "regaddr", "addr", "name", "comma", "offset",
- "pointer", "con", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
- 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
- 315, 316, 317, 318, 58, 61, 59, 44, 40, 41,
- 36, 126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 82, 83, 84, 83, 86, 85, 85, 85, 85,
- 85, 85, 85, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 88, 88, 89, 90,
- 90, 91, 92, 93, 94, 95, 95, 95, 96, 97,
- 97, 98, 98, 99, 100, 101, 101, 101, 101, 102,
- 102, 103, 103, 104, 105, 105, 106, 106, 107, 107,
- 108, 108, 108, 109, 109, 110, 110, 110, 111, 111,
- 111, 112, 112, 112, 112, 112, 112, 113, 113, 113,
- 113, 113, 113, 113, 113, 113, 113, 113
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 0, 3, 0, 4, 4, 4, 2,
- 1, 2, 2, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 6, 4, 4, 6, 4, 4, 6,
- 6, 6, 4, 4, 6, 4, 6, 4, 6, 4,
- 4, 2, 6, 4, 4, 4, 6, 4, 4, 4,
- 4, 4, 4, 4, 4, 2, 2, 4, 3, 3,
- 5, 4, 4, 6, 4, 4, 6, 6, 6, 8,
- 4, 4, 3, 2, 4, 4, 6, 8, 4, 6,
- 4, 4, 6, 6, 8, 8, 8, 8, 4, 4,
- 4, 6, 4, 6, 4, 4, 2, 2, 3, 3,
- 3, 3, 2, 3, 3, 4, 4, 2, 5, 7,
- 4, 6, 6, 6, 6, 2, 4, 2, 1, 1,
- 1, 1, 1, 1, 1, 1, 4, 1, 1, 1,
- 4, 1, 4, 1, 3, 1, 2, 3, 4, 2,
- 2, 2, 3, 2, 1, 4, 3, 5, 1, 4,
- 4, 5, 7, 0, 1, 0, 2, 2, 1, 1,
- 1, 1, 1, 2, 2, 2, 3, 1, 3, 3,
- 3, 3, 3, 4, 4, 3, 3, 3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 3, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 163,
- 163, 163, 0, 0, 0, 0, 163, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 10, 4, 0, 12, 0, 0, 171, 141, 154, 139,
- 0, 132, 0, 138, 131, 133, 0, 135, 134, 165,
- 172, 0, 0, 0, 0, 0, 129, 0, 130, 137,
- 0, 0, 0, 0, 0, 0, 128, 0, 0, 158,
- 0, 0, 0, 0, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 143, 0, 165, 0, 0, 65,
- 0, 66, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 164, 163, 0, 83, 164, 163, 163, 112,
- 107, 117, 163, 163, 0, 0, 0, 0, 125, 0,
- 0, 9, 0, 0, 0, 106, 0, 0, 0, 0,
- 0, 0, 0, 0, 5, 0, 0, 11, 174, 173,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 177,
- 0, 150, 149, 153, 175, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 153, 0, 0, 0, 0, 0, 0, 127,
- 0, 68, 69, 0, 0, 0, 0, 0, 0, 151,
- 0, 0, 0, 0, 0, 0, 0, 0, 164, 82,
- 0, 110, 111, 108, 109, 114, 113, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 165, 166, 167, 0, 0, 156, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 176, 13, 62, 38,
- 64, 37, 0, 26, 25, 61, 59, 60, 58, 31,
- 34, 32, 0, 30, 29, 63, 57, 54, 53, 15,
- 14, 169, 168, 170, 0, 0, 16, 28, 27, 18,
- 17, 50, 45, 128, 47, 128, 49, 128, 42, 0,
- 128, 43, 128, 90, 91, 55, 143, 0, 67, 0,
- 71, 72, 0, 74, 75, 0, 0, 152, 22, 24,
- 23, 21, 20, 19, 84, 88, 85, 0, 80, 81,
- 0, 0, 120, 0, 0, 115, 116, 100, 0, 0,
- 102, 105, 104, 0, 0, 99, 98, 35, 0, 6,
- 7, 8, 155, 142, 140, 136, 0, 0, 0, 187,
- 186, 185, 0, 0, 178, 179, 180, 181, 182, 0,
- 0, 159, 160, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 70, 0, 0, 0, 126, 0, 0, 0,
- 0, 145, 118, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 161, 157, 183, 184, 132, 36, 33, 44,
- 46, 48, 41, 39, 40, 92, 93, 56, 73, 76,
- 0, 77, 78, 89, 86, 0, 146, 0, 0, 121,
- 0, 123, 124, 122, 101, 103, 0, 0, 0, 0,
- 0, 52, 0, 0, 0, 0, 147, 119, 0, 0,
- 0, 0, 0, 0, 162, 79, 87, 148, 97, 96,
- 144, 95, 94
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 3, 41, 233, 42, 99, 64, 65, 66,
- 67, 68, 69, 70, 71, 72, 73, 93, 436, 392,
- 74, 105, 75, 76, 77, 162, 79, 115, 157, 285,
- 159, 160
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -180
-static const yytype_int16 yypact[] =
-{
- -180, 12, -180, 484, -53, 517, 619, 28, 28, -24,
- -24, 28, 799, 577, 596, -29, -29, -29, -29, 19,
- -11, -51, -38, 701, 701, 701, -51, -19, -19, -8,
- -7, 28, -7, -14, -24, 643, -19, 28, -36, 6,
- -180, -180, 26, -180, 799, 799, -180, -180, -180, -180,
- 7, 27, 51, -180, -180, -180, 61, -180, -180, 188,
- -180, 662, 674, 799, 79, 93, -180, 99, -180, -180,
- 112, 116, 126, 136, 138, 157, -180, 168, 176, -180,
- 80, 179, 182, 184, 186, 194, 799, 196, 198, 200,
- 201, 202, 799, 203, -180, 27, 188, 714, 676, -180,
- 206, -180, 49, 8, 215, 216, 217, 219, 220, 221,
- 223, 224, -180, 225, 226, -180, 181, -51, -51, -180,
- -180, -180, -51, -51, 227, 158, 231, 296, -180, 232,
- 233, -180, 28, 234, 236, -180, 237, 238, 242, 245,
- 246, 248, 249, 250, -180, 799, 799, -180, -180, -180,
- 799, 799, 799, 799, 321, 799, 799, 251, 3, -180,
- 377, -180, -180, 80, -180, 565, 28, 28, 172, 162,
- 623, 31, 28, 28, 28, 28, 230, 619, 28, 28,
- 28, 28, -180, 28, 28, -24, 28, -24, 799, 251,
- 676, -180, -180, 254, 257, 723, 753, 111, 268, -180,
- 67, -29, -29, -29, -29, -29, -29, -29, 28, -180,
- 28, -180, -180, -180, -180, -180, -180, 733, 96, 760,
- 799, -19, 701, -24, 40, -7, 28, 28, 28, 701,
- 28, 799, 28, 484, 463, 524, 265, 266, 267, 270,
- 135, -180, -180, 96, 28, -180, 799, 799, 799, 341,
- 347, 799, 799, 799, 799, 799, -180, -180, -180, -180,
- -180, -180, 278, -180, -180, -180, -180, -180, -180, -180,
- -180, -180, 279, -180, -180, -180, -180, -180, -180, -180,
- -180, -180, -180, -180, 281, 282, -180, -180, -180, -180,
- -180, -180, -180, 280, -180, 285, -180, 286, -180, 288,
- 289, -180, 297, 299, 301, -180, 319, 294, -180, 676,
- -180, -180, 676, -180, -180, 171, 318, -180, -180, -180,
- -180, -180, -180, -180, -180, 324, 325, 327, -180, -180,
- 9, 328, -180, 329, 330, -180, -180, -180, 331, 335,
- -180, -180, -180, 336, 337, -180, -180, -180, 338, -180,
- -180, -180, -180, -180, -180, -180, 320, 339, 340, 571,
- 430, 82, 799, 799, 153, 153, -180, -180, -180, 374,
- 373, -180, -180, 28, 28, 28, 28, 28, 28, 20,
- 20, 799, -180, 344, 345, 772, -180, 20, -29, -29,
- 390, 419, -180, 349, -19, 350, 28, -7, 760, 760,
- 28, 392, -180, -180, 277, 277, -180, -180, -180, -180,
- -180, -180, -180, -180, -180, -180, -180, -180, -180, -180,
- 676, -180, -180, -180, -180, 355, 436, 411, 9, -180,
- 322, -180, -180, -180, -180, -180, 375, 376, 378, 380,
- 381, -180, 372, 382, -29, 417, -180, -180, 790, 28,
- 28, 799, 28, 28, -180, -180, -180, -180, -180, -180,
- -180, -180, -180
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -180, -180, -180, 229, -180, -180, -73, -6, -62, -180,
- -158, -180, -180, -150, -162, 37, 30, -179, 60, 32,
- -16, 68, 97, 167, 81, 95, 159, 24, -86, 239,
- 35, 87
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -1
-static const yytype_uint16 yytable[] =
-{
- 81, 84, 85, 87, 89, 91, 122, 259, 271, 305,
- 189, 244, 2, 113, 117, 260, 49, 198, 390, 52,
- 48, 275, 50, 43, 191, 134, 112, 136, 138, 140,
- 48, 143, 50, 48, 49, 50, 194, 52, 144, 145,
- 80, 80, 62, 100, 120, 121, 391, 94, 102, 80,
- 128, 104, 108, 109, 110, 111, 86, 118, 125, 125,
- 125, 86, 47, 48, 132, 50, 116, 95, 131, 86,
- 80, 132, 48, 47, 50, 44, 45, 199, 95, 148,
- 149, 146, 245, 56, 57, 150, 58, 82, 249, 250,
- 251, 252, 253, 254, 255, 106, 112, 163, 164, 86,
- 78, 83, 147, 258, 46, 151, 88, 90, 101, 107,
- 211, 133, 49, 135, 137, 52, 114, 119, 132, 123,
- 86, 182, 310, 313, 129, 130, 196, 197, 307, 152,
- 141, 139, 193, 142, 281, 282, 283, 209, 59, 153,
- 60, 213, 214, 155, 156, 61, 215, 216, 63, 281,
- 282, 283, 316, 212, 356, 48, 165, 50, 176, 257,
- 265, 266, 267, 253, 254, 255, 277, 278, 279, 280,
- 166, 286, 289, 290, 291, 292, 167, 294, 296, 298,
- 301, 303, 124, 126, 127, 236, 237, 238, 239, 168,
- 241, 242, 192, 169, 154, 261, 155, 156, 268, 270,
- 80, 276, 417, 170, 47, 80, 269, 49, 408, 95,
- 52, 407, 80, 171, 47, 172, 48, 337, 50, 95,
- 342, 343, 344, 306, 346, 48, 49, 50, 158, 52,
- 193, 315, 234, 235, 173, 80, 218, 318, 321, 322,
- 323, 324, 325, 326, 327, 174, 263, 383, 385, 197,
- 384, 273, 331, 175, 333, 334, 177, 80, 287, 178,
- 264, 179, 262, 180, 80, 274, 347, 272, 281, 282,
- 283, 181, 288, 183, 48, 184, 50, 185, 186, 187,
- 188, 319, 299, 195, 304, 251, 252, 253, 254, 255,
- 311, 314, 200, 201, 202, 320, 203, 204, 205, 158,
- 206, 207, 208, 210, 217, 340, 341, 220, 219, 221,
- 222, 223, 421, 224, 225, 226, 332, 336, 335, 227,
- 338, 339, 228, 229, 345, 230, 231, 232, 240, 243,
- 44, 448, 197, 359, 360, 361, 308, 317, 364, 365,
- 366, 367, 368, 284, 352, 353, 354, 362, 293, 355,
- 295, 297, 300, 302, 363, 369, 370, 373, 443, 46,
- 371, 372, 374, 375, 284, 376, 377, 409, 410, 411,
- 412, 413, 414, 382, 378, 328, 379, 329, 380, 431,
- 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
- 434, 199, 161, 59, 441, 60, 381, 386, 401, 348,
- 92, 387, 388, 63, 389, 393, 394, 395, 396, 415,
- 416, 358, 397, 398, 399, 400, 94, 423, 402, 403,
- 193, 406, 53, 418, 419, 424, 425, 426, 427, 428,
- 430, 442, 444, 438, 438, 248, 249, 250, 251, 252,
- 253, 254, 255, 458, 459, 445, 461, 462, 446, 404,
- 405, 454, 449, 450, 457, 451, 256, 452, 453, 439,
- 447, 455, 349, 432, 0, 163, 246, 247, 248, 249,
- 250, 251, 252, 253, 254, 255, 0, 0, 435, 0,
- 422, 456, 357, 149, 0, 4, 460, 0, 0, 0,
- 0, 429, 433, 0, 0, 437, 440, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 0, 20, 21, 0, 22, 23, 24, 25,
- 26, 0, 0, 0, 0, 44, 45, 246, 247, 248,
- 249, 250, 251, 252, 253, 254, 255, 0, 0, 350,
- 27, 28, 29, 30, 31, 32, 33, 34, 35, 0,
- 0, 36, 37, 0, 46, 38, 0, 39, 0, 47,
- 40, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- 57, 0, 58, 44, 45, 247, 248, 249, 250, 251,
- 252, 253, 254, 255, 0, 44, 45, 0, 59, 0,
- 60, 0, 0, 0, 0, 61, 0, 62, 63, 0,
- 351, 0, 46, 0, 44, 45, 0, 47, 0, 48,
- 0, 50, 51, 0, 46, 54, 55, 56, 57, 47,
- 58, 0, 0, 0, 95, 0, 0, 44, 45, 0,
- 0, 44, 45, 46, 0, 0, 59, 0, 60, 0,
- 0, 49, 0, 61, 52, 86, 63, 0, 96, 0,
- 60, 44, 45, 0, 97, 98, 46, 0, 63, 0,
- 46, 0, 0, 48, 0, 50, 0, 59, 0, 60,
- 44, 45, 53, 0, 61, 0, 103, 63, 0, 0,
- 46, 0, 44, 45, 44, 45, 0, 48, 0, 50,
- 59, 0, 60, 0, 59, 0, 60, 61, 0, 46,
- 63, 61, 0, 86, 63, 0, 48, 0, 50, 44,
- 45, 46, 0, 46, 59, 0, 60, 0, 0, 0,
- 0, 92, 44, 45, 63, 0, 54, 55, 0, 0,
- 0, 44, 45, 0, 0, 60, 0, 0, 46, 0,
- 92, 44, 45, 63, 161, 59, 0, 60, 0, 60,
- 0, 46, 92, 0, 92, 63, 0, 63, 0, 0,
- 46, 44, 45, 0, 0, 0, 0, 0, 44, 45,
- 46, 0, 59, 0, 60, 0, 0, 0, 0, 92,
- 44, 45, 63, 0, 0, 96, 0, 60, 0, 0,
- 46, 0, 190, 0, 96, 63, 60, 46, 44, 45,
- 0, 309, 0, 0, 63, 0, 60, 44, 45, 46,
- 0, 92, 0, 330, 63, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 96, 0, 60, 46, 0, 0,
- 0, 312, 0, 60, 63, 0, 46, 0, 92, 0,
- 86, 63, 0, 96, 0, 60, 0, 0, 0, 0,
- 420, 0, 0, 63, 0, 0, 0, 0, 0, 317,
- 0, 0, 0, 60, 0, 0, 0, 0, 92, 0,
- 0, 63, 60, 0, 0, 0, 0, 92, 0, 0,
- 63
-};
-
-static const yytype_int16 yycheck[] =
-{
- 6, 7, 8, 9, 10, 11, 22, 165, 170, 188,
- 96, 8, 0, 19, 20, 165, 45, 9, 9, 48,
- 44, 171, 46, 76, 97, 31, 77, 33, 34, 35,
- 44, 37, 46, 44, 45, 46, 98, 48, 74, 75,
- 5, 6, 80, 13, 20, 21, 37, 12, 13, 14,
- 26, 14, 15, 16, 17, 18, 80, 20, 23, 24,
- 25, 80, 42, 44, 78, 46, 77, 47, 76, 80,
- 35, 78, 44, 42, 46, 8, 9, 69, 47, 44,
- 45, 75, 79, 52, 53, 78, 55, 6, 6, 7,
- 8, 9, 10, 11, 12, 14, 77, 62, 63, 80,
- 5, 6, 76, 165, 37, 78, 9, 10, 13, 14,
- 116, 30, 45, 32, 33, 48, 19, 20, 78, 22,
- 80, 86, 195, 196, 27, 28, 77, 78, 190, 78,
- 35, 34, 97, 36, 38, 39, 40, 113, 71, 78,
- 73, 117, 118, 8, 9, 78, 122, 123, 81, 38,
- 39, 40, 41, 116, 240, 44, 77, 46, 78, 165,
- 166, 167, 168, 10, 11, 12, 172, 173, 174, 175,
- 77, 177, 178, 179, 180, 181, 77, 183, 184, 185,
- 186, 187, 23, 24, 25, 150, 151, 152, 153, 77,
- 155, 156, 97, 77, 6, 165, 8, 9, 168, 169,
- 165, 171, 381, 77, 42, 170, 169, 45, 370, 47,
- 48, 369, 177, 77, 42, 77, 44, 223, 46, 47,
- 226, 227, 228, 188, 230, 44, 45, 46, 61, 48,
- 195, 196, 145, 146, 77, 200, 78, 200, 201, 202,
- 203, 204, 205, 206, 207, 77, 165, 309, 77, 78,
- 312, 170, 217, 77, 219, 220, 77, 222, 177, 77,
- 165, 77, 165, 77, 229, 170, 231, 170, 38, 39,
- 40, 77, 177, 77, 44, 77, 46, 77, 77, 77,
- 77, 200, 185, 77, 187, 8, 9, 10, 11, 12,
- 195, 196, 77, 77, 77, 200, 77, 77, 77, 132,
- 77, 77, 77, 77, 77, 224, 225, 11, 77, 77,
- 77, 77, 385, 77, 77, 77, 219, 222, 221, 77,
- 223, 224, 77, 77, 229, 77, 77, 77, 7, 78,
- 8, 9, 78, 246, 247, 248, 79, 69, 251, 252,
- 253, 254, 255, 176, 79, 79, 79, 6, 181, 79,
- 183, 184, 185, 186, 7, 77, 77, 77, 420, 37,
- 79, 79, 77, 77, 197, 77, 77, 373, 374, 375,
- 376, 377, 378, 79, 77, 208, 77, 210, 77, 395,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 396, 69, 70, 71, 400, 73, 77, 79, 78, 232,
- 78, 77, 77, 81, 77, 77, 77, 77, 77, 379,
- 380, 244, 77, 77, 77, 77, 381, 387, 79, 79,
- 385, 47, 49, 79, 79, 388, 389, 37, 9, 80,
- 80, 39, 77, 398, 399, 5, 6, 7, 8, 9,
- 10, 11, 12, 449, 450, 9, 452, 453, 37, 362,
- 363, 79, 77, 77, 37, 77, 79, 77, 77, 399,
- 428, 79, 233, 395, -1, 430, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, -1, -1, 397, -1,
- 385, 444, 243, 448, -1, 1, 451, -1, -1, -1,
- -1, 394, 395, -1, -1, 398, 399, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, -1, 29, 30, -1, 32, 33, 34, 35,
- 36, -1, -1, -1, -1, 8, 9, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, -1, -1, 76,
- 56, 57, 58, 59, 60, 61, 62, 63, 64, -1,
- -1, 67, 68, -1, 37, 71, -1, 73, -1, 42,
- 76, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- 53, -1, 55, 8, 9, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, -1, 8, 9, -1, 71, -1,
- 73, -1, -1, -1, -1, 78, -1, 80, 81, -1,
- 76, -1, 37, -1, 8, 9, -1, 42, -1, 44,
- -1, 46, 47, -1, 37, 50, 51, 52, 53, 42,
- 55, -1, -1, -1, 47, -1, -1, 8, 9, -1,
- -1, 8, 9, 37, -1, -1, 71, -1, 73, -1,
- -1, 45, -1, 78, 48, 80, 81, -1, 71, -1,
- 73, 8, 9, -1, 77, 78, 37, -1, 81, -1,
- 37, -1, -1, 44, -1, 46, -1, 71, -1, 73,
- 8, 9, 49, -1, 78, -1, 80, 81, -1, -1,
- 37, -1, 8, 9, 8, 9, -1, 44, -1, 46,
- 71, -1, 73, -1, 71, -1, 73, 78, -1, 37,
- 81, 78, -1, 80, 81, -1, 44, -1, 46, 8,
- 9, 37, -1, 37, 71, -1, 73, -1, -1, -1,
- -1, 78, 8, 9, 81, -1, 50, 51, -1, -1,
- -1, 8, 9, -1, -1, 73, -1, -1, 37, -1,
- 78, 8, 9, 81, 70, 71, -1, 73, -1, 73,
- -1, 37, 78, -1, 78, 81, -1, 81, -1, -1,
- 37, 8, 9, -1, -1, -1, -1, -1, 8, 9,
- 37, -1, 71, -1, 73, -1, -1, -1, -1, 78,
- 8, 9, 81, -1, -1, 71, -1, 73, -1, -1,
- 37, -1, 78, -1, 71, 81, 73, 37, 8, 9,
- -1, 78, -1, -1, 81, -1, 73, 8, 9, 37,
- -1, 78, -1, 80, 81, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 71, -1, 73, 37, -1, -1,
- -1, 78, -1, 73, 81, -1, 37, -1, 78, -1,
- 80, 81, -1, 71, -1, 73, -1, -1, -1, -1,
- 78, -1, -1, 81, -1, -1, -1, -1, -1, 69,
- -1, -1, -1, 73, -1, -1, -1, -1, 78, -1,
- -1, 81, 73, -1, -1, -1, -1, 78, -1, -1,
- 81
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 83, 0, 84, 1, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 29, 30, 32, 33, 34, 35, 36, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 67, 68, 71, 73,
- 76, 85, 87, 76, 8, 9, 37, 42, 44, 45,
- 46, 47, 48, 49, 50, 51, 52, 53, 55, 71,
- 73, 78, 80, 81, 89, 90, 91, 92, 93, 94,
- 95, 96, 97, 98, 102, 104, 105, 106, 107, 108,
- 112, 89, 106, 107, 89, 89, 80, 89, 104, 89,
- 104, 89, 78, 99, 112, 47, 71, 77, 78, 88,
- 98, 107, 112, 80, 97, 103, 106, 107, 97, 97,
- 97, 97, 77, 89, 104, 109, 77, 89, 97, 104,
- 109, 109, 102, 104, 108, 112, 108, 108, 109, 104,
- 104, 76, 78, 106, 89, 106, 89, 106, 89, 104,
- 89, 107, 104, 89, 74, 75, 75, 76, 112, 112,
- 78, 78, 78, 78, 6, 8, 9, 110, 105, 112,
- 113, 70, 107, 112, 112, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 78, 77, 77, 77,
- 77, 77, 112, 77, 77, 77, 77, 77, 77, 110,
- 78, 88, 107, 112, 90, 77, 77, 78, 9, 69,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 109,
- 77, 89, 97, 109, 109, 109, 109, 77, 78, 77,
- 11, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 86, 113, 113, 112, 112, 112, 112,
- 7, 112, 112, 78, 8, 79, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 79, 89, 90, 92,
- 95, 98, 104, 106, 107, 89, 89, 89, 98, 97,
- 98, 96, 104, 106, 107, 95, 98, 89, 89, 89,
- 89, 38, 39, 40, 105, 111, 89, 106, 107, 89,
- 89, 89, 89, 105, 89, 105, 89, 105, 89, 104,
- 105, 89, 105, 89, 104, 99, 112, 90, 79, 78,
- 88, 107, 78, 88, 107, 112, 41, 69, 97, 106,
- 107, 97, 97, 97, 97, 97, 97, 97, 105, 105,
- 80, 112, 104, 112, 112, 104, 107, 89, 104, 104,
- 106, 106, 89, 89, 89, 107, 89, 112, 105, 85,
- 76, 76, 79, 79, 79, 79, 110, 111, 105, 113,
- 113, 113, 6, 7, 113, 113, 113, 113, 113, 77,
- 77, 79, 79, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 79, 90, 90, 77, 79, 77, 77, 77,
- 9, 37, 101, 77, 77, 77, 77, 77, 77, 77,
- 77, 78, 79, 79, 113, 113, 47, 92, 96, 89,
- 89, 89, 89, 89, 89, 98, 98, 99, 79, 79,
- 78, 88, 107, 98, 97, 97, 37, 9, 80, 104,
- 80, 102, 103, 104, 89, 106, 100, 104, 112, 100,
- 104, 89, 39, 90, 77, 9, 37, 101, 9, 77,
- 77, 77, 77, 77, 79, 79, 97, 37, 89, 89,
- 112, 89, 89
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 3:
-#line 68 "a.y"
- {
- stmtline = lineno;
- }
- break;
-
- case 5:
-#line 75 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc)
- yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyvsp[(1) - (2)].sym)->type = LLAB;
- (yyvsp[(1) - (2)].sym)->value = pc;
- }
- break;
-
- case 7:
-#line 84 "a.y"
- {
- (yyvsp[(1) - (4)].sym)->type = LVAR;
- (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 8:
-#line 89 "a.y"
- {
- if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
- yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
- (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 9:
-#line 95 "a.y"
- {
- nosched = (yyvsp[(1) - (2)].lval);
- }
- break;
-
- case 13:
-#line 107 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 14:
-#line 111 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 15:
-#line 115 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 16:
-#line 119 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 17:
-#line 123 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 18:
-#line 127 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 19:
-#line 134 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 20:
-#line 138 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 21:
-#line 142 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 22:
-#line 146 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 23:
-#line 150 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 24:
-#line 154 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 25:
-#line 161 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 26:
-#line 165 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 27:
-#line 169 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 28:
-#line 173 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 29:
-#line 180 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 30:
-#line 184 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 31:
-#line 191 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 32:
-#line 195 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 33:
-#line 199 "a.y"
- {
- outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 34:
-#line 203 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 35:
-#line 207 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
- }
- break;
-
- case 36:
-#line 214 "a.y"
- {
- outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 37:
-#line 218 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 38:
-#line 222 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 39:
-#line 232 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 40:
-#line 236 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 41:
-#line 240 "a.y"
- {
- outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 42:
-#line 244 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 43:
-#line 248 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 44:
-#line 252 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 45:
-#line 256 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 46:
-#line 260 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 47:
-#line 264 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 48:
-#line 268 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 49:
-#line 272 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 50:
-#line 276 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 51:
-#line 280 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &(yyvsp[(2) - (2)].addr));
- }
- break;
-
- case 52:
-#line 287 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 53:
-#line 294 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 54:
-#line 298 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 55:
-#line 305 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].addr).reg, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 56:
-#line 309 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 57:
-#line 317 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 58:
-#line 321 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 59:
-#line 325 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 60:
-#line 329 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 61:
-#line 333 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 62:
-#line 337 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 63:
-#line 341 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 64:
-#line 345 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 65:
-#line 354 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr));
- }
- break;
-
- case 66:
-#line 358 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr));
- }
- break;
-
- case 67:
-#line 362 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &nullgen, 0, &(yyvsp[(3) - (4)].addr));
- }
- break;
-
- case 68:
-#line 366 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 69:
-#line 370 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 70:
-#line 374 "a.y"
- {
- outcode((yyvsp[(1) - (5)].lval), &nullgen, 0, &(yyvsp[(4) - (5)].addr));
- }
- break;
-
- case 71:
-#line 378 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 72:
-#line 382 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 73:
-#line 386 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(5) - (6)].addr));
- }
- break;
-
- case 74:
-#line 390 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 75:
-#line 394 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 76:
-#line 398 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr));
- }
- break;
-
- case 77:
-#line 402 "a.y"
- {
- Addr g;
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset = (yyvsp[(2) - (6)].lval);
- outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 78:
-#line 410 "a.y"
- {
- Addr g;
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset = (yyvsp[(2) - (6)].lval);
- outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 79:
-#line 418 "a.y"
- {
- Addr g;
- g = nullgen;
- g.type = TYPE_CONST;
- g.offset = (yyvsp[(2) - (8)].lval);
- outcode((yyvsp[(1) - (8)].lval), &g, REG_R0+(yyvsp[(4) - (8)].lval), &(yyvsp[(7) - (8)].addr));
- }
- break;
-
- case 80:
-#line 429 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
- }
- break;
-
- case 81:
-#line 433 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
- }
- break;
-
- case 82:
-#line 437 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
- }
- break;
-
- case 83:
-#line 441 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
- }
- break;
-
- case 84:
-#line 448 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 85:
-#line 452 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 86:
-#line 456 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 87:
-#line 460 "a.y"
- {
- outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
- }
- break;
-
- case 88:
-#line 464 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 89:
-#line 468 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
- }
- break;
-
- case 90:
-#line 475 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 91:
-#line 479 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 92:
-#line 483 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
- }
- break;
-
- case 93:
-#line 487 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
- }
- break;
-
- case 94:
-#line 494 "a.y"
- {
- outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
- }
- break;
-
- case 95:
-#line 498 "a.y"
- {
- outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
- }
- break;
-
- case 96:
-#line 502 "a.y"
- {
- outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
- }
- break;
-
- case 97:
-#line 506 "a.y"
- {
- outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr));
- }
- break;
-
- case 98:
-#line 513 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 99:
-#line 517 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 100:
-#line 525 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 101:
-#line 529 "a.y"
- {
- outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 102:
-#line 533 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 103:
-#line 537 "a.y"
- {
- outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
- }
- break;
-
- case 104:
-#line 541 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 105:
-#line 545 "a.y"
- {
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 106:
-#line 549 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen);
- }
- break;
-
- case 107:
-#line 556 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
- }
- break;
-
- case 108:
-#line 560 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
- }
- break;
-
- case 109:
-#line 564 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
- }
- break;
-
- case 110:
-#line 568 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 111:
-#line 572 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr));
- }
- break;
-
- case 112:
-#line 576 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen);
- }
- break;
-
- case 113:
-#line 583 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
- }
- break;
-
- case 114:
-#line 587 "a.y"
- {
- outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen);
- }
- break;
-
- case 115:
-#line 594 "a.y"
- {
- if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST)
- yyerror("arguments to PCDATA must be integer constants");
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 116:
-#line 603 "a.y"
- {
- if((yyvsp[(2) - (4)].addr).type != TYPE_CONST)
- yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM)
- yyerror("value for FUNCDATA must be symbol reference");
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 117:
-#line 614 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
- }
- break;
-
- case 118:
-#line 621 "a.y"
- {
- settext((yyvsp[(2) - (5)].addr).sym);
- outcode((yyvsp[(1) - (5)].lval), &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr));
- }
- break;
-
- case 119:
-#line 626 "a.y"
- {
- settext((yyvsp[(2) - (7)].addr).sym);
- outcode((yyvsp[(1) - (7)].lval), &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (7)].lval);
- }
- }
- break;
-
- case 120:
-#line 638 "a.y"
- {
- settext((yyvsp[(2) - (4)].addr).sym);
- outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
- }
- break;
-
- case 121:
-#line 643 "a.y"
- {
- settext((yyvsp[(2) - (6)].addr).sym);
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 122:
-#line 656 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 123:
-#line 664 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 124:
-#line 672 "a.y"
- {
- outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr));
- if(pass > 1) {
- lastpc->from3.type = TYPE_CONST;
- lastpc->from3.offset = (yyvsp[(4) - (6)].lval);
- }
- }
- break;
-
- case 125:
-#line 683 "a.y"
- {
- outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen);
- }
- break;
-
- case 126:
-#line 689 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
- }
- break;
-
- case 127:
-#line 695 "a.y"
- {
- (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym));
- (yyval.addr) = nullgen;
- if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB)
- yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname);
- (yyval.addr).type = TYPE_BRANCH;
- (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 128:
-#line 706 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 131:
-#line 718 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 132:
-#line 726 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval); /* whole register */
- }
- break;
-
- case 133:
-#line 734 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 134:
-#line 742 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 135:
-#line 750 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 136:
-#line 756 "a.y"
- {
- if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= 1024)
- yyerror("SPR/DCR out of range");
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (4)].lval) + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 138:
-#line 767 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 139:
-#line 775 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 140:
-#line 781 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 141:
-#line 789 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 142:
-#line 795 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = REG_C0 + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 143:
-#line 803 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_REG;
- (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
- }
- break;
-
- case 144:
-#line 811 "a.y"
- {
- int mb, me;
- uint32 v;
-
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- mb = (yyvsp[(1) - (3)].lval);
- me = (yyvsp[(3) - (3)].lval);
- if(mb < 0 || mb > 31 || me < 0 || me > 31){
- yyerror("illegal mask start/end value(s)");
- mb = me = 0;
- }
- if(mb <= me)
- v = ((uint32)~0L>>mb) & (~0L<<(31-me));
- else
- v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
- (yyval.addr).offset = v;
- }
- break;
-
- case 145:
-#line 832 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 146:
-#line 839 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (2)].lval);
- (yyval.addr).u.argsize = ArgsSizeUnknown;
- }
- break;
-
- case 147:
-#line 846 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = (yyvsp[(1) - (3)].lval);
- (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 148:
-#line 853 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_TEXTSIZE;
- (yyval.addr).offset = -(yyvsp[(2) - (4)].lval);
- (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 149:
-#line 862 "a.y"
- {
- (yyval.addr) = (yyvsp[(2) - (2)].addr);
- (yyval.addr).type = TYPE_ADDR;
- }
- break;
-
- case 150:
-#line 867 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_SCONST;
- memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
- }
- break;
-
- case 151:
-#line 875 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
- }
- break;
-
- case 152:
-#line 881 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_FCONST;
- (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
- }
- break;
-
- case 153:
-#line 888 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_CONST;
- (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 155:
-#line 897 "a.y"
- {
- if((yyval.lval) < 0 || (yyval.lval) >= NREG)
- print("register value out of range\n");
- (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval);
- }
- break;
-
- case 156:
-#line 905 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
- (yyval.addr).offset = 0;
- }
- break;
-
- case 157:
-#line 912 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
- (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
- (yyval.addr).offset = 0;
- }
- break;
-
- case 159:
-#line 923 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 160:
-#line 932 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(3) - (4)].lval);
- (yyval.addr).sym = nil;
- (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
- }
- break;
-
- case 161:
-#line 940 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = (yyvsp[(4) - (5)].lval);
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
- (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
- }
- break;
-
- case 162:
-#line 948 "a.y"
- {
- (yyval.addr) = nullgen;
- (yyval.addr).type = TYPE_MEM;
- (yyval.addr).name = NAME_STATIC;
- (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
- (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
- }
- break;
-
- case 165:
-#line 960 "a.y"
- {
- (yyval.lval) = 0;
- }
- break;
-
- case 166:
-#line 964 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 167:
-#line 968 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 172:
-#line 980 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
- }
- break;
-
- case 173:
-#line 984 "a.y"
- {
- (yyval.lval) = -(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 174:
-#line 988 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 175:
-#line 992 "a.y"
- {
- (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
- }
- break;
-
- case 176:
-#line 996 "a.y"
- {
- (yyval.lval) = (yyvsp[(2) - (3)].lval);
- }
- break;
-
- case 178:
-#line 1003 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 179:
-#line 1007 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 180:
-#line 1011 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 181:
-#line 1015 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 182:
-#line 1019 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 183:
-#line 1023 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 184:
-#line 1027 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
- }
- break;
-
- case 185:
-#line 1031 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 186:
-#line 1035 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
- }
- break;
-
- case 187:
-#line 1039 "a.y"
- {
- (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 3253 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/9a/y.tab.h b/src/cmd/9a/y.tab.h
deleted file mode 100644
index e7b00330fa..0000000000
--- a/src/cmd/9a/y.tab.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LMOVW = 258,
- LMOVB = 259,
- LABS = 260,
- LLOGW = 261,
- LSHW = 262,
- LADDW = 263,
- LCMP = 264,
- LCROP = 265,
- LBRA = 266,
- LFMOV = 267,
- LFCONV = 268,
- LFCMP = 269,
- LFADD = 270,
- LFMA = 271,
- LTRAP = 272,
- LXORW = 273,
- LNOP = 274,
- LEND = 275,
- LRETT = 276,
- LWORD = 277,
- LTEXT = 278,
- LGLOBL = 279,
- LDATA = 280,
- LRETRN = 281,
- LCONST = 282,
- LSP = 283,
- LSB = 284,
- LFP = 285,
- LPC = 286,
- LCREG = 287,
- LFLUSH = 288,
- LREG = 289,
- LFREG = 290,
- LR = 291,
- LCR = 292,
- LF = 293,
- LFPSCR = 294,
- LLR = 295,
- LCTR = 296,
- LSPR = 297,
- LSPREG = 298,
- LSEG = 299,
- LMSR = 300,
- LPCDAT = 301,
- LFUNCDAT = 302,
- LSCHED = 303,
- LXLD = 304,
- LXST = 305,
- LXOP = 306,
- LXMV = 307,
- LRLWM = 308,
- LMOVMW = 309,
- LMOVEM = 310,
- LMOVFL = 311,
- LMTFSB = 312,
- LMA = 313,
- LFCONST = 314,
- LSCONST = 315,
- LNAME = 316,
- LLAB = 317,
- LVAR = 318
- };
-#endif
-/* Tokens. */
-#define LMOVW 258
-#define LMOVB 259
-#define LABS 260
-#define LLOGW 261
-#define LSHW 262
-#define LADDW 263
-#define LCMP 264
-#define LCROP 265
-#define LBRA 266
-#define LFMOV 267
-#define LFCONV 268
-#define LFCMP 269
-#define LFADD 270
-#define LFMA 271
-#define LTRAP 272
-#define LXORW 273
-#define LNOP 274
-#define LEND 275
-#define LRETT 276
-#define LWORD 277
-#define LTEXT 278
-#define LGLOBL 279
-#define LDATA 280
-#define LRETRN 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LCREG 287
-#define LFLUSH 288
-#define LREG 289
-#define LFREG 290
-#define LR 291
-#define LCR 292
-#define LF 293
-#define LFPSCR 294
-#define LLR 295
-#define LCTR 296
-#define LSPR 297
-#define LSPREG 298
-#define LSEG 299
-#define LMSR 300
-#define LPCDAT 301
-#define LFUNCDAT 302
-#define LSCHED 303
-#define LXLD 304
-#define LXST 305
-#define LXOP 306
-#define LXMV 307
-#define LRLWM 308
-#define LMOVMW 309
-#define LMOVEM 310
-#define LMOVFL 311
-#define LMTFSB 312
-#define LMA 313
-#define LFCONST 314
-#define LSCONST 315
-#define LNAME 316
-#define LLAB 317
-#define LVAR 318
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
- Sym *sym;
- vlong lval;
- double dval;
- char sval[8];
- Addr addr;
-}
-/* Line 1529 of yacc.c. */
-#line 183 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/9g/cgen.c b/src/cmd/9g/cgen.c
deleted file mode 100644
index 009ea1ed7a..0000000000
--- a/src/cmd/9g/cgen.c
+++ /dev/null
@@ -1,1758 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
- Node *nl, *nr, *r;
- Node n1, n2;
- 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 = TYPE_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 = TYPE_ADDR;
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
- n1 = n3;
- n1.op = OINDREG;
- n1.type = types[tptr];
- n1.xoffset = Array_array;
- gmove(&n1, &n3);
- }
-
- if(w == 0) {
- // nothing to do
- } else if(w == 1) {
- /* w 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;
- 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;
-
- 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 != 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 = 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:
- case OOROR:
- if((n->op == OANDAND) == true) {
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- } else {
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
- }
- goto ret;
-
- case OEQ:
- case ONE:
- case OLT:
- case OGT:
- case OLE:
- case OGE:
- nr = n->right;
- if(nr == N || nr->type == T)
- goto ret;
-
- case ONOT: // unary
- nl = n->left;
- if(nl == N || nl->type == T)
- goto ret;
- 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 = TYPE_CONST;
- p->from.offset = w;
-
- p = gins(AADD, N, &dst);
- p->from.type = TYPE_CONST;
- p->from.offset = w;
- } else {
- p = gins(AADD, N, &src);
- p->from.type = TYPE_CONST;
- p->from.offset = -dir;
-
- p = gins(AADD, N, &dst);
- p->from.type = TYPE_CONST;
- p->from.offset = -dir;
-
- if(c >= 4) {
- regalloc(&nend, types[tptr], N);
- p = gins(AMOVD, &src, &nend);
- p->from.type = TYPE_ADDR;
- p->from.offset = w;
- }
- }
-
-
- // move
- // TODO: enable duffcopy for larger copies.
- if(c >= 4) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
- ploop = p;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = dir;
-
- p = gins(ACMP, &src, &nend);
-
- patch(gbranch(ABNE, T, 0), ploop);
- regfree(&nend);
- } else {
- // TODO(austin): Instead of generating ADD $-8,R8; ADD
- // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
- // generate the offsets directly and eliminate the
- // ADDs. That will produce shorter, more
- // pipeline-able code.
- while(c-- > 0) {
- p = gins(op, &src, &tmp);
- p->from.type = TYPE_MEM;
- p->from.offset = dir;
-
- p = gins(op, &tmp, &dst);
- p->to.type = TYPE_MEM;
- 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, tmp;
- Type *t;
- int freel, freer;
- vlong fldcount;
- vlong loffset, roffset;
-
- freel = 0;
- freer = 0;
-
- switch(nl->type->etype) {
- default:
- goto no;
-
- case TARRAY:
- t = nl->type;
-
- // Slices are ok.
- if(isslice(t))
- break;
- // Small arrays are ok.
- if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
- break;
-
- goto no;
-
- case TSTRUCT:
- // Small structs with non-fat types are ok.
- // Zero-sized structs are treated separately elsewhere.
- fldcount = 0;
- for(t=nl->type->type; t; t=t->down) {
- if(isfat(t->type))
- goto no;
- if(t->etype != TFIELD)
- fatal("componentgen: not a TFIELD: %lT", t);
- fldcount++;
- }
- if(fldcount == 0 || fldcount > 4)
- goto no;
-
- break;
-
- case TSTRING:
- case TINTER:
- break;
- }
-
- nodl = *nl;
- if(!cadable(nl)) {
- if(nr != N && !cadable(nr))
- goto no;
- igen(nl, &nodl, N);
- freel = 1;
- }
-
- if(nr != N) {
- nodr = *nr;
- if(!cadable(nr)) {
- igen(nr, &nodr, N);
- freer = 1;
- }
- } else {
- // When zeroing, prepare a register containing zero.
- nodconst(&tmp, nl->type, 0);
- regalloc(&nodr, types[TUINT], N);
- gmove(&tmp, &nodr);
- freer = 1;
- }
-
- // nl and nr are 'cadable' which basically means they are names (variables) now.
- // If they are the same variable, don't generate any code, because the
- // VARDEF we generate will mark the old value as dead incorrectly.
- // (And also the assignments are useless.)
- if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
- goto yes;
-
- switch(nl->type->etype) {
- case TARRAY:
- // componentgen for arrays.
- if(nl->op == ONAME)
- gvardef(nl);
- t = nl->type;
- if(!isslice(t)) {
- nodl.type = t->type;
- nodr.type = nodl.type;
- for(fldcount=0; fldcount < t->bound; fldcount++) {
- if(nr == N)
- clearslim(&nodl);
- else
- gmove(&nodr, &nodl);
- nodl.xoffset += t->type->width;
- nodr.xoffset += t->type->width;
- }
- goto yes;
- }
-
- // componentgen for slices.
- nodl.xoffset += Array_array;
- nodl.type = ptrto(nl->type->type);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_cap-Array_nel;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRING:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[simtype[TUINT]];
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TINTER:
- if(nl->op == ONAME)
- gvardef(nl);
- nodl.xoffset += Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- nodl.xoffset += Array_nel-Array_array;
- nodl.type = ptrto(types[TUINT8]);
-
- if(nr != N) {
- nodr.xoffset += Array_nel-Array_array;
- nodr.type = nodl.type;
- }
- gmove(&nodr, &nodl);
-
- goto yes;
-
- case TSTRUCT:
- if(nl->op == ONAME)
- gvardef(nl);
- loffset = nodl.xoffset;
- roffset = nodr.xoffset;
- // funarg structs may not begin at offset zero.
- if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
- loffset -= nl->type->type->width;
- if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
- roffset -= nr->type->type->width;
-
- for(t=nl->type->type; t; t=t->down) {
- nodl.xoffset = loffset + t->width;
- nodl.type = t->type;
-
- if(nr == N)
- clearslim(&nodl);
- else {
- nodr.xoffset = roffset + t->width;
- nodr.type = nodl.type;
- gmove(&nodr, &nodl);
- }
- }
- goto yes;
- }
-
-no:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 0;
-
-yes:
- if(freer)
- regfree(&nodr);
- if(freel)
- regfree(&nodl);
- return 1;
-}
diff --git a/src/cmd/new9g/cgen.go b/src/cmd/9g/cgen.go
index 7a1e967267..7a1e967267 100644
--- a/src/cmd/new9g/cgen.go
+++ b/src/cmd/9g/cgen.go
diff --git a/src/cmd/9g/doc.go b/src/cmd/9g/doc.go
deleted file mode 100644
index 56bb14344b..0000000000
--- a/src/cmd/9g/doc.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-// +build ignore
-
-/*
-
-9g is the version of the gc compiler for 64-bit PowerPC or Power Architecture processors.
-The $GOARCH for these tools is ppc64 (big endian) or
-ppc64le (little endian).
-
-It reads .go files and outputs .9 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/9g/galign.c b/src/cmd/9g/galign.c
deleted file mode 100644
index 74856e2af0..0000000000
--- a/src/cmd/9g/galign.c
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int thechar = '9';
-char* thestring = "ppc64";
-LinkArch* thelinkarch;
-
-void
-linkarchinit(void)
-{
- thestring = getgoarch();
- thearch.thestring = thestring;
- if(strcmp(thestring, "ppc64le") == 0)
- thelinkarch = &linkppc64le;
- else
- thelinkarch = &linkppc64;
- thearch.thelinkarch = thelinkarch;
-}
-
-vlong MAXWIDTH = 1LL<<50;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef typedefs[] =
-{
- {"int", TINT, TINT64},
- {"uint", TUINT, TUINT64},
- {"uintptr", TUINTPTR, TUINT64},
- {0}
-};
-
-void
-betypeinit(void)
-{
- widthptr = 8;
- widthint = 8;
- widthreg = 8;
-
- listinit9();
-}
-
-void
-main(int argc, char **argv)
-{
- thearch.thechar = thechar;
- thearch.thestring = thestring;
- thearch.thelinkarch = thelinkarch;
- thearch.typedefs = typedefs;
- thearch.REGSP = REGSP;
- thearch.REGCTXT = REGCTXT;
- thearch.MAXWIDTH = MAXWIDTH;
- thearch.anyregalloc = anyregalloc;
- thearch.betypeinit = betypeinit;
- thearch.bgen = bgen;
- thearch.cgen = cgen;
- thearch.cgen_call = cgen_call;
- thearch.cgen_callinter = cgen_callinter;
- thearch.cgen_ret = cgen_ret;
- thearch.clearfat = clearfat;
- thearch.defframe = defframe;
- thearch.excise = excise;
- thearch.expandchecks = expandchecks;
- thearch.gclean = gclean;
- thearch.ginit = ginit;
- thearch.gins = gins;
- thearch.ginscall = ginscall;
- thearch.igen = igen;
- thearch.linkarchinit = linkarchinit;
- thearch.peep = peep;
- thearch.proginfo = proginfo;
- thearch.regalloc = regalloc;
- thearch.regfree = regfree;
- thearch.regtyp = regtyp;
- thearch.sameaddr = sameaddr;
- thearch.smallindir = smallindir;
- thearch.stackaddr = stackaddr;
- thearch.excludedregs = excludedregs;
- thearch.RtoB = RtoB;
- thearch.FtoB = RtoB;
- thearch.BtoR = BtoR;
- thearch.BtoF = BtoF;
- thearch.optoas = optoas;
- thearch.doregbits = doregbits;
- thearch.regnames = regnames;
-
- gcmain(argc, argv);
-}
diff --git a/src/cmd/new9g/galign.go b/src/cmd/9g/galign.go
index 99425c3929..99425c3929 100644
--- a/src/cmd/new9g/galign.go
+++ b/src/cmd/9g/galign.go
diff --git a/src/cmd/new9g/gg.go b/src/cmd/9g/gg.go
index 068d8afe53..068d8afe53 100644
--- a/src/cmd/new9g/gg.go
+++ b/src/cmd/9g/gg.go
diff --git a/src/cmd/9g/gg.h b/src/cmd/9g/gg.h
deleted file mode 100644
index 938675937e..0000000000
--- a/src/cmd/9g/gg.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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"
-
-EXTERN uchar reg[NREG+NFREG];
-EXTERN Node* panicdiv;
-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 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);
-
-void afunclit(Addr*, Node*);
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node*, int, int, Prog*);
-void cgen(Node*, Node*);
-void cgen_call(Node*, int);
-void cgen_callinter(Node*, Node*, int);
-void cgen_ret(Node*);
-void clearfat(Node*);
-void clearp(Prog*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int, char*);
-int dgostrlitptr(Sym*, int, Strlit*);
-int dsname(Sym*, int, char*, int);
-int dsymptr(Sym*, int, Sym*, int);
-void dumpdata(void);
-void dumpit(char*, Flow*, int);
-void excise(Flow*);
-void expandchecks(Prog*);
-void fixautoused(Prog*);
-void gclean(void);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void ggloblnod(Node *nam);
-void ggloblsym(Sym *s, int32 width, int8 flags);
-void ginit(void);
-Prog* gins(int, Node*, Node*);
-void ginscall(Node*, int);
-Prog* gjmp(Prog*);
-void gtrack(Sym*);
-void gused(Node*);
-void igen(Node*, Node*, Node*);
-int isfat(Type*);
-void linkarchinit(void);
-void markautoused(Prog*);
-void naddr(Node*, Addr*, int);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void patch(Prog*, Prog*);
-void proginfo(ProgInfo*, Prog*);
-void regalloc(Node*, Type*, Node*);
-void regfree(Node*);
-void regopt(Prog*);
-int regtyp(Addr*);
-int sameaddr(Addr*, Addr*);
-int smallindir(Addr*, Addr*);
-int stackaddr(Addr*);
-Prog* unpatch(Prog*);
-
-
-/*
- * reg.c
- */
-uint64 excludedregs(void);
-uint64 RtoB(int);
-uint64 FtoB(int);
-int BtoR(uint64);
-int BtoF(uint64);
-uint64 doregbits(int);
-char** regnames(int*);
-
-/*
- * peep.c
- */
-void peep(Prog*);
diff --git a/src/cmd/9g/ggen.c b/src/cmd/9g/ggen.c
deleted file mode 100644
index 7b34282685..0000000000
--- a/src/cmd/9g/ggen.c
+++ /dev/null
@@ -1,965 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#undef EXTERN
-#define EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-
-static Prog *appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi);
-
-void
-defframe(Prog *ptxt)
-{
- uint32 frame;
- Prog *p;
- vlong hi, lo;
- NodeList *l;
- Node *n;
-
- // fill in argument size, stack size
- ptxt->to.type = TYPE_TEXTSIZE;
- ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr);
- frame = rnd(stksize+maxarg, widthreg);
- ptxt->to.offset = frame;
-
- // insert code to zero ambiguously live variables
- // so that the garbage collector only sees initialized values
- // when it looks for pointers.
- p = ptxt;
- lo = hi = 0;
- // iterate through declarations - they are sorted in decreasing xoffset order.
- for(l=curfn->dcl; l != nil; l = l->next) {
- n = l->n;
- if(!n->needzero)
- continue;
- if(n->class != PAUTO)
- fatal("needzero class %d", n->class);
- if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
- fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
-
- if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
- // merge with range we already have
- lo = n->xoffset;
- continue;
- }
- // zero old range
- p = zerorange(p, frame, lo, hi);
-
- // set new range
- hi = n->xoffset + n->type->width;
- lo = n->xoffset;
- }
- // zero final range
- zerorange(p, frame, lo, hi);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi)
-{
- vlong cnt, i;
- Prog *p1;
- Node *f;
-
- cnt = hi - lo;
- if(cnt == 0)
- return p;
- if(cnt < 4*widthptr) {
- for(i = 0; i < cnt; i += widthptr)
- p = appendpp(p, AMOVD, TYPE_REG, REGZERO, 0, TYPE_MEM, REGSP, 8+frame+lo+i);
- } else if(cnt <= 128*widthptr) {
- p = appendpp(p, AADD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGRT1, 0);
- p->reg = REGSP;
- p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0);
- f = sysfunc("duffzero");
- naddr(f, &p->to, 1);
- afunclit(&p->to, f);
- p->to.offset = 4*(128-cnt/widthptr);
- } else {
- p = appendpp(p, AMOVD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGTMP, 0);
- p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT1, 0);
- p->reg = REGSP;
- p = appendpp(p, AMOVD, TYPE_CONST, 0, cnt, TYPE_REG, REGTMP, 0);
- p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT2, 0);
- p->reg = REGRT1;
- p1 = p = appendpp(p, AMOVDU, TYPE_REG, REGZERO, 0, TYPE_MEM, REGRT1, widthptr);
- p = appendpp(p, ACMP, TYPE_REG, REGRT1, 0, TYPE_REG, REGRT2, 0);
- p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0);
- patch(p, p1);
- }
- return p;
-}
-
-static Prog*
-appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset)
-{
- Prog *q;
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.reg = freg;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.reg = treg;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-/*
- * generate: BL reg, f
- * where both reg and f are registers.
- * On power, f must be moved to CTR first.
- */
-static void
-ginsBL(Node *reg, Node *f)
-{
- Prog *p;
- p = gins(AMOVD, f, N);
- p->to.type = TYPE_REG;
- p->to.reg = REG_CTR;
- p = gins(ABL, reg, N);
- p->to.type = TYPE_REG;
- p->to.reg = REG_CTR;
-}
-
-/*
- * generate:
- * call f
- * proc=-1 normal call but no return
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- * proc=3 normal call to C pointer (not Go func value)
- */
-void
-ginscall(Node *f, int proc)
-{
- Prog *p;
- Node reg, con, reg2;
- Node r1;
- int32 extra;
-
- if(f->type != T) {
- extra = 0;
- if(proc == 1 || proc == 2)
- extra = 2 * widthptr;
- setmaxarg(f->type, extra);
- }
-
- switch(proc) {
- default:
- fatal("ginscall: bad proc %d", proc);
- break;
-
- case 0: // normal call
- case -1: // normal call but no return
- if(f->op == ONAME && f->class == PFUNC) {
- if(f == deferreturn) {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert a ppc64 NOP that we will have the right line number.
- // The ppc64 NOP is really or r0, r0, r0; use that description
- // because the NOP pseudo-instruction would be removed by
- // the linker.
- nodreg(&reg, types[TINT], REG_R0);
- gins(AOR, &reg, &reg);
- }
- p = gins(ABL, N, f);
- afunclit(&p->to, f);
- if(proc == -1 || noreturn(p))
- gins(AUNDEF, N, N);
- break;
- }
- nodreg(&reg, types[tptr], REGCTXT);
- nodreg(&r1, types[tptr], REG_R3);
- gmove(f, &reg);
- reg.op = OINDREG;
- gmove(&reg, &r1);
- reg.op = OREGISTER;
- ginsBL(&reg, &r1);
- break;
-
- case 3: // normal call of c function pointer
- ginsBL(N, f);
- break;
-
- case 1: // call in new proc (go)
- case 2: // deferred call (defer)
- nodconst(&con, types[TINT64], argsize(f->type));
- nodreg(&reg, types[TINT64], REG_R3);
- nodreg(&reg2, types[TINT64], REG_R4);
- gmove(f, &reg);
-
- gmove(&con, &reg2);
- p = gins(AMOVW, &reg2, N);
- p->to.type = TYPE_MEM;
- p->to.reg = REGSP;
- p->to.offset = 8;
-
- p = gins(AMOVD, &reg, N);
- p->to.type = TYPE_MEM;
- p->to.reg = REGSP;
- p->to.offset = 16;
-
- if(proc == 1)
- ginscall(newproc, 0);
- else {
- if(!hasdefer)
- fatal("hasdefer=0 but has defer");
- ginscall(deferproc, 0);
- }
-
- if(proc == 2) {
- nodreg(&reg, types[TINT64], REG_R3);
- p = gins(ACMP, &reg, N);
- p->to.type = TYPE_REG;
- p->to.reg = REG_R0;
- p = gbranch(ABEQ, T, +1);
- cgen_ret(N);
- patch(p, pc);
- }
- break;
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
- Node *i, *f;
- Node tmpi, nodi, nodo, nodr, nodsp;
- Prog *p;
-
- i = n->left;
- if(i->op != ODOTINTER)
- fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
- f = i->right; // field
- if(f->op != ONAME)
- fatal("cgen_callinter: not ONAME %O", f->op);
-
- i = i->left; // interface
-
- if(!i->addable) {
- tempname(&tmpi, i->type);
- cgen(i, &tmpi);
- i = &tmpi;
- }
-
- genlist(n->list); // assign the args
-
- // i is now addable, prepare an indirected
- // register to hold its address.
- igen(i, &nodi, res); // REG = &inter
-
- nodindreg(&nodsp, types[tptr], REGSP);
- nodsp.xoffset = widthptr;
- if(proc != 0)
- nodsp.xoffset += 2 * widthptr; // leave room for size & fn
- nodi.type = types[tptr];
- nodi.xoffset += widthptr;
- cgen(&nodi, &nodsp); // {8 or 24}(SP) = 8(REG) -- i.data
-
- regalloc(&nodo, types[tptr], res);
- nodi.type = types[tptr];
- nodi.xoffset -= widthptr;
- cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab
- regfree(&nodi);
-
- regalloc(&nodr, types[tptr], &nodo);
- if(n->left->xoffset == BADWIDTH)
- fatal("cgen_callinter: badwidth");
- cgen_checknil(&nodo); // in case offset is huge
- nodo.op = OINDREG;
- nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- if(proc == 0) {
- // plain call: use direct c function pointer - more efficient
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
- proc = 3;
- } else {
- // go/defer. generate go func value.
- p = gins(AMOVD, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.tab->fun[f]
- p->from.type = TYPE_ADDR;
- }
-
- nodr.type = n->left->type;
- ginscall(&nodr, proc);
-
- regfree(&nodr);
- regfree(&nodo);
-}
-
-/*
- * generate function call;
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_call(Node *n, int proc)
-{
- Type *t;
- Node nod, afun;
-
- if(n == N)
- return;
-
- if(n->left->ullman >= UINF) {
- // if name involves a fn call
- // precompute the address of the fn
- tempname(&afun, types[tptr]);
- cgen(n->left, &afun);
- }
-
- genlist(n->list); // assign the args
- t = n->left->type;
-
- // call tempname pointer
- if(n->left->ullman >= UINF) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, &afun);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call pointer
- if(n->left->op != ONAME || n->left->class != PFUNC) {
- regalloc(&nod, types[tptr], N);
- cgen_as(&nod, n->left);
- nod.type = t;
- ginscall(&nod, proc);
- regfree(&nod);
- return;
- }
-
- // call direct
- n->left->method = 1;
- ginscall(n->left, proc);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = return value from call.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
- Node nod;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(t->etype == TPTR32 || t->etype == TPTR64)
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_callret: nil");
-
- memset(&nod, 0, sizeof(nod));
- nod.op = OINDREG;
- nod.val.u.reg = REGSP;
- nod.addable = 1;
-
- nod.xoffset = fp->width + widthptr; // +widthptr: saved LR at 0(R1)
- nod.type = fp->type;
- cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
- Node nod1, nod2;
- Type *fp, *t;
- Iter flist;
-
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
-
- fp = structfirst(&flist, getoutarg(t));
- if(fp == T)
- fatal("cgen_aret: nil");
-
- memset(&nod1, 0, sizeof(nod1));
- nod1.op = OINDREG;
- nod1.val.u.reg = REGSP;
- nod1.addable = 1;
-
- nod1.xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP)
- nod1.type = fp->type;
-
- if(res->op != OREGISTER) {
- regalloc(&nod2, types[tptr], res);
- agen(&nod1, &nod2);
- gins(AMOVD, &nod2, res);
- regfree(&nod2);
- } else
- agen(&nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
- Prog *p;
-
- if(n != N)
- genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- genlist(curfn->exit);
- p = gins(ARET, N, N);
- if(n != N && n->op == ORETJMP) {
- p->to.name = NAME_EXTERN;
- p->to.type = TYPE_ADDR;
- p->to.sym = linksym(n->left->sym);
- }
-}
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res)
-{
- int a, check;
- Type *t, *t0;
- Node tl, tr, tl2, tr2, nm1, nz, tm;
- Prog *p1, *p2;
-
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will generate undefined result.
- // Also need to explicitly trap on division on zero,
- // the hardware will silently generate undefined result.
- // DIVW will leave unpredicable result in higher 32-bit,
- // so always use DIVD/DIVDU.
- t = nl->type;
- t0 = t;
- check = 0;
- if(issigned[t->etype]) {
- check = 1;
- if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1)))
- check = 0;
- else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
- check = 0;
- }
- if(t->width < 8) {
- if(issigned[t->etype])
- t = types[TINT64];
- else
- t = types[TUINT64];
- check = 0;
- }
-
- a = optoas(ODIV, t);
-
- regalloc(&tl, t0, N);
- regalloc(&tr, t0, N);
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &tl);
- cgen(nr, &tr);
- } else {
- cgen(nr, &tr);
- cgen(nl, &tl);
- }
- if(t != t0) {
- // Convert
- tl2 = tl;
- tr2 = tr;
- tl.type = t;
- tr.type = t;
- gmove(&tl2, &tl);
- gmove(&tr2, &tr);
- }
-
- // Handle divide-by-zero panic.
- p1 = gins(optoas(OCMP, t), &tr, N);
- p1->to.type = TYPE_REG;
- p1->to.reg = REGZERO;
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(panicdiv == N)
- panicdiv = sysfunc("panicdivide");
- ginscall(panicdiv, -1);
- patch(p1, pc);
-
- if(check) {
- nodconst(&nm1, t, -1);
- gins(optoas(OCMP, t), &tr, &nm1);
- p1 = gbranch(optoas(ONE, t), T, +1);
- if(op == ODIV) {
- // a / (-1) is -a.
- gins(optoas(OMINUS, t), N, &tl);
- gmove(&tl, res);
- } else {
- // a % (-1) is 0.
- nodconst(&nz, t, 0);
- gmove(&nz, res);
- }
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- }
- p1 = gins(a, &tr, &tl);
- if(op == ODIV) {
- regfree(&tr);
- gmove(&tl, res);
- } else {
- // A%B = A-(A/B*B)
- regalloc(&tm, t, N);
- // patch div to use the 3 register form
- // TODO(minux): add gins3?
- p1->reg = p1->to.reg;
- p1->to.reg = tm.val.u.reg;
- gins(optoas(OMUL, t), &tr, &tm);
- regfree(&tr);
- gins(optoas(OSUB, t), &tm, &tl);
- regfree(&tm);
- gmove(&tl, res);
- }
- regfree(&tl);
- if(check)
- patch(p2, pc);
-}
-
-/*
- * generate division according to op, one of:
- * res = nl / nr
- * res = nl % nr
- */
-void
-cgen_div(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3;
- int w, a;
- Magic m;
-
- // TODO(minux): enable division by magic multiply (also need to fix longmod below)
- //if(nr->op != OLITERAL)
- goto longdiv;
- w = nl->type->width*8;
-
- // Front end handled 32-bit division. We only need to handle 64-bit.
- // try to do division by multiply by (2^w)/d
- // see hacker's delight chapter 10
- switch(simtype[nl->type->etype]) {
- default:
- goto longdiv;
-
- case TUINT64:
- m.w = w;
- m.ud = mpgetfix(nr->val.u.xval);
- umagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- cgenr(nl, &n1, N);
- nodconst(&n2, nl->type, m.um);
- regalloc(&n3, nl->type, res);
- cgen_hmul(&n1, &n2, &n3);
-
- if(m.ua) {
- // need to add numerator accounting for overflow
- gins(optoas(OADD, nl->type), &n1, &n3);
- nodconst(&n2, nl->type, 1);
- gins(optoas(ORROTC, nl->type), &n2, &n3);
- nodconst(&n2, nl->type, m.s-1);
- gins(optoas(ORSH, nl->type), &n2, &n3);
- } else {
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &n3); // shift dx
- }
-
- gmove(&n3, res);
- regfree(&n1);
- regfree(&n3);
- return;
-
- case TINT64:
- m.w = w;
- m.sd = mpgetfix(nr->val.u.xval);
- smagic(&m);
- if(m.bad)
- break;
- if(op == OMOD)
- goto longmod;
-
- cgenr(nl, &n1, res);
- nodconst(&n2, nl->type, m.sm);
- regalloc(&n3, nl->type, N);
- cgen_hmul(&n1, &n2, &n3);
-
- if(m.sm < 0) {
- // need to add numerator
- gins(optoas(OADD, nl->type), &n1, &n3);
- }
-
- nodconst(&n2, nl->type, m.s);
- gins(optoas(ORSH, nl->type), &n2, &n3); // shift n3
-
- nodconst(&n2, nl->type, w-1);
- gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg
- gins(optoas(OSUB, nl->type), &n1, &n3); // added
-
- if(m.sd < 0) {
- // this could probably be removed
- // by factoring it into the multiplier
- gins(optoas(OMINUS, nl->type), N, &n3);
- }
-
- gmove(&n3, res);
- regfree(&n1);
- regfree(&n3);
- return;
- }
- goto longdiv;
-
-longdiv:
- // division and mod using (slow) hardware instruction
- dodiv(op, nl, nr, res);
- return;
-
-longmod:
- // mod using formula A%B = A-(A/B*B) but
- // we know that there is a fast algorithm for A/B
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- regalloc(&n2, nl->type, N);
- cgen_div(ODIV, &n1, nr, &n2);
- a = optoas(OMUL, nl->type);
- if(w == 8) {
- // use 2-operand 16-bit multiply
- // because there is no 2-operand 8-bit multiply
- //a = AIMULW;
- }
- if(!smallintconst(nr)) {
- regalloc(&n3, nl->type, N);
- cgen(nr, &n3);
- gins(a, &n3, &n2);
- regfree(&n3);
- } else
- gins(a, nr, &n2);
- gins(optoas(OSUB, nl->type), &n2, &n1);
- gmove(&n1, res);
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
- int w;
- Node n1, n2, *tmp;
- Type *t;
- Prog *p;
-
- // largest ullman on left.
- if(nl->ullman < nr->ullman) {
- tmp = nl;
- nl = nr;
- nr = tmp;
- }
- t = nl->type;
- w = t->width * 8;
- cgenr(nl, &n1, res);
- cgenr(nr, &n2, N);
- switch(simtype[t->etype]) {
- case TINT8:
- case TINT16:
- case TINT32:
- gins(optoas(OMUL, t), &n2, &n1);
- p = gins(ASRAD, N, &n1);
- p->from.type = TYPE_CONST;
- p->from.offset = w;
- break;
- case TUINT8:
- case TUINT16:
- case TUINT32:
- gins(optoas(OMUL, t), &n2, &n1);
- p = gins(ASRD, N, &n1);
- p->from.type = TYPE_CONST;
- p->from.offset = w;
- break;
- case TINT64:
- case TUINT64:
- if(issigned[t->etype])
- p = gins(AMULHD, &n2, &n1);
- else
- p = gins(AMULHDU, &n2, &n1);
- break;
- default:
- fatal("cgen_hmul %T", t);
- break;
- }
- cgen(&n1, res);
- regfree(&n1);
- regfree(&n2);
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5;
- int a;
- Prog *p1;
- uvlong sc;
- Type *tcount;
-
- a = optoas(op, nl->type);
-
- if(nr->op == OLITERAL) {
- regalloc(&n1, nl->type, res);
- cgen(nl, &n1);
- sc = mpgetfix(nr->val.u.xval);
- if(sc >= nl->type->width*8) {
- // large shift gets 2 shifts by width-1
- nodconst(&n3, types[TUINT32], nl->type->width*8-1);
- gins(a, &n3, &n1);
- gins(a, &n3, &n1);
- } else
- gins(a, nr, &n1);
- gmove(&n1, res);
- regfree(&n1);
- goto ret;
- }
-
- if(nl->ullman >= UINF) {
- tempname(&n4, nl->type);
- cgen(nl, &n4);
- nl = &n4;
- }
- if(nr->ullman >= UINF) {
- tempname(&n5, nr->type);
- cgen(nr, &n5);
- nr = &n5;
- }
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount = types[simtype[nr->type->etype]];
- if(tcount->etype < TUINT32)
- tcount = types[TUINT32];
-
- regalloc(&n1, nr->type, N); // to hold the shift type in CX
- regalloc(&n3, tcount, &n1); // to clear high bits of CX
-
- regalloc(&n2, nl->type, res);
- if(nl->ullman >= nr->ullman) {
- cgen(nl, &n2);
- cgen(nr, &n1);
- gmove(&n1, &n3);
- } else {
- cgen(nr, &n1);
- gmove(&n1, &n3);
- cgen(nl, &n2);
- }
- regfree(&n3);
-
- // test and fix up large shifts
- if(!bounded) {
- nodconst(&n3, tcount, nl->type->width*8);
- gins(optoas(OCMP, tcount), &n1, &n3);
- p1 = gbranch(optoas(OLT, tcount), T, +1);
- if(op == ORSH && issigned[nl->type->etype]) {
- nodconst(&n3, types[TUINT32], nl->type->width*8-1);
- gins(a, &n3, &n2);
- } else {
- nodconst(&n3, nl->type, 0);
- gmove(&n3, &n2);
- }
- patch(p1, pc);
- }
-
- gins(a, &n1, &n2);
-
- gmove(&n2, res);
-
- regfree(&n1);
- regfree(&n2);
-
-ret:
- ;
-}
-
-void
-clearfat(Node *nl)
-{
- uint64 w, c, q, t, boff;
- Node dst, end, r0, *f;
- Prog *p, *pl;
-
- /* clear a fat object */
- if(debug['g']) {
- print("clearfat %N (%T, size: %lld)\n", nl, nl->type, nl->type->width);
- }
-
- w = nl->type->width;
- // Avoid taking the address for simple enough types.
- //if(componentgen(N, nl))
- // return;
-
- c = w % 8; // bytes
- q = w / 8; // dwords
-
- if(reg[REGRT1] > 0)
- fatal("R%d in use during clearfat", REGRT1);
-
- nodreg(&r0, types[TUINT64], REG_R0); // r0 is always zero
- nodreg(&dst, types[tptr], REGRT1);
- reg[REGRT1]++;
- agen(nl, &dst);
-
- if(q > 128) {
- p = gins(ASUB, N, &dst);
- p->from.type = TYPE_CONST;
- p->from.offset = 8;
-
- regalloc(&end, types[tptr], N);
- p = gins(AMOVD, &dst, &end);
- p->from.type = TYPE_ADDR;
- p->from.offset = q*8;
-
- p = gins(AMOVDU, &r0, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = 8;
- pl = p;
-
- p = gins(ACMP, &dst, &end);
- patch(gbranch(ABNE, T, 0), pl);
-
- regfree(&end);
- // The loop leaves R3 on the last zeroed dword
- boff = 8;
- } else if(q >= 4) {
- p = gins(ASUB, N, &dst);
- p->from.type = TYPE_CONST;
- p->from.offset = 8;
- f = sysfunc("duffzero");
- p = gins(ADUFFZERO, N, f);
- afunclit(&p->to, f);
- // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
- p->to.offset = 4*(128-q);
- // duffzero leaves R3 on the last zeroed dword
- boff = 8;
- } else {
- for(t = 0; t < q; t++) {
- p = gins(AMOVD, &r0, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = 8*t;
- }
- boff = 8*q;
- }
-
- for(t = 0; t < c; t++) {
- p = gins(AMOVB, &r0, &dst);
- p->to.type = TYPE_MEM;
- p->to.offset = t+boff;
- }
- reg[REGRT1]--;
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
- Prog *p, *p1, *p2;
-
- for(p = firstp; p != P; p = p->link) {
- if(debug_checknil && ctxt->debugvlog)
- print("expandchecks: %P\n", p);
- if(p->as != ACHECKNIL)
- continue;
- if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
- warnl(p->lineno, "generated nil check");
- if(p->from.type != TYPE_REG)
- fatal("invalid nil check %P\n", p);
- /*
- // check is
- // TD $4, R0, arg (R0 is always zero)
- // eqv. to:
- // tdeq r0, arg
- // NOTE: this needs special runtime support to make SIGTRAP recoverable.
- reg = p->from.reg;
- p->as = ATD;
- p->from = p->to = p->from3 = zprog.from;
- p->from.type = TYPE_CONST;
- p->from.offset = 4;
- p->from.reg = 0;
- p->reg = REG_R0;
- p->to.type = TYPE_REG;
- p->to.reg = reg;
- */
- // check is
- // CMP arg, R0
- // BNE 2(PC) [likely]
- // MOVD R0, 0(R0)
- p1 = mal(sizeof *p1);
- p2 = mal(sizeof *p2);
- clearp(p1);
- clearp(p2);
- p1->link = p2;
- p2->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
- p2->lineno = p->lineno;
- p1->pc = 9999;
- p2->pc = 9999;
- p->as = ACMP;
- p->to.type = TYPE_REG;
- p->to.reg = REGZERO;
- p1->as = ABNE;
- //p1->from.type = TYPE_CONST;
- //p1->from.offset = 1; // likely
- p1->to.type = TYPE_BRANCH;
- p1->to.u.branch = p2->link;
- // crash by write to memory address 0.
- p2->as = AMOVD;
- p2->from.type = TYPE_REG;
- p2->from.reg = REG_R0;
- p2->to.type = TYPE_MEM;
- p2->to.reg = REG_R0;
- p2->to.offset = 0;
- }
-}
diff --git a/src/cmd/new9g/ggen.go b/src/cmd/9g/ggen.go
index 54bebdda40..54bebdda40 100644
--- a/src/cmd/new9g/ggen.go
+++ b/src/cmd/9g/ggen.go
diff --git a/src/cmd/9g/gsubr.c b/src/cmd/9g/gsubr.c
deleted file mode 100644
index 1fb1511361..0000000000
--- a/src/cmd/9g/gsubr.c
+++ /dev/null
@@ -1,1158 +0,0 @@
-// 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 "../../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 ../../runtime/stack.h.
-vlong unmappedzero = 4096;
-
-static int resvd[] =
-{
- REGZERO,
- REGSP, // reserved for SP
- // We need to preserve the C ABI TLS pointer because sigtramp
- // may happen during C code and needs to access the g. C
- // clobbers REGG, so if Go were to clobber REGTLS, sigtramp
- // won't know which convention to use. By preserving REGTLS,
- // we can just retrieve g from TLS when we aren't sure.
- REGTLS,
- // TODO(austin): Consolidate REGTLS and REGG?
- REGG,
- REGTMP, // REGTMP
- FREGCVI,
- FREGZERO,
- FREGHALF,
- FREGONE,
- FREGTWO,
-};
-
-void
-ginit(void)
-{
- int i;
-
- for(i=0; i<nelem(reg); i++)
- reg[i] = 1;
- for(i=0; i<NREG+NFREG; i++)
- reg[i] = 0;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i] - REG_R0]++;
-}
-
-static uintptr regpc[nelem(reg)];
-
-void
-gclean(void)
-{
- int i;
-
- for(i=0; i<nelem(resvd); i++)
- reg[resvd[i] - REG_R0]--;
-
- for(i=0; i<nelem(reg); i++)
- if(reg[i])
- yyerror("reg %R left allocated, %p\n", i+REG_R0, regpc[i]);
-}
-
-int
-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 = REG_R0; i < REG_F31; i++)
- if(reg[i - REG_R0] == 0) {
- if(i < REG_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 >= REGMIN && i <= REGMAX)
- goto out;
- }
- for(i=REGMIN; i<=REGMAX; i++)
- if(reg[i - REG_R0] == 0) {
- regpc[i - REG_R0] = (uintptr)getcallerpc(&n);
- goto out;
- }
- flusherrors();
- for(i=REG_R0; i<REG_R0+NREG; i++)
- print("R%d %p\n", i, regpc[i - REG_R0]);
- fatal("out of fixed registers");
-
- case TFLOAT32:
- case TFLOAT64:
- if(o != N && o->op == OREGISTER) {
- i = o->val.u.reg;
- if(i >= FREGMIN && i <= FREGMAX)
- goto out;
- }
- for(i=FREGMIN; i<=FREGMAX; i++)
- if(reg[i - REG_R0] == 0) {
- regpc[i - REG_R0] = (uintptr)getcallerpc(&n);
- goto out;
- }
- flusherrors();
- for(i=REG_F0; i<REG_F0+NREG; i++)
- print("F%d %p\n", i, regpc[i - REG_R0]);
- fatal("out of floating registers");
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- tempname(n, t);
- return;
- }
- fatal("regalloc: unknown type %T", t);
- return;
-
-out:
- reg[i - REG_R0]++;
- 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 - REG_R0;
- if(i == REGSP - REG_R0)
- 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;
-}
-
-/*
- * 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); */
-
-/*
- * 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 = TYPE_MEM;
- p1->to.reg = REGSP;
- p1->to.offset = -8;
- p1 = gins(AMOVD, N, &r3);
- p1->from.type = TYPE_MEM;
- 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], 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], REGTMP);
- gmove(&bigi, &r2);
- gins(ACMPU, &r1, &r2);
- p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
- p2 = gins(ASRD, N, &r1);
- p2->from.type = TYPE_CONST;
- p2->from.offset = 1;
- patch(p1, pc);
- }
- regalloc(&r2, types[TFLOAT64], t);
- p1 = gins(AMOVD, &r1, N);
- p1->to.type = TYPE_MEM;
- p1->to.reg = REGSP;
- p1->to.offset = -8;
- p1 = gins(AFMOVD, N, &r2);
- p1->from.type = TYPE_MEM;
- 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], 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;
-
- // TODO(austin): Add self-move test like in 6g (but be careful
- // of truncation moves)
-
- 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(debug['g'])
- print("%P\n", p);
-
- 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:
- if(af.type == TYPE_CONST || af.type == TYPE_ADDR)
- break;
- w = 8;
- break;
- }
- if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != TYPE_REG && 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 == 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.
- fatal("offset too large: %N", n);
- 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;
- }
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
- int a;
-
- if(t == T)
- fatal("optoas: t is nil");
-
- a = AXXX;
- 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(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);
- memset(a, 0, sizeof *a);
- return 0;
-}
diff --git a/src/cmd/new9g/gsubr.go b/src/cmd/9g/gsubr.go
index 91e87ff015..91e87ff015 100644
--- a/src/cmd/new9g/gsubr.go
+++ b/src/cmd/9g/gsubr.go
diff --git a/src/cmd/new9g/opt.go b/src/cmd/9g/opt.go
index a0294209aa..a0294209aa 100644
--- a/src/cmd/new9g/opt.go
+++ b/src/cmd/9g/opt.go
diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h
deleted file mode 100644
index 79a34fb1f0..0000000000
--- a/src/cmd/9g/opt.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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.
-
-// Many Power ISA arithmetic and logical instructions come in four
-// standard variants. These bits let us map between variants.
-enum {
- V_CC = 1<<0, // xCC (affect CR field 0 flags)
- V_V = 1<<1, // xV (affect SO and OV flags)
-};
-
-int as2variant(int);
-int variant2as(int, int);
diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c
deleted file mode 100644
index cf96d5dcda..0000000000
--- a/src/cmd/9g/peep.c
+++ /dev/null
@@ -1,959 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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 "../gc/popt.h"
-#include "opt.h"
-
-static int regzer(Addr *a);
-static int subprop(Flow*);
-static int copyprop(Flow*);
-static int copy1(Addr*, Addr*, Flow*, int);
-static int copyas(Addr*, Addr*);
-static int copyau(Addr*, Addr*);
-static int copysub(Addr*, Addr*, Addr*, int);
-static int copysub1(Prog*, Addr*, Addr*, int);
-static int copyau1(Prog *p, Addr *v);
-static int copyu(Prog *p, Addr *v, Addr *s);
-
-static uint32 gactive;
-
-void
-peep(Prog *firstp)
-{
- Graph *g;
- Flow *r, *r1;
- Prog *p, *p1;
- int t;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
- gactive = 0;
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", g->start, 0);
-
- t = 0;
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- // TODO(austin) Handle smaller moves. arm and amd64
- // distinguish between moves that moves that *must*
- // sign/zero extend and moves that don't care so they
- // can eliminate moves that don't care without
- // breaking moves that do care. This might let us
- // simplify or remove the next peep loop, too.
- if(p->as == AMOVD || p->as == AFMOVD)
- if(regtyp(&p->to)) {
- // Try to eliminate reg->reg moves
- if(regtyp(&p->from))
- if(p->from.type == p->to.type) {
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- // Convert uses to $0 to uses of R0 and
- // propagate R0
- if(regzer(&p->from))
- if(p->to.type == TYPE_REG) {
- p->from.type = TYPE_REG;
- p->from.reg = REGZERO;
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- }
- }
- if(t)
- goto loop1;
-
- /*
- * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
- */
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- default:
- continue;
- case AMOVH:
- case AMOVHZ:
- case AMOVB:
- case AMOVBZ:
- case AMOVW:
- case AMOVWZ:
- if(p->to.type != TYPE_REG)
- continue;
- break;
- }
- r1 = r->link;
- if(r1 == nil)
- continue;
- p1 = r1->prog;
- if(p1->as != p->as)
- continue;
- if(p1->from.type != TYPE_REG || p1->from.reg != p->to.reg)
- continue;
- if(p1->to.type != TYPE_REG || p1->to.reg != p->to.reg)
- continue;
- excise(r1);
- }
-
- if(debug['D'] > 1)
- goto ret; /* allow following code improvement to be suppressed */
-
- /*
- * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
- * when OP can set condition codes correctly
- */
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ACMP:
- case ACMPW: /* always safe? */
- if(!regzer(&p->to))
- continue;
- r1 = r->s1;
- if(r1 == nil)
- continue;
- switch(r1->prog->as) {
- default:
- continue;
- case ABCL:
- case ABC:
- /* the conditions can be complex and these are currently little used */
- continue;
- case ABEQ:
- case ABGE:
- case ABGT:
- case ABLE:
- case ABLT:
- case ABNE:
- case ABVC:
- case ABVS:
- break;
- }
- r1 = r;
- do
- r1 = uniqp(r1);
- while (r1 != nil && r1->prog->as == ANOP);
- if(r1 == nil)
- continue;
- p1 = r1->prog;
- if(p1->to.type != TYPE_REG || p1->to.reg != p->from.reg)
- continue;
- switch(p1->as) {
- case ASUB:
- case AADD:
- case AXOR:
- case AOR:
- /* irregular instructions */
- if(p1->from.type == TYPE_CONST || p1->from.type == TYPE_ADDR)
- continue;
- break;
- }
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- case AMOVD:
- if(p1->from.type != TYPE_REG)
- continue;
- continue;
- case AANDCC:
- case AANDNCC:
- case AORCC:
- case AORNCC:
- case AXORCC:
- case ASUBCC:
- case ASUBECC:
- case ASUBMECC:
- case ASUBZECC:
- case AADDCC:
- case AADDCCC:
- case AADDECC:
- case AADDMECC:
- case AADDZECC:
- case ARLWMICC:
- case ARLWNMCC:
- /* don't deal with floating point instructions for now */
-/*
- case AFABS:
- case AFADD:
- case AFADDS:
- case AFCTIW:
- case AFCTIWZ:
- case AFDIV:
- case AFDIVS:
- case AFMADD:
- case AFMADDS:
- case AFMOVD:
- case AFMSUB:
- case AFMSUBS:
- case AFMUL:
- case AFMULS:
- case AFNABS:
- case AFNEG:
- case AFNMADD:
- case AFNMADDS:
- case AFNMSUB:
- case AFNMSUBS:
- case AFRSP:
- case AFSUB:
- case AFSUBS:
- case ACNTLZW:
- case AMTFSB0:
- case AMTFSB1:
-*/
- case AADD:
- case AADDV:
- case AADDC:
- case AADDCV:
- case AADDME:
- case AADDMEV:
- case AADDE:
- case AADDEV:
- case AADDZE:
- case AADDZEV:
- case AAND:
- case AANDN:
- case ADIVW:
- case ADIVWV:
- case ADIVWU:
- case ADIVWUV:
- case ADIVD:
- case ADIVDV:
- case ADIVDU:
- case ADIVDUV:
- case AEQV:
- case AEXTSB:
- case AEXTSH:
- case AEXTSW:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLWV:
- case AMULHD:
- case AMULHDU:
- case AMULLD:
- case AMULLDV:
- case ANAND:
- case ANEG:
- case ANEGV:
- case ANOR:
- case AOR:
- case AORN:
- case AREM:
- case AREMV:
- case AREMU:
- case AREMUV:
- case AREMD:
- case AREMDV:
- case AREMDU:
- case AREMDUV:
- case ARLWMI:
- case ARLWNM:
- case ASLW:
- case ASRAW:
- case ASRW:
- case ASLD:
- case ASRAD:
- case ASRD:
- case ASUB:
- case ASUBV:
- case ASUBC:
- case ASUBCV:
- case ASUBME:
- case ASUBMEV:
- case ASUBE:
- case ASUBEV:
- case ASUBZE:
- case ASUBZEV:
- case AXOR:
- t = variant2as(p1->as, as2variant(p1->as) | V_CC);
- break;
- }
- if(debug['D'])
- print("cmp %P; %P -> ", p1, p);
- p1->as = t;
- if(debug['D'])
- print("%P\n", p1);
- excise(r);
- continue;
- }
- }
-
-ret:
- flowend(g);
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
- nopout(p);
- ostats.ndelmov++;
-}
-
-/*
- * regzer returns 1 if a's value is 0 (a is R0 or $0)
- */
-static int
-regzer(Addr *a)
-{
- if(a->type == TYPE_CONST || a->type == TYPE_ADDR)
- if(a->sym == nil && a->reg == 0)
- if(a->offset == 0)
- return 1;
- if(a->type == TYPE_REG)
- if(a->reg == REGZERO)
- return 1;
- return 0;
-}
-
-int
-regtyp(Adr *a)
-{
- // TODO(rsc): Floating point register exclusions?
- return a->type == TYPE_REG && REG_R0 <= a->reg && a->reg <= REG_F31 && a->reg != REGZERO;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R1
- * ADD b, R1 / no use of R2
- * MOV R1, R2
- * would be converted to
- * MOV a, R2
- * ADD b, R2
- * MOV R2, R1
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- *
- * r0 (the argument, not the register) is the MOV at the end of the
- * above sequences. This returns 1 if it modified any instructions.
- */
-static int
-subprop(Flow *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Flow *r;
- int t;
- ProgInfo info;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- if(uniqs(r) == nil)
- break;
- p = r->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
- if(info.flags & Call)
- return 0;
-
- if((info.flags & (RightRead|RightWrite)) == RightWrite) {
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- goto gotit;
- }
-
- if(copyau(&p->from, v2) ||
- copyau1(p, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub1(p, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub1(p, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail (v1->v2 move must remain)
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success (caller can remove v1->v2 move)
- */
-static int
-copyprop(Flow *r0)
-{
- Prog *p;
- Addr *v1, *v2;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2)) {
- if(debug['P'])
- print("eliminating self-move\n", r0->prog);
- return 1;
- }
- gactive++;
- if(debug['P'])
- print("trying to eliminate %D->%D move from:\n%P\n", v1, v2, r0->prog);
- return copy1(v1, v2, r0->s1, 0);
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
-// all uses were rewritten.
-static int
-copy1(Addr *v1, Addr *v2, Flow *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active == gactive) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = gactive;
- if(debug['P'])
- print("copy1 replace %D with %D f=%d\n", v2, v1, f);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == nil) {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub %D->%D\n => %P", v2, v1, p);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, nil);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %D set and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// 1 if v only used
-// 2 if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// 3 if v is only set
-// 4 if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// 0 otherwise (not touched)
-static int
-copyu(Prog *p, Addr *v, Addr *s)
-{
- if(p->from3.type != TYPE_NONE)
- // 9g never generates a from3
- print("copyu: from3 (%D) not implemented\n", &p->from3);
-
- switch(p->as) {
-
- default:
- print("copyu: can't find %A\n", p->as);
- return 2;
-
- case ANOP: /* read p->from, write p->to */
- case AMOVH:
- case AMOVHZ:
- case AMOVB:
- case AMOVBZ:
- case AMOVW:
- case AMOVWZ:
- case AMOVD:
-
- case ANEG:
- case ANEGCC:
- case AADDME:
- case AADDMECC:
- case AADDZE:
- case AADDZECC:
- case ASUBME:
- case ASUBMECC:
- case ASUBZE:
- case ASUBZECC:
-
- case AFCTIW:
- case AFCTIWZ:
- case AFCTID:
- case AFCTIDZ:
- case AFCFID:
- case AFCFIDCC:
- case AFMOVS:
- case AFMOVD:
- case AFRSP:
- case AFNEG:
- case AFNEGCC:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- // Update only indirect uses of v in p->to
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- // Fix up implicit from
- if(p->from.type == TYPE_NONE)
- p->from = p->to;
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- // p->to only indirectly uses v
- return 1;
- return 0;
-
- case AMOVBU: /* rar p->from, write p->to or read p->from, rar p->to */
- case AMOVBZU:
- case AMOVHU:
- case AMOVHZU:
- case AMOVWZU:
- case AMOVDU:
- if(p->from.type == TYPE_MEM) {
- if(copyas(&p->from, v))
- // No s!=nil check; need to fail
- // anyway in that case
- return 2;
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v))
- return 3;
- } else if (p->to.type == TYPE_MEM) {
- if(copyas(&p->to, v))
- return 2;
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->from, v))
- return 1;
- } else {
- print("copyu: bad %P\n", p);
- }
- return 0;
-
- case ARLWMI: /* read p->from, read p->reg, rar p->to */
- case ARLWMICC:
- if(copyas(&p->to, v))
- return 2;
- /* fall through */
-
- case AADD: /* read p->from, read p->reg, write p->to */
- case AADDC:
- case AADDE:
- case ASUB:
- case ASLW:
- case ASRW:
- case ASRAW:
- case ASLD:
- case ASRD:
- case ASRAD:
- case AOR:
- case AORCC:
- case AORN:
- case AORNCC:
- case AAND:
- case AANDCC:
- case AANDN:
- case AANDNCC:
- case ANAND:
- case ANANDCC:
- case ANOR:
- case ANORCC:
- case AXOR:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLD:
- case ADIVW:
- case ADIVD:
- case ADIVWU:
- case ADIVDU:
- case AREM:
- case AREMU:
- case AREMD:
- case AREMDU:
- case ARLWNM:
- case ARLWNMCC:
-
- case AFADDS:
- case AFADD:
- case AFSUBS:
- case AFSUB:
- case AFMULS:
- case AFMUL:
- case AFDIVS:
- case AFDIV:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(copysub1(p, v, s, 1))
- return 1;
- // Update only indirect uses of v in p->to
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->reg == 0)
- // Fix up implicit reg (e.g., ADD
- // R3,R4 -> ADD R3,R4,R4) so we can
- // update reg and to separately.
- p->reg = p->to.reg;
- if(copyau(&p->from, v))
- return 4;
- if(copyau1(p, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ABEQ:
- case ABGT:
- case ABGE:
- case ABLT:
- case ABLE:
- case ABNE:
- case ABVC:
- case ABVS:
- return 0;
-
- case ACHECKNIL: /* read p->from */
- case ACMP: /* read p->from, read p->to */
- case ACMPU:
- case ACMPW:
- case ACMPWU:
- case AFCMPO:
- case AFCMPU:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ABR: /* read p->to */
- // 9g never generates a branch to a GPR (this isn't
- // even a normal instruction; liblink turns it in to a
- // mov and a branch).
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARETURN: /* funny */
- if(s != nil)
- return 0;
- // All registers die at this point, so claim
- // everything is set (and not used).
- return 3;
-
- case ABL: /* funny */
- if(v->type == TYPE_REG) {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if(REG_R0 < v->reg && v->reg <= REGEXT)
- return 2;
- if(v->reg == REGARG)
- return 2;
- if(REG_F0 < v->reg && v->reg <= FREGEXT)
- return 2;
- }
- if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg)
- return 2;
-
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ADUFFZERO:
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R3 is ptr to memory, used and set, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == 0)
- return 1;
- if(v->reg == 3)
- return 2;
- }
- return 0;
-
- case ADUFFCOPY:
- // R3, R4 are ptr to src, dst, used and set, cannot be substituted.
- // R5 is scratch, set by DUFFCOPY, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == 3 || v->reg == 4)
- return 2;
- if(v->reg == 5)
- return 3;
- }
- return 0;
-
- case ATEXT: /* funny */
- if(v->type == TYPE_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
-
- case APCDATA:
- case AFUNCDATA:
- case AVARDEF:
- case AVARKILL:
- return 0;
- }
-}
-
-// copyas returns 1 if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-static int
-copyas(Addr *a, Addr *v)
-{
- if(regtyp(v))
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- return 0;
-}
-
-// copyau returns 1 if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-static int
-copyau(Addr *a, Addr *v)
-{
- if(copyas(a, v))
- return 1;
- if(v->type == TYPE_REG)
- if(a->type == TYPE_MEM || (a->type == TYPE_ADDR && a->reg != 0))
- if(v->reg == a->reg)
- return 1;
- return 0;
-}
-
-// copyau1 returns 1 if p->reg references the same register as v and v
-// is a direct reference.
-static int
-copyau1(Prog *p, Addr *v)
-{
- if(regtyp(v) && v->reg != 0)
- if(p->reg == v->reg)
- return 1;
- return 0;
-}
-
-// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
-// Returns 1 on failure to substitute (it always succeeds on ppc64).
-static int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
- if(f)
- if(copyau(a, v))
- a->reg = s->reg;
- return 0;
-}
-
-// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
-// Returns 1 on failure to substitute (it always succeeds on ppc64).
-static int
-copysub1(Prog *p1, Addr *v, Addr *s, int f)
-{
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
- if(a->type != v->type)
- return 0;
- if(regtyp(v) && a->reg == v->reg)
- return 1;
- if(v->type == NAME_AUTO || v->type == NAME_PARAM)
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
- return reg->type == TYPE_REG && a->type == TYPE_MEM &&
- a->reg == reg->reg &&
- 0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
- return a->type == TYPE_REG && a->reg == REGSP;
-}
diff --git a/src/cmd/new9g/peep.go b/src/cmd/9g/peep.go
index 486b316dcf..486b316dcf 100644
--- a/src/cmd/new9g/peep.go
+++ b/src/cmd/9g/peep.go
diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c
deleted file mode 100644
index 561249c358..0000000000
--- a/src/cmd/9g/prog.c
+++ /dev/null
@@ -1,308 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-#include "opt.h"
-
-enum {
- LeftRdwr = LeftRead | LeftWrite,
- RightRdwr = RightRead | RightWrite,
-};
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-static ProgInfo progtable[ALAST] = {
- [ATYPE]= {Pseudo | Skip},
- [ATEXT]= {Pseudo},
- [AFUNCDATA]= {Pseudo},
- [APCDATA]= {Pseudo},
- [AUNDEF]= {Break},
- [AUSEFIELD]= {OK},
- [ACHECKNIL]= {LeftRead},
- [AVARDEF]= {Pseudo | RightWrite},
- [AVARKILL]= {Pseudo | RightWrite},
-
- // NOP is an internal no-op that also stands
- // for USED and SET annotations, not the Power opcode.
- [ANOP]= {LeftRead | RightWrite},
-
- // Integer
- [AADD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ASUB]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ANEG]= {SizeQ | LeftRead | RegRead | RightWrite},
- [AAND]= {SizeQ | LeftRead | RegRead | RightWrite},
- [AOR]= {SizeQ | LeftRead | RegRead | RightWrite},
- [AXOR]= {SizeQ | LeftRead | RegRead | RightWrite},
- [AMULLD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [AMULLW]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMULHD]= {SizeL | LeftRead | RegRead | RightWrite},
- [AMULHDU]= {SizeL | LeftRead | RegRead | RightWrite},
- [ADIVD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ADIVDU]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ASLD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ASRD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ASRAD]= {SizeQ | LeftRead | RegRead | RightWrite},
- [ACMP]= {SizeQ | LeftRead | RightRead},
- [ACMPU]= {SizeQ | LeftRead | RightRead},
- [ATD]= {SizeQ | RightRead},
-
- // Floating point.
- [AFADD]= {SizeD | LeftRead | RegRead | RightWrite},
- [AFADDS]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFSUB]= {SizeD | LeftRead | RegRead | RightWrite},
- [AFSUBS]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFMUL]= {SizeD | LeftRead | RegRead | RightWrite},
- [AFMULS]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFDIV]= {SizeD | LeftRead | RegRead | RightWrite},
- [AFDIVS]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFCTIDZ]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFCFID]= {SizeF | LeftRead | RegRead | RightWrite},
- [AFCMPU]= {SizeD | LeftRead | RightRead},
- [AFRSP]= {SizeD | LeftRead | RightWrite | Conv},
-
- // Moves
- [AMOVB]= {SizeB | LeftRead | RightWrite | Move | Conv},
- [AMOVBU]= {SizeB | LeftRead | RightWrite | Move | Conv | PostInc},
- [AMOVBZ]= {SizeB | LeftRead | RightWrite | Move | Conv},
- [AMOVH]= {SizeW | LeftRead | RightWrite | Move | Conv},
- [AMOVHU]= {SizeW | LeftRead | RightWrite | Move | Conv | PostInc},
- [AMOVHZ]= {SizeW | LeftRead | RightWrite | Move | Conv},
- [AMOVW]= {SizeL | LeftRead | RightWrite | Move | Conv},
- // there is no AMOVWU.
- [AMOVWZU]= {SizeL | LeftRead | RightWrite | Move | Conv | PostInc},
- [AMOVWZ]= {SizeL | LeftRead | RightWrite | Move | Conv},
- [AMOVD]= {SizeQ | LeftRead | RightWrite | Move},
- [AMOVDU]= {SizeQ | LeftRead | RightWrite | Move | PostInc},
- [AFMOVS]= {SizeF | LeftRead | RightWrite | Move | Conv},
- [AFMOVD]= {SizeD | LeftRead | RightWrite | Move},
-
- // Jumps
- [ABR]= {Jump | Break},
- [ABL]= {Call},
- [ABEQ]= {Cjmp},
- [ABNE]= {Cjmp},
- [ABGE]= {Cjmp},
- [ABLT]= {Cjmp},
- [ABGT]= {Cjmp},
- [ABLE]= {Cjmp},
- [ARETURN]= {Break},
-
- [ADUFFZERO]= {Call},
- [ADUFFCOPY]= {Call},
-};
-
-static void
-initproginfo(void)
-{
- static int initialized;
- int addvariant[] = {V_CC, V_V, V_CC|V_V};
- int as, as2, i, variant;
-
- if(initialized)
- return;
- initialized = 1;
-
- // Perform one-time expansion of instructions in progtable to
- // their CC, V, and VCC variants
- for(as=0; as<nelem(progtable); as++) {
- if(progtable[as].flags == 0)
- continue;
- variant = as2variant(as);
- for(i=0; i<nelem(addvariant); i++) {
- as2 = variant2as(as, variant | addvariant[i]);
- if(as2 != 0 && progtable[as2].flags == 0)
- progtable[as2] = progtable[as];
- }
- }
-}
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
- initproginfo();
-
- *info = progtable[p->as];
- if(info->flags == 0) {
- *info = progtable[AADD];
- fatal("proginfo: unknown instruction %P", p);
- }
-
- if((info->flags & RegRead) && p->reg == 0) {
- info->flags &= ~RegRead;
- info->flags |= /*CanRegRead |*/ RightRead;
- }
-
- if((p->from.type == TYPE_MEM || p->from.type == TYPE_ADDR) && p->from.reg != 0) {
- info->regindex |= RtoB(p->from.reg);
- if(info->flags & PostInc) {
- info->regset |= RtoB(p->from.reg);
- }
- }
- if((p->to.type == TYPE_MEM || p->to.type == TYPE_ADDR) && p->to.reg != 0) {
- info->regindex |= RtoB(p->to.reg);
- if(info->flags & PostInc) {
- info->regset |= RtoB(p->to.reg);
- }
- }
-
- if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) {
- info->flags &= ~LeftRead;
- info->flags |= LeftAddr;
- }
-
- if(p->as == ADUFFZERO) {
- info->reguse |= (1<<0) | RtoB(REG_R3);
- info->regset |= RtoB(REG_R3);
- }
- if(p->as == ADUFFCOPY) {
- // TODO(austin) Revisit when duffcopy is implemented
- info->reguse |= RtoB(REG_R3) | RtoB(REG_R4) | RtoB(REG_R5);
- info->regset |= RtoB(REG_R3) | RtoB(REG_R4);
- }
-}
-
-// Instruction variants table. Initially this contains entries only
-// for the "base" form of each instruction. On the first call to
-// as2variant or variant2as, we'll add the variants to the table.
-static int varianttable[ALAST][4] = {
- [AADD]= {AADD, AADDCC, AADDV, AADDVCC},
- [AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC},
- [AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC},
- [AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC},
- [AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC},
- [AAND]= {AAND, AANDCC, 0, 0},
- [AANDN]= {AANDN, AANDNCC, 0, 0},
- [ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0},
- [ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0},
- [ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC},
- [ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC},
- [ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC},
- [ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC},
- [AEQV]= {AEQV, AEQVCC, 0, 0},
- [AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0},
- [AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0},
- [AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0},
- [AFABS]= {AFABS, AFABSCC, 0, 0},
- [AFADD]= {AFADD, AFADDCC, 0, 0},
- [AFADDS]= {AFADDS, AFADDSCC, 0, 0},
- [AFCFID]= {AFCFID, AFCFIDCC, 0, 0},
- [AFCTID]= {AFCTID, AFCTIDCC, 0, 0},
- [AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0},
- [AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0},
- [AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0},
- [AFDIV]= {AFDIV, AFDIVCC, 0, 0},
- [AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0},
- [AFMADD]= {AFMADD, AFMADDCC, 0, 0},
- [AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0},
- [AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0},
- [AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0},
- [AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0},
- [AFMUL]= {AFMUL, AFMULCC, 0, 0},
- [AFMULS]= {AFMULS, AFMULSCC, 0, 0},
- [AFNABS]= {AFNABS, AFNABSCC, 0, 0},
- [AFNEG]= {AFNEG, AFNEGCC, 0, 0},
- [AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0},
- [AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0},
- [AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0},
- [AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0},
- [AFRES]= {AFRES, AFRESCC, 0, 0},
- [AFRSP]= {AFRSP, AFRSPCC, 0, 0},
- [AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0},
- [AFSEL]= {AFSEL, AFSELCC, 0, 0},
- [AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0},
- [AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0},
- [AFSUB]= {AFSUB, AFSUBCC, 0, 0},
- [AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0},
- [AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0},
- [AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0},
- [AMULHD]= {AMULHD, AMULHDCC, 0, 0},
- [AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0},
- [AMULHW]= {AMULHW, AMULHWCC, 0, 0},
- [AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0},
- [AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC},
- [AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC},
- [ANAND]= {ANAND, ANANDCC, 0, 0},
- [ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC},
- [ANOR]= {ANOR, ANORCC, 0, 0},
- [AOR]= {AOR, AORCC, 0, 0},
- [AORN]= {AORN, AORNCC, 0, 0},
- [AREM]= {AREM, AREMCC, AREMV, AREMVCC},
- [AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC},
- [AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC},
- [AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC},
- [ARLDC]= {ARLDC, ARLDCCC, 0, 0},
- [ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0},
- [ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0},
- [ARLDMI]= {ARLDMI, ARLDMICC, 0, 0},
- [ARLWMI]= {ARLWMI, ARLWMICC, 0, 0},
- [ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0},
- [ASLD]= {ASLD, ASLDCC, 0, 0},
- [ASLW]= {ASLW, ASLWCC, 0, 0},
- [ASRAD]= {ASRAD, ASRADCC, 0, 0},
- [ASRAW]= {ASRAW, ASRAWCC, 0, 0},
- [ASRD]= {ASRD, ASRDCC, 0, 0},
- [ASRW]= {ASRW, ASRWCC, 0, 0},
- [ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC},
- [ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC},
- [ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC},
- [ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC},
- [ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC},
- [AXOR]= {AXOR, AXORCC, 0, 0},
-};
-
-static void
-initvariants(void)
-{
- static int initialized;
- int i, j;
-
- if(initialized)
- return;
- initialized = 1;
-
- for(i=0; i<nelem(varianttable); i++) {
- if(varianttable[i][0] == 0) {
- // Instruction has no variants
- varianttable[i][0] = i;
- continue;
- }
- // Copy base form to other variants
- if(varianttable[i][0] == i) {
- for(j=0; j<nelem(varianttable[i]); j++)
- memmove(&varianttable[varianttable[i][j]], &varianttable[i], sizeof(varianttable[i]));
- }
- }
-}
-
-// as2variant returns the variant (V_*) flags of instruction as.
-int
-as2variant(int as)
-{
- int i;
- initvariants();
- for(i=0; i<nelem(varianttable[as]); i++)
- if(varianttable[as][i] == as)
- return i;
- fatal("as2variant: instruction %A is not a variant of itself", as);
- return 0;
-}
-
-// variant2as returns the instruction as with the given variant (V_*) flags.
-// If no such variant exists, this returns 0.
-int
-variant2as(int as, int flags)
-{
- initvariants();
- return varianttable[as][flags];
-}
diff --git a/src/cmd/new9g/prog.go b/src/cmd/9g/prog.go
index e188f0dc65..e188f0dc65 100644
--- a/src/cmd/new9g/prog.go
+++ b/src/cmd/9g/prog.go
diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c
deleted file mode 100644
index 84e1747e8d..0000000000
--- a/src/cmd/9g/reg.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 "../gc/popt.h"
-
-enum {
- NREGVAR = 64, /* 32 general + 32 floating */
-};
-
-
-static char* regname[] = {
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".R16",
- ".R17",
- ".R18",
- ".R19",
- ".R20",
- ".R21",
- ".R22",
- ".R23",
- ".R24",
- ".R25",
- ".R26",
- ".R27",
- ".R28",
- ".R29",
- ".R30",
- ".R31",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
- ".F16",
- ".F17",
- ".F18",
- ".F19",
- ".F20",
- ".F21",
- ".F22",
- ".F23",
- ".F24",
- ".F25",
- ".F26",
- ".F27",
- ".F28",
- ".F29",
- ".F30",
- ".F31",
-};
-
-char**
-regnames(int *n)
-{
- *n = NREGVAR;
- return regname;
-}
-
-uint64
-excludedregs(void)
-{
- uint64 regbits;
-
- // Exclude registers with fixed functions
- regbits = (1<<0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
- // Also exclude floating point registers with fixed constants
- regbits |= RtoB(REG_F27)|RtoB(REG_F28)|RtoB(REG_F29)|RtoB(REG_F30)|RtoB(REG_F31);
- return regbits;
-}
-
-uint64
-doregbits(int r)
-{
- USED(r);
- return 0;
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 31 R31
- * 32+0 F0
- * 32+1 F1
- * ... ...
- * 32+31 F31
- */
-uint64
-RtoB(int r)
-{
- if(r > REG_R0 && r <= REG_R31)
- return 1ULL << (r - REG_R0);
- if(r >= REG_F0 && r <= REG_F31)
- return 1ULL << (32 + r - REG_F0);
- return 0;
-}
-
-int
-BtoR(uint64 b)
-{
- b &= 0xffffffffull;
- if(b == 0)
- return 0;
- return bitno(b) + REG_R0;
-}
-
-int
-BtoF(uint64 b)
-{
- b >>= 32;
- if(b == 0)
- return 0;
- return bitno(b) + REG_F0;
-}
diff --git a/src/cmd/new9g/reg.go b/src/cmd/9g/reg.go
index faed60d0ee..faed60d0ee 100644
--- a/src/cmd/new9g/reg.go
+++ b/src/cmd/9g/reg.go
diff --git a/src/cmd/new9g/util.go b/src/cmd/9g/util.go
index bb5eedb15a..bb5eedb15a 100644
--- a/src/cmd/new9g/util.go
+++ b/src/cmd/9g/util.go
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
deleted file mode 100644
index 58e25faaf9..0000000000
--- a/src/cmd/gc/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.
-
-include ../../Make.dist
-
-install: y.tab.h builtin.c
-
-y.tab.h: go.y go.errors bisonerrors
- bison -v -y -d go.y
- # make yystate global, yytname mutable
- cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
- mv y1.tab.c y.tab.c
- awk -f bisonerrors y.output go.errors >yerr.h
-
-builtin.c: runtime.go unsafe.go
- ./mkbuiltin
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
deleted file mode 100644
index 59ff0abf73..0000000000
--- a/src/cmd/gc/align.c
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * machine size and rounding
- * alignment is dictated around
- * the size of a pointer, set in betypeinit
- * (see ../6g/galign.c).
- */
-
-static int defercalc;
-
-vlong
-rnd(vlong o, vlong r)
-{
- if(r < 1 || r > 8 || (r&(r-1)) != 0)
- fatal("rnd %lld", r);
- return (o+r-1)&~(r-1);
-}
-
-static void
-offmod(Type *t)
-{
- Type *f;
- int32 o;
-
- o = 0;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("offmod: not TFIELD: %lT", f);
- f->width = o;
- o += widthptr;
- if(o >= thearch.MAXWIDTH) {
- yyerror("interface too large");
- o = widthptr;
- }
- }
-}
-
-static vlong
-widstruct(Type *errtype, Type *t, vlong o, int flag)
-{
- Type *f;
- int64 w;
- int32 maxalign;
- vlong starto, lastzero;
-
- starto = o;
- maxalign = flag;
- if(maxalign < 1)
- maxalign = 1;
- lastzero = 0;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("widstruct: not TFIELD: %lT", f);
- if(f->type == T) {
- // broken field, just skip it so that other valid fields
- // get a width.
- continue;
- }
- dowidth(f->type);
- if(f->type->align > maxalign)
- maxalign = f->type->align;
- if(f->type->width < 0)
- fatal("invalid width %lld", f->type->width);
- w = f->type->width;
- if(f->type->align > 0)
- o = rnd(o, f->type->align);
- f->width = o; // really offset for TFIELD
- if(f->nname != N) {
- // this same stackparam logic is in addrescapes
- // in typecheck.c. usually addrescapes runs after
- // widstruct, in which case we could drop this,
- // but function closure functions are the exception.
- if(f->nname->stackparam) {
- f->nname->stackparam->xoffset = o;
- f->nname->xoffset = 0;
- } else
- f->nname->xoffset = o;
- }
- if(w == 0)
- lastzero = o;
- o += w;
- if(o >= thearch.MAXWIDTH) {
- yyerror("type %lT too large", errtype);
- o = 8; // small but nonzero
- }
- }
- // For nonzero-sized structs which end in a zero-sized thing, we add
- // an extra byte of padding to the type. This padding ensures that
- // taking the address of the zero-sized thing can't manufacture a
- // pointer to the next object in the heap. See issue 9401.
- if(flag == 1 && o > starto && o == lastzero)
- o++;
-
- // final width is rounded
- if(flag)
- o = rnd(o, maxalign);
- t->align = maxalign;
-
- // type width only includes back to first field's offset
- t->width = o - starto;
- return o;
-}
-
-void
-dowidth(Type *t)
-{
- int32 et;
- int64 w;
- int lno;
- Type *t1;
-
- if(widthptr == 0)
- fatal("dowidth without betypeinit");
-
- if(t == T)
- return;
-
- if(t->width > 0)
- return;
-
- if(t->width == -2) {
- lno = lineno;
- lineno = t->lineno;
- if(!t->broke) {
- t->broke = 1;
- yyerror("invalid recursive type %T", t);
- }
- t->width = 0;
- lineno = lno;
- return;
- }
-
- // break infinite recursion if the broken recursive type
- // is referenced again
- if(t->broke && t->width == 0)
- return;
-
- // defer checkwidth calls until after we're done
- defercalc++;
-
- lno = lineno;
- lineno = t->lineno;
- t->width = -2;
- t->align = 0;
-
- et = t->etype;
- switch(et) {
- case TFUNC:
- case TCHAN:
- case TMAP:
- case TSTRING:
- break;
-
- default:
- /* simtype == 0 during bootstrap */
- if(simtype[t->etype] != 0)
- et = simtype[t->etype];
- break;
- }
-
- w = 0;
- switch(et) {
- default:
- fatal("dowidth: unknown type: %T", t);
- break;
-
- /* compiler-specific stuff */
- case TINT8:
- case TUINT8:
- case TBOOL: // bool is int8
- w = 1;
- break;
- case TINT16:
- case TUINT16:
- w = 2;
- break;
- case TINT32:
- case TUINT32:
- case TFLOAT32:
- w = 4;
- break;
- case TINT64:
- case TUINT64:
- case TFLOAT64:
- case TCOMPLEX64:
- w = 8;
- t->align = widthreg;
- break;
- case TCOMPLEX128:
- w = 16;
- t->align = widthreg;
- break;
- case TPTR32:
- w = 4;
- checkwidth(t->type);
- break;
- case TPTR64:
- w = 8;
- checkwidth(t->type);
- break;
- case TUNSAFEPTR:
- w = widthptr;
- break;
- case TINTER: // implemented as 2 pointers
- w = 2*widthptr;
- t->align = widthptr;
- offmod(t);
- break;
- case TCHAN: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
-
- // make fake type to check later to
- // trigger channel argument check.
- t1 = typ(TCHANARGS);
- t1->type = t;
- checkwidth(t1);
- break;
- case TCHANARGS:
- t1 = t->type;
- dowidth(t->type); // just in case
- if(t1->type->width >= (1<<16))
- yyerror("channel element type too large (>64kB)");
- t->width = 1;
- break;
- case TMAP: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
- checkwidth(t->down);
- break;
- case TFORW: // should have been filled in
- if(!t->broke)
- yyerror("invalid recursive type %T", t);
- w = 1; // anything will do
- break;
- case TANY:
- // dummy type; should be replaced before use.
- if(!debug['A'])
- fatal("dowidth any");
- w = 1; // anything will do
- break;
- case TSTRING:
- if(sizeof_String == 0)
- fatal("early dowidth string");
- w = sizeof_String;
- t->align = widthptr;
- break;
- case TARRAY:
- if(t->type == T)
- break;
- if(t->bound >= 0) {
- uint64 cap;
-
- dowidth(t->type);
- if(t->type->width != 0) {
- cap = (thearch.MAXWIDTH-1) / t->type->width;
- if(t->bound > cap)
- yyerror("type %lT larger than address space", t);
- }
- w = t->bound * t->type->width;
- t->align = t->type->align;
- }
- else if(t->bound == -1) {
- w = sizeof_Array;
- checkwidth(t->type);
- t->align = widthptr;
- }
- else if(t->bound == -100) {
- if(!t->broke) {
- yyerror("use of [...] array outside of array literal");
- t->broke = 1;
- }
- }
- else
- fatal("dowidth %T", t); // probably [...]T
- break;
-
- case TSTRUCT:
- if(t->funarg)
- fatal("dowidth fn struct %T", t);
- w = widstruct(t, t, 0, 1);
- break;
-
- case TFUNC:
- // make fake type to check later to
- // trigger function argument computation.
- t1 = typ(TFUNCARGS);
- t1->type = t;
- checkwidth(t1);
-
- // width of func type is pointer
- w = widthptr;
- break;
-
- case TFUNCARGS:
- // function is 3 cated structures;
- // compute their widths as side-effect.
- t1 = t->type;
- w = widstruct(t->type, *getthis(t1), 0, 0);
- w = widstruct(t->type, *getinarg(t1), w, widthreg);
- w = widstruct(t->type, *getoutarg(t1), w, widthreg);
- t1->argwid = w;
- if(w%widthreg)
- warn("bad type %T %d\n", t1, w);
- t->align = 1;
- break;
- }
-
- if(widthptr == 4 && w != (int32)w)
- yyerror("type %T too large", t);
-
- t->width = w;
- if(t->align == 0) {
- if(w > 8 || (w&(w-1)) != 0)
- fatal("invalid alignment for %T", t);
- t->align = w;
- }
- lineno = lno;
-
- if(defercalc == 1)
- resumecheckwidth();
- else
- --defercalc;
-}
-
-/*
- * when a type's width should be known, we call checkwidth
- * to compute it. during a declaration like
- *
- * type T *struct { next T }
- *
- * it is necessary to defer the calculation of the struct width
- * until after T has been initialized to be a pointer to that struct.
- * similarly, during import processing structs may be used
- * before their definition. in those situations, calling
- * defercheckwidth() stops width calculations until
- * resumecheckwidth() is called, at which point all the
- * checkwidths that were deferred are executed.
- * dowidth should only be called when the type's size
- * is needed immediately. checkwidth makes sure the
- * size is evaluated eventually.
- */
-typedef struct TypeList TypeList;
-struct TypeList {
- Type *t;
- TypeList *next;
-};
-
-static TypeList *tlfree;
-static TypeList *tlq;
-
-void
-checkwidth(Type *t)
-{
- TypeList *l;
-
- if(t == T)
- return;
-
- // function arg structs should not be checked
- // outside of the enclosing function.
- if(t->funarg)
- fatal("checkwidth %T", t);
-
- if(!defercalc) {
- dowidth(t);
- return;
- }
- if(t->deferwidth)
- return;
- t->deferwidth = 1;
-
- l = tlfree;
- if(l != nil)
- tlfree = l->next;
- else
- l = mal(sizeof *l);
-
- l->t = t;
- l->next = tlq;
- tlq = l;
-}
-
-void
-defercheckwidth(void)
-{
- // we get out of sync on syntax errors, so don't be pedantic.
- if(defercalc && nerrors == 0)
- fatal("defercheckwidth");
- defercalc = 1;
-}
-
-void
-resumecheckwidth(void)
-{
- TypeList *l;
-
- if(!defercalc)
- fatal("resumecheckwidth");
- for(l = tlq; l != nil; l = tlq) {
- l->t->deferwidth = 0;
- tlq = l->next;
- dowidth(l->t);
- l->next = tlfree;
- tlfree = l;
- }
- defercalc = 0;
-}
-
-void
-typeinit(void)
-{
- int i, etype, sameas;
- Type *t;
- Sym *s, *s1;
-
- if(widthptr == 0)
- fatal("typeinit before betypeinit");
-
- for(i=0; i<NTYPE; i++)
- simtype[i] = i;
-
- types[TPTR32] = typ(TPTR32);
- dowidth(types[TPTR32]);
-
- types[TPTR64] = typ(TPTR64);
- dowidth(types[TPTR64]);
-
- t = typ(TUNSAFEPTR);
- types[TUNSAFEPTR] = t;
- t->sym = pkglookup("Pointer", unsafepkg);
- t->sym->def = typenod(t);
-
- dowidth(types[TUNSAFEPTR]);
-
- tptr = TPTR32;
- if(widthptr == 8)
- tptr = TPTR64;
-
- for(i=TINT8; i<=TUINT64; i++)
- isint[i] = 1;
- isint[TINT] = 1;
- isint[TUINT] = 1;
- isint[TUINTPTR] = 1;
-
- isfloat[TFLOAT32] = 1;
- isfloat[TFLOAT64] = 1;
-
- iscomplex[TCOMPLEX64] = 1;
- iscomplex[TCOMPLEX128] = 1;
-
- isptr[TPTR32] = 1;
- isptr[TPTR64] = 1;
-
- isforw[TFORW] = 1;
-
- issigned[TINT] = 1;
- issigned[TINT8] = 1;
- issigned[TINT16] = 1;
- issigned[TINT32] = 1;
- issigned[TINT64] = 1;
-
- /*
- * initialize okfor
- */
- for(i=0; i<NTYPE; i++) {
- if(isint[i] || i == TIDEAL) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforarith[i] = 1;
- okforadd[i] = 1;
- okforand[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minintval[i] = mal(sizeof(*minintval[i]));
- maxintval[i] = mal(sizeof(*maxintval[i]));
- }
- if(isfloat[i]) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minfltval[i] = mal(sizeof(*minfltval[i]));
- maxfltval[i] = mal(sizeof(*maxfltval[i]));
- }
- if(iscomplex[i]) {
- okforeq[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- }
- }
-
- issimple[TBOOL] = 1;
-
- okforadd[TSTRING] = 1;
-
- okforbool[TBOOL] = 1;
-
- okforcap[TARRAY] = 1;
- okforcap[TCHAN] = 1;
-
- okforconst[TBOOL] = 1;
- okforconst[TSTRING] = 1;
-
- okforlen[TARRAY] = 1;
- okforlen[TCHAN] = 1;
- okforlen[TMAP] = 1;
- okforlen[TSTRING] = 1;
-
- okforeq[TPTR32] = 1;
- okforeq[TPTR64] = 1;
- okforeq[TUNSAFEPTR] = 1;
- okforeq[TINTER] = 1;
- okforeq[TCHAN] = 1;
- okforeq[TSTRING] = 1;
- okforeq[TBOOL] = 1;
- okforeq[TMAP] = 1; // nil only; refined in typecheck
- okforeq[TFUNC] = 1; // nil only; refined in typecheck
- okforeq[TARRAY] = 1; // nil slice only; refined in typecheck
- okforeq[TSTRUCT] = 1; // it's complicated; refined in typecheck
-
- okforcmp[TSTRING] = 1;
-
- for(i=0; i<nelem(okfor); i++)
- okfor[i] = okfornone;
-
- // binary
- okfor[OADD] = okforadd;
- okfor[OAND] = okforand;
- okfor[OANDAND] = okforbool;
- okfor[OANDNOT] = okforand;
- okfor[ODIV] = okforarith;
- okfor[OEQ] = okforeq;
- okfor[OGE] = okforcmp;
- okfor[OGT] = okforcmp;
- okfor[OLE] = okforcmp;
- okfor[OLT] = okforcmp;
- okfor[OMOD] = okforand;
- okfor[OMUL] = okforarith;
- okfor[ONE] = okforeq;
- okfor[OOR] = okforand;
- okfor[OOROR] = okforbool;
- okfor[OSUB] = okforarith;
- okfor[OXOR] = okforand;
- okfor[OLSH] = okforand;
- okfor[ORSH] = okforand;
-
- // unary
- okfor[OCOM] = okforand;
- okfor[OMINUS] = okforarith;
- okfor[ONOT] = okforbool;
- okfor[OPLUS] = okforarith;
-
- // special
- okfor[OCAP] = okforcap;
- okfor[OLEN] = okforlen;
-
- // comparison
- iscmp[OLT] = 1;
- iscmp[OGT] = 1;
- iscmp[OGE] = 1;
- iscmp[OLE] = 1;
- iscmp[OEQ] = 1;
- iscmp[ONE] = 1;
-
- mpatofix(maxintval[TINT8], "0x7f");
- mpatofix(minintval[TINT8], "-0x80");
- mpatofix(maxintval[TINT16], "0x7fff");
- mpatofix(minintval[TINT16], "-0x8000");
- mpatofix(maxintval[TINT32], "0x7fffffff");
- mpatofix(minintval[TINT32], "-0x80000000");
- mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
- mpatofix(minintval[TINT64], "-0x8000000000000000");
-
- mpatofix(maxintval[TUINT8], "0xff");
- mpatofix(maxintval[TUINT16], "0xffff");
- mpatofix(maxintval[TUINT32], "0xffffffff");
- mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
-
- /* f is valid float if min < f < max. (min and max are not themselves valid.) */
- mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/
- mpatoflt(minfltval[TFLOAT32], "-33554431p103");
- mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */
- mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
-
- maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
- minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
- maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
- minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
-
- /* for walk to use in error messages */
- types[TFUNC] = functype(N, nil, nil);
-
- /* types used in front end */
- // types[TNIL] got set early in lexinit
- types[TIDEAL] = typ(TIDEAL);
- types[TINTER] = typ(TINTER);
-
- /* simple aliases */
- simtype[TMAP] = tptr;
- simtype[TCHAN] = tptr;
- simtype[TFUNC] = tptr;
- simtype[TUNSAFEPTR] = tptr;
-
- /* pick up the backend thearch.typedefs */
- for(i=0; thearch.typedefs[i].name; i++) {
- s = lookup(thearch.typedefs[i].name);
- s1 = pkglookup(thearch.typedefs[i].name, builtinpkg);
-
- etype = thearch.typedefs[i].etype;
- if(etype < 0 || etype >= nelem(types))
- fatal("typeinit: %s bad etype", s->name);
- sameas = thearch.typedefs[i].sameas;
- if(sameas < 0 || sameas >= nelem(types))
- fatal("typeinit: %s bad sameas", s->name);
- simtype[etype] = sameas;
- minfltval[etype] = minfltval[sameas];
- maxfltval[etype] = maxfltval[sameas];
- minintval[etype] = minintval[sameas];
- maxintval[etype] = maxintval[sameas];
-
- t = types[etype];
- if(t != T)
- fatal("typeinit: %s already defined", s->name);
-
- t = typ(etype);
- t->sym = s1;
-
- dowidth(t);
- types[etype] = t;
- s1->def = typenod(t);
- }
-
- Array_array = rnd(0, widthptr);
- Array_nel = rnd(Array_array+widthptr, widthint);
- Array_cap = rnd(Array_nel+widthint, widthint);
- sizeof_Array = rnd(Array_cap+widthint, widthptr);
-
- // string is same as slice wo the cap
- sizeof_String = rnd(Array_nel+widthint, widthptr);
-
- dowidth(types[TSTRING]);
- dowidth(idealstring);
-}
-
-/*
- * compute total size of f's in/out arguments.
- */
-int
-argsize(Type *t)
-{
- Iter save;
- Type *fp;
- int64 w, x;
-
- w = 0;
-
- fp = structfirst(&save, getoutarg(t));
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = structnext(&save);
- }
-
- fp = funcfirst(&save, t);
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = funcnext(&save);
- }
-
- w = (w+widthptr-1) & ~(widthptr-1);
- if((int)w != w)
- fatal("argsize too big");
- return w;
-}
diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c
deleted file mode 100644
index d5d9646d6a..0000000000
--- a/src/cmd/gc/array.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum {
- DEFAULTCAPACITY = 16,
-};
-
-Array*
-arraynew(int capacity, int32 size)
-{
- Array *result;
-
- if(capacity < 0)
- fatal("arraynew: capacity %d is not positive", capacity);
- if(size < 0)
- fatal("arraynew: size %d is not positive\n", size);
- result = malloc(sizeof(*result));
- if(result == nil)
- fatal("arraynew: malloc failed\n");
- result->length = 0;
- result->size = size;
- result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity;
- result->data = malloc(result->capacity * result->size);
- if(result->data == nil)
- fatal("arraynew: malloc failed\n");
- return result;
-}
-
-void
-arrayfree(Array *array)
-{
- if(array == nil)
- return;
- free(array->data);
- free(array);
-}
-
-int
-arraylength(Array *array)
-{
- return array->length;
-}
-
-void*
-arrayget(Array *array, int index)
-{
- if(array == nil)
- fatal("arrayget: array is nil\n");
- if(index < 0 || index >= array->length)
- fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
- return array->data + index * array->size;
-}
-
-void
-arrayset(Array *array, int index, void *element)
-{
- if(array == nil)
- fatal("arrayset: array is nil\n");
- if(element == nil)
- fatal("arrayset: element is nil\n");
- if(index < 0 || index >= array->length)
- fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
- memmove(array->data + index * array->size, element, array->size);
-}
-
-static void
-ensurecapacity(Array *array, int capacity)
-{
- int32 newcapacity;
- char *newdata;
-
- if(array == nil)
- fatal("ensurecapacity: array is nil\n");
- if(capacity < 0)
- fatal("ensurecapacity: capacity %d is not positive", capacity);
- if(capacity >= array->capacity) {
- newcapacity = capacity + (capacity >> 1);
- newdata = realloc(array->data, newcapacity * array->size);
- if(newdata == nil)
- fatal("ensurecapacity: realloc failed\n");
- array->capacity = newcapacity;
- array->data = newdata;
- }
-}
-
-void
-arrayadd(Array *array, void *element)
-{
- if(array == nil)
- fatal("arrayset: array is nil\n");
- if(element == nil)
- fatal("arrayset: element is nil\n");
- ensurecapacity(array, array->length + 1);
- array->length++;
- arrayset(array, array->length - 1, element);
-}
-
-void
-arraysort(Array *array, int (*cmp)(const void*, const void*))
-{
- qsort(array->data, array->length, array->size, cmp);
-}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
deleted file mode 100755
index fa74c67c3b..0000000000
--- a/src/cmd/gc/bisonerrors
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/usr/bin/awk -f
-# Copyright 2010 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 program implements the core idea from
-#
-# Clinton L. Jeffery, Generating LR syntax error messages from examples,
-# ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566
-#
-# It reads Bison's summary of a grammar followed by a file
-# like go.errors, replacing lines beginning with % by the
-# yystate and yychar that will be active when an error happens
-# while parsing that line.
-#
-# Unlike the system described in the paper, the lines in go.errors
-# give grammar symbol name lists, not actual program fragments.
-# This is a little less programmer-friendly but doesn't require being
-# able to run the text through lex.c.
-
-BEGIN{
- bison = 1
- grammar = 0
- states = 0
- open = 0
-}
-
-# In Grammar section of y.output,
-# record lhs and length of rhs for each rule.
-bison && /^Grammar/ { grammar = 1 }
-bison && /^(Terminals|state 0)/ { grammar = 0 }
-grammar && NF>0 {
- if($2 != "|") {
- r = $2
- sub(/:$/, "", r)
- }
- rulelhs[$1] = r
- rulesize[$1] = NF-2
- if(rulesize[$1] == 1 && $3 == "%empty") {
- rulesize[$1] = 0
- }
- if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
- rulesize[$1] = 0
- }
-}
-
-# In state dumps, record shift/reduce actions.
-bison && /^[Ss]tate 0/ { grammar = 0; states = 1 }
-
-states && /^[Ss]tate / { state = $2 }
-states { statetext[state] = statetext[state] $0 "\n" }
-
-states && / shift/ {
- n = nshift[state]++
- if($0 ~ /and go to/)
- shift[state,n] = $7 # GNU Bison
- else
- shift[state,n] = $3 # Plan 9 Yacc
- shifttoken[state,n] = $1
- next
-}
-states && / (go to|goto)/ {
- n = nshift[state]++
- if($0 ~ /go to/)
- shift[state,n] = $5 # GNU Bison
- else
- shift[state,n] = $3 # Plan 9 Yacc
- shifttoken[state,n] = $1
- next
-}
-states && / reduce/ {
- n = nreduce[state]++
- if($0 ~ /reduce using rule/)
- reduce[state,n] = $5 # GNU Bison
- else
- reduce[state,n] = $3 # Plan 9 yacc
- reducetoken[state,n] = $1
- next
-}
-
-# Skip over the summary information printed by Plan 9 yacc.
-/nonterminals$/,/^maximum spread/ { next }
-
-# First // comment marks the beginning of the pattern file.
-/^\/\// { bison = 0; grammar = 0; state = 0 }
-bison { next }
-
-# Treat % as first field on line as introducing a pattern (token sequence).
-# Run it through the LR machine and print the induced "yystate, yychar,"
-# at the point where the error happens.
-$1 == "%" {
- nstack = 0
- state = 0
- f = 2
- tok = ""
- for(;;) {
- if(tok == "" && f <= NF) {
- tok = $f
- f++
- }
- found = 0
- for(j=0; j<nshift[state]; j++) {
- if(shifttoken[state,j] == tok) {
- # print "SHIFT " tok " " state " -> " shift[state,j]
- stack[nstack++] = state
- state = shift[state,j]
- found = 1
- tok = ""
- break
- }
- }
- if(found)
- continue
- for(j=0; j<nreduce[state]; j++) {
- t = reducetoken[state,j]
- if(t == tok || t == "$default" || t == ".") {
- stack[nstack++] = state
- rule = reduce[state,j]
- nstack -= rulesize[rule]
- state = stack[--nstack]
- lhs = rulelhs[rule]
- if(tok != "")
- --f
- tok = rulelhs[rule]
- # print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
- found = 1
- break
- }
- }
- if(found)
- continue
-
- # No shift or reduce applied - found the error.
- printf("\t{%s, %s,\n", state, tok);
- open = 1;
- break
- }
- next
-}
-
-# Print other lines verbatim.
-open && /,$/ {
- s = $0;
- sub(",", "},", s)
- print s
- open = 0
- next
-}
-
-open && /"$/ {
- print $0 "}"
- open = 0
- next
-}
-
-{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
deleted file mode 100644
index 21e25dd1c9..0000000000
--- a/src/cmd/gc/bits.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno utils/cc/bits.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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 "go.h"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] | b.b[i];
- return c;
-}
-
-Bits
-band(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] & b.b[i];
- return c;
-}
-
-Bits
-bnot(Bits a)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = ~a.b[i];
- return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a->b[i])
- return 1;
- return 0;
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a.b[i] != b.b[i])
- return 0;
- return 1;
-}
-*/
-
-int
-bnum(Bits a)
-{
- int i;
- uint64 b;
-
- for(i=0; i<BITS; i++){
- b = a.b[i];
- if(b)
- return 64*i + bitno(b);
- }
- fatal("bad in bnum");
- return 0;
-}
-
-Bits
-blsh(uint n)
-{
- Bits c;
-
- c = zbits;
- c.b[n/64] = 1LL << (n%64);
- return c;
-}
-
-int
-btest(Bits *a, uint n)
-{
- return (a->b[n/64] & (1LL << (n%64))) != 0;
-}
-
-void
-biset(Bits *a, uint n)
-{
- a->b[n/64] |= 1LL << (n%64);
-}
-
-void
-biclr(Bits *a, uint n)
-{
- a->b[n/64] &= ~(1LL << (n%64));
-}
-
-int
-bitno(uint64 b)
-{
- int i;
-
- for(i=0; i<64; i++)
- if(b & (1LL<<i))
- return i;
- fatal("bad in bitno");
- return 0;
-}
-
-int
-Qconv(Fmt *fp)
-{
- Bits bits;
- int i, first;
-
- first = 1;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(first)
- first = 0;
- else
- fmtprint(fp, " ");
- if(var[i].node == N || var[i].node->sym == S)
- fmtprint(fp, "$%d", i);
- else {
- fmtprint(fp, "%s(%d)", var[i].node->sym->name, i);
- if(var[i].offset != 0)
- fmtprint(fp, "%+lld", (vlong)var[i].offset);
- }
- biclr(&bits, i);
- }
- return 0;
-}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
deleted file mode 100644
index 1178f622e5..0000000000
--- a/src/cmd/gc/builtin.c
+++ /dev/null
@@ -1,165 +0,0 @@
-// AUTO-GENERATED by mkbuiltin; DO NOT EDIT
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-char *runtimeimport =
- "package runtime\n"
- "import runtime \"runtime\"\n"
- "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n"
- "func @\"\".panicindex ()\n"
- "func @\"\".panicslice ()\n"
- "func @\"\".panicdivide ()\n"
- "func @\"\".throwreturn ()\n"
- "func @\"\".throwinit ()\n"
- "func @\"\".panicwrap (? string, ? string, ? string)\n"
- "func @\"\".gopanic (? interface {})\n"
- "func @\"\".gorecover (? *int32) (? interface {})\n"
- "func @\"\".printbool (? bool)\n"
- "func @\"\".printfloat (? float64)\n"
- "func @\"\".printint (? int64)\n"
- "func @\"\".printhex (? uint64)\n"
- "func @\"\".printuint (? uint64)\n"
- "func @\"\".printcomplex (? complex128)\n"
- "func @\"\".printstring (? string)\n"
- "func @\"\".printpointer (? any)\n"
- "func @\"\".printiface (? any)\n"
- "func @\"\".printeface (? any)\n"
- "func @\"\".printslice (? any)\n"
- "func @\"\".printnl ()\n"
- "func @\"\".printsp ()\n"
- "func @\"\".printlock ()\n"
- "func @\"\".printunlock ()\n"
- "func @\"\".concatstring2 (? *[32]byte, ? string, ? string) (? string)\n"
- "func @\"\".concatstring3 (? *[32]byte, ? string, ? string, ? string) (? string)\n"
- "func @\"\".concatstring4 (? *[32]byte, ? string, ? string, ? string, ? string) (? string)\n"
- "func @\"\".concatstring5 (? *[32]byte, ? string, ? string, ? string, ? string, ? string) (? string)\n"
- "func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n"
- "func @\"\".cmpstring (? string, ? string) (? int)\n"
- "func @\"\".eqstring (? string, ? string) (? bool)\n"
- "func @\"\".intstring (? *[4]byte, ? int64) (? string)\n"
- "func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n"
- "func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
- "func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n"
- "func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n"
- "func @\"\".stringtoslicebytetmp (? string) (? []byte)\n"
- "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n"
- "func @\"\".stringiter (? string, ? int) (? int)\n"
- "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
- "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n"
- "func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n"
- "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n"
- "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n"
- "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n"
- "func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertE2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".assertE2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertE2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".assertI2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertI2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".assertI2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertI2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".assertI2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
- "func @\"\".assertI2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
- "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
- "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
- "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
- "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
- "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n"
- "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n"
- "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n"
- "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n"
- "func @\"\".mapiternext (@\"\".hiter·1 *any)\n"
- "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n"
- "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n"
- "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n"
- "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
- "func @\"\".closechan (@\"\".hchan·1 any)\n"
- "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
- "func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n"
- "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
- "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
- "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"
- "func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n"
- "func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
- "func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
- "func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n"
- "func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n"
- "func @\"\".selectgo (@\"\".sel·1 *byte)\n"
- "func @\"\".block ()\n"
- "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
- "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
- "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
- "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n"
- "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
- "func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
- "func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
- "func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
- "func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
- "func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
- "func @\"\".int64div (? int64, ? int64) (? int64)\n"
- "func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
- "func @\"\".int64mod (? int64, ? int64) (? int64)\n"
- "func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n"
- "func @\"\".float64toint64 (? float64) (? int64)\n"
- "func @\"\".float64touint64 (? float64) (? uint64)\n"
- "func @\"\".int64tofloat64 (? int64) (? float64)\n"
- "func @\"\".uint64tofloat64 (? uint64) (? float64)\n"
- "func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n"
- "func @\"\".racefuncenter (? uintptr)\n"
- "func @\"\".racefuncexit ()\n"
- "func @\"\".raceread (? uintptr)\n"
- "func @\"\".racewrite (? uintptr)\n"
- "func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
- "func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
- "\n"
- "$$\n";
-char *unsafeimport =
- "package unsafe\n"
- "import runtime \"runtime\"\n"
- "type @\"\".Pointer uintptr\n"
- "func @\"\".Offsetof (? any) (? uintptr)\n"
- "func @\"\".Sizeof (? any) (? uintptr)\n"
- "func @\"\".Alignof (? any) (? uintptr)\n"
- "\n"
- "$$\n";
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
deleted file mode 100644
index 2428006c8a..0000000000
--- a/src/cmd/gc/bv.c
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum {
- WORDSIZE = 4,
- WORDBITS = 32,
- WORDMASK = WORDBITS - 1,
- WORDSHIFT = 5,
-};
-
-static uintptr
-bvsize(uintptr n)
-{
- return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
-}
-
-int32
-bvbits(Bvec *bv)
-{
- return bv->n;
-}
-
-int32
-bvwords(Bvec *bv)
-{
- return (bv->n + WORDBITS - 1) / WORDBITS;
-}
-
-Bvec*
-bvalloc(int32 n)
-{
- Bvec *bv;
- uintptr nbytes;
-
- if(n < 0)
- fatal("bvalloc: initial size is negative\n");
- nbytes = sizeof(Bvec) + bvsize(n);
- bv = malloc(nbytes);
- if(bv == nil)
- fatal("bvalloc: malloc failed\n");
- memset(bv, 0, nbytes);
- bv->n = n;
- return bv;
-}
-
-/* difference */
-void
-bvandnot(Bvec *dst, Bvec *src1, Bvec *src2)
-{
- int32 i, w;
-
- if(dst->n != src1->n || dst->n != src2->n)
- fatal("bvand: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
- for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
- dst->b[w] = src1->b[w] & ~src2->b[w];
-}
-
-int
-bvcmp(Bvec *bv1, Bvec *bv2)
-{
- uintptr nbytes;
-
- if(bv1->n != bv2->n)
- fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n);
- nbytes = bvsize(bv1->n);
- return memcmp(bv1->b, bv2->b, nbytes);
-}
-
-void
-bvcopy(Bvec *dst, Bvec *src)
-{
- memmove(dst->b, src->b, bvsize(dst->n));
-}
-
-Bvec*
-bvconcat(Bvec *src1, Bvec *src2)
-{
- Bvec *dst;
- int32 i;
-
- dst = bvalloc(src1->n + src2->n);
- for(i = 0; i < src1->n; i++)
- if(bvget(src1, i))
- bvset(dst, i);
- for(i = 0; i < src2->n; i++)
- if(bvget(src2, i))
- bvset(dst, i + src1->n);
- return dst;
-}
-
-int
-bvget(Bvec *bv, int32 i)
-{
- if(i < 0 || i >= bv->n)
- fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n);
- return (bv->b[i>>WORDSHIFT] >> (i&WORDMASK)) & 1;
-}
-
-// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
-// If there is no such index, bvnext returns -1.
-int
-bvnext(Bvec *bv, int32 i)
-{
- uint32 w;
-
- if(i >= bv->n)
- return -1;
-
- // Jump i ahead to next word with bits.
- if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) {
- i &= ~WORDMASK;
- i += WORDBITS;
- while(i < bv->n && bv->b[i>>WORDSHIFT] == 0)
- i += WORDBITS;
- }
- if(i >= bv->n)
- return -1;
-
- // Find 1 bit.
- w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK);
- while((w&1) == 0) {
- w>>=1;
- i++;
- }
- return i;
-}
-
-int
-bvisempty(Bvec *bv)
-{
- int32 i;
-
- for(i = 0; i < bv->n; i += WORDBITS)
- if(bv->b[i>>WORDSHIFT] != 0)
- return 0;
- return 1;
-}
-
-void
-bvnot(Bvec *bv)
-{
- int32 i, w;
-
- for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++)
- bv->b[w] = ~bv->b[w];
-}
-
-/* union */
-void
-bvor(Bvec *dst, Bvec *src1, Bvec *src2)
-{
- int32 i, w;
-
- if(dst->n != src1->n || dst->n != src2->n)
- fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
- for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
- dst->b[w] = src1->b[w] | src2->b[w];
-}
-
-/* intersection */
-void
-bvand(Bvec *dst, Bvec *src1, Bvec *src2)
-{
- int32 i, w;
-
- if(dst->n != src1->n || dst->n != src2->n)
- fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
- for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
- dst->b[w] = src1->b[w] & src2->b[w];
-}
-
-void
-bvprint(Bvec *bv)
-{
- int32 i;
-
- print("#*");
- for(i = 0; i < bv->n; i++)
- print("%d", bvget(bv, i));
-}
-
-void
-bvreset(Bvec *bv, int32 i)
-{
- uint32 mask;
-
- if(i < 0 || i >= bv->n)
- fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n);
- mask = ~(1 << (i % WORDBITS));
- bv->b[i / WORDBITS] &= mask;
-}
-
-void
-bvresetall(Bvec *bv)
-{
- memset(bv->b, 0x00, bvsize(bv->n));
-}
-
-void
-bvset(Bvec *bv, int32 i)
-{
- uint32 mask;
-
- if(i < 0 || i >= bv->n)
- fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
- mask = 1U << (i % WORDBITS);
- bv->b[i / WORDBITS] |= mask;
-}
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
deleted file mode 100644
index 35b6d4b1b4..0000000000
--- a/src/cmd/gc/closure.c
+++ /dev/null
@@ -1,659 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * function literals aka closures
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-void
-closurehdr(Node *ntype)
-{
- Node *n, *name, *a;
- NodeList *l;
-
- n = nod(OCLOSURE, N, N);
- n->ntype = ntype;
- n->funcdepth = funcdepth;
- n->outerfunc = curfn;
-
- funchdr(n);
-
- // steal ntype's argument names and
- // leave a fresh copy in their place.
- // references to these variables need to
- // refer to the variables in the external
- // function declared below; see walkclosure.
- n->list = ntype->list;
- n->rlist = ntype->rlist;
- ntype->list = nil;
- ntype->rlist = nil;
- for(l=n->list; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- a = nod(ODCLFIELD, name, l->n->right);
- a->isddd = l->n->isddd;
- if(name)
- name->isddd = a->isddd;
- ntype->list = list(ntype->list, a);
- }
- for(l=n->rlist; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
- }
-}
-
-Node*
-closurebody(NodeList *body)
-{
- Node *func, *v;
- NodeList *l;
-
- if(body == nil)
- body = list1(nod(OEMPTY, N, N));
-
- func = curfn;
- func->nbody = body;
- func->endlineno = lineno;
- funcbody(func);
-
- // closure-specific variables are hanging off the
- // ordinary ones in the symbol table; see oldname.
- // unhook them.
- // make the list of pointers for the closure call.
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- v->closure->closure = v->outer;
- v->outerexpr = oldname(v->sym);
- }
-
- return func;
-}
-
-static Node* makeclosure(Node *func);
-
-void
-typecheckclosure(Node *func, int top)
-{
- Node *oldfn, *n;
- NodeList *l;
- int olddd;
-
- for(l=func->cvars; l; l=l->next) {
- n = l->n->closure;
- if(!n->captured) {
- n->captured = 1;
- if(n->decldepth == 0)
- fatal("typecheckclosure: var %hN does not have decldepth assigned", n);
- // Ignore assignments to the variable in straightline code
- // preceding the first capturing by a closure.
- if(n->decldepth == decldepth)
- n->assigned = 0;
- }
- }
-
- for(l=func->dcl; l; l=l->next)
- if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT))
- l->n->decldepth = 1;
-
- oldfn = curfn;
- typecheck(&func->ntype, Etype);
- func->type = func->ntype->type;
- func->top = top;
-
- // Type check the body now, but only if we're inside a function.
- // At top level (in a variable initialization: curfn==nil) we're not
- // ready to type check code yet; we'll check it later, because the
- // underlying closure function we create is added to xtop.
- if(curfn && func->type != T) {
- curfn = func;
- olddd = decldepth;
- decldepth = 1;
- typechecklist(func->nbody, Etop);
- decldepth = olddd;
- curfn = oldfn;
- }
-
- // Create top-level function
- xtop = list(xtop, makeclosure(func));
-}
-
-// closurename returns name for OCLOSURE n.
-// It is not as simple as it ought to be, because we typecheck nested closures
-// starting from the innermost one. So when we check the inner closure,
-// we don't yet have name for the outer closure. This function uses recursion
-// to generate names all the way up if necessary.
-static Sym*
-closurename(Node *n)
-{
- static int closgen;
- char *outer, *prefix;
- int gen;
-
- if(n->sym != S)
- return n->sym;
- gen = 0;
- outer = nil;
- prefix = nil;
- if(n->outerfunc == N) {
- // Global closure.
- outer = "glob";
- prefix = "func";
- gen = ++closgen;
- } else if(n->outerfunc->op == ODCLFUNC) {
- // The outermost closure inside of a named function.
- outer = n->outerfunc->nname->sym->name;
- prefix = "func";
- // Yes, functions can be named _.
- // Can't use function closgen in such case,
- // because it would lead to name clashes.
- if(!isblank(n->outerfunc->nname))
- gen = ++n->outerfunc->closgen;
- else
- gen = ++closgen;
- } else if(n->outerfunc->op == OCLOSURE) {
- // Nested closure, recurse.
- outer = closurename(n->outerfunc)->name;
- prefix = "";
- gen = ++n->outerfunc->closgen;
- } else
- fatal("closurename called for %hN", n);
- snprint(namebuf, sizeof namebuf, "%s.%s%d", outer, prefix, gen);
- n->sym = lookup(namebuf);
- return n->sym;
-}
-
-static Node*
-makeclosure(Node *func)
-{
- Node *xtype, *xfunc;
-
- /*
- * wrap body in external function
- * that begins by reading closure parameters.
- */
- xtype = nod(OTFUNC, N, N);
- xtype->list = func->list;
- xtype->rlist = func->rlist;
-
- // create the function
- xfunc = nod(ODCLFUNC, N, N);
- xfunc->nname = newname(closurename(func));
- xfunc->nname->sym->flags |= SymExported; // disable export
- xfunc->nname->ntype = xtype;
- xfunc->nname->defn = xfunc;
- declare(xfunc->nname, PFUNC);
- xfunc->nname->funcdepth = func->funcdepth;
- xfunc->funcdepth = func->funcdepth;
- xfunc->endlineno = func->endlineno;
-
- xfunc->nbody = func->nbody;
- xfunc->dcl = concat(func->dcl, xfunc->dcl);
- if(xfunc->nbody == nil)
- fatal("empty body - won't generate any code");
- typecheck(&xfunc, Etop);
-
- xfunc->closure = func;
- func->closure = xfunc;
-
- func->nbody = nil;
- func->list = nil;
- func->rlist = nil;
-
- return xfunc;
-}
-
-// capturevars is called in a separate phase after all typechecking is done.
-// It decides whether each variable captured by a closure should be captured
-// by value or by reference.
-// We use value capturing for values <= 128 bytes that are never reassigned
-// after capturing (effectively constant).
-void
-capturevars(Node *xfunc)
-{
- Node *func, *v, *outer;
- NodeList *l;
- int lno;
-
- lno = lineno;
- lineno = xfunc->lineno;
-
- func = xfunc->closure;
- func->enter = nil;
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->type == T) {
- // if v->type is nil, it means v looked like it was
- // going to be used in the closure but wasn't.
- // this happens because when parsing a, b, c := f()
- // the a, b, c gets parsed as references to older
- // a, b, c before the parser figures out this is a
- // declaration.
- v->op = OXXX;
- continue;
- }
-
- // type check the & of closed variables outside the closure,
- // so that the outer frame also grabs them and knows they escape.
- dowidth(v->type);
- outer = v->outerexpr;
- v->outerexpr = N;
- // out parameters will be assigned to implicitly upon return.
- if(outer->class != PPARAMOUT && !v->closure->addrtaken && !v->closure->assigned && v->type->width <= 128)
- v->byval = 1;
- else {
- v->closure->addrtaken = 1;
- outer = nod(OADDR, outer, N);
- }
- if(debug['m'] > 1) {
- Sym *name;
- char *how;
- name = nil;
- if(v->curfn && v->curfn->nname)
- name = v->curfn->nname->sym;
- how = "ref";
- if(v->byval)
- how = "value";
- warnl(v->lineno, "%S capturing by %s: %S (addr=%d assign=%d width=%d)",
- name, how,
- v->sym, v->closure->addrtaken, v->closure->assigned, (int32)v->type->width);
- }
- typecheck(&outer, Erv);
- func->enter = list(func->enter, outer);
- }
-
- lineno = lno;
-}
-
-// transformclosure is called in a separate phase after escape analysis.
-// It transform closure bodies to properly reference captured variables.
-void
-transformclosure(Node *xfunc)
-{
- Node *func, *cv, *addr, *v, *f;
- NodeList *l, *body;
- Type **param, *fld;
- vlong offset;
- int lno, nvar;
-
- lno = lineno;
- lineno = xfunc->lineno;
- func = xfunc->closure;
-
- if(func->top&Ecall) {
- // If the closure is directly called, we transform it to a plain function call
- // with variables passed as args. This avoids allocation of a closure object.
- // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
- // will complete the transformation later.
- // For illustration, the following closure:
- // func(a int) {
- // println(byval)
- // byref++
- // }(42)
- // becomes:
- // func(a int, byval int, &byref *int) {
- // println(byval)
- // (*&byref)++
- // }(42, byval, &byref)
-
- // f is ONAME of the actual function.
- f = xfunc->nname;
- // Get pointer to input arguments and rewind to the end.
- // We are going to append captured variables to input args.
- param = &getinargx(f->type)->type;
- for(; *param; param = &(*param)->down) {
- }
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->op == OXXX)
- continue;
- fld = typ(TFIELD);
- fld->funarg = 1;
- if(v->byval) {
- // If v is captured by value, we merely downgrade it to PPARAM.
- v->class = PPARAM;
- v->ullman = 1;
- fld->nname = v;
- } else {
- // If v of type T is captured by reference,
- // we introduce function param &v *T
- // and v remains PPARAMREF with &v heapaddr
- // (accesses will implicitly deref &v).
- snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
- addr = newname(lookup(namebuf));
- addr->type = ptrto(v->type);
- addr->class = PPARAM;
- v->heapaddr = addr;
- fld->nname = addr;
- }
- fld->type = fld->nname->type;
- fld->sym = fld->nname->sym;
- // Declare the new param and append it to input arguments.
- xfunc->dcl = list(xfunc->dcl, fld->nname);
- *param = fld;
- param = &fld->down;
- }
- // Recalculate param offsets.
- if(f->type->width > 0)
- fatal("transformclosure: width is already calculated");
- dowidth(f->type);
- xfunc->type = f->type; // update type of ODCLFUNC
- } else {
- // The closure is not called, so it is going to stay as closure.
- nvar = 0;
- body = nil;
- offset = widthptr;
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->op == OXXX)
- continue;
- nvar++;
- // cv refers to the field inside of closure OSTRUCTLIT.
- cv = nod(OCLOSUREVAR, N, N);
- cv->type = v->type;
- if(!v->byval)
- cv->type = ptrto(v->type);
- offset = rnd(offset, cv->type->align);
- cv->xoffset = offset;
- offset += cv->type->width;
-
- if(v->byval && v->type->width <= 2*widthptr && thearch.thechar == '6') {
- // If it is a small variable captured by value, downgrade it to PAUTO.
- // This optimization is currently enabled only for amd64, see:
- // https://github.com/golang/go/issues/9865
- v->class = PAUTO;
- v->ullman = 1;
- xfunc->dcl = list(xfunc->dcl, v);
- body = list(body, nod(OAS, v, cv));
- } else {
- // Declare variable holding addresses taken from closure
- // and initialize in entry prologue.
- snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
- addr = newname(lookup(namebuf));
- addr->ntype = nod(OIND, typenod(v->type), N);
- addr->class = PAUTO;
- addr->used = 1;
- addr->curfn = xfunc;
- xfunc->dcl = list(xfunc->dcl, addr);
- v->heapaddr = addr;
- if(v->byval)
- cv = nod(OADDR, cv, N);
- body = list(body, nod(OAS, addr, cv));
- }
- }
- typechecklist(body, Etop);
- walkstmtlist(body);
- xfunc->enter = body;
- xfunc->needctxt = nvar > 0;
- }
-
- lineno = lno;
-}
-
-Node*
-walkclosure(Node *func, NodeList **init)
-{
- Node *clos, *typ, *typ1, *v;
- NodeList *l;
-
- // If no closure vars, don't bother wrapping.
- if(func->cvars == nil)
- return func->closure->nname;
-
- // Create closure in the form of a composite literal.
- // supposing the closure captures an int i and a string s
- // and has one float64 argument and no results,
- // the generated code looks like:
- //
- // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
- //
- // The use of the struct provides type information to the garbage
- // collector so that it can walk the closure. We could use (in this case)
- // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
- // The information appears in the binary in the form of type descriptors;
- // the struct is unnamed so that closures in multiple packages with the
- // same struct type can share the descriptor.
-
- typ = nod(OTSTRUCT, N, N);
- typ->list = list1(nod(ODCLFIELD, newname(lookup(".F")), typenod(types[TUINTPTR])));
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->op == OXXX)
- continue;
- typ1 = typenod(v->type);
- if(!v->byval)
- typ1 = nod(OIND, typ1, N);
- typ->list = list(typ->list, nod(ODCLFIELD, newname(v->sym), typ1));
- }
-
- clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
- clos->esc = func->esc;
- clos->right->implicit = 1;
- clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter);
-
- // Force type conversion from *struct to the func type.
- clos = nod(OCONVNOP, clos, N);
- clos->type = func->type;
-
- typecheck(&clos, Erv);
- // typecheck will insert a PTRLIT node under CONVNOP,
- // tag it with escape analysis result.
- clos->left->esc = func->esc;
- // non-escaping temp to use, if any.
- // orderexpr did not compute the type; fill it in now.
- if(func->alloc != N) {
- func->alloc->type = clos->left->left->type;
- func->alloc->orig->type = func->alloc->type;
- clos->left->right = func->alloc;
- func->alloc = N;
- }
- walkexpr(&clos, init);
-
- return clos;
-}
-
-static Node *makepartialcall(Node*, Type*, Node*);
-
-void
-typecheckpartialcall(Node *fn, Node *sym)
-{
- switch(fn->op) {
- case ODOTINTER:
- case ODOTMETH:
- break;
- default:
- fatal("invalid typecheckpartialcall");
- }
-
- // Create top-level function.
- fn->nname = makepartialcall(fn, fn->type, sym);
- fn->right = sym;
- fn->op = OCALLPART;
- fn->type = fn->nname->type;
-}
-
-static Node*
-makepartialcall(Node *fn, Type *t0, Node *meth)
-{
- Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn;
- Type *rcvrtype, *basetype, *t;
- NodeList *body, *l, *callargs, *retargs;
- char *p;
- Sym *sym;
- Pkg *spkg;
- static Pkg* gopkg;
- int i, ddd;
-
- rcvrtype = fn->left->type;
- if(exportname(meth->sym->name))
- p = smprint("(%-hT).%s-fm", rcvrtype, meth->sym->name);
- else
- p = smprint("(%-hT).(%-S)-fm", rcvrtype, meth->sym);
- basetype = rcvrtype;
- if(isptr[rcvrtype->etype])
- basetype = basetype->type;
- if(basetype->etype != TINTER && basetype->sym == S)
- fatal("missing base type for %T", rcvrtype);
-
- spkg = nil;
- if(basetype->sym != S)
- spkg = basetype->sym->pkg;
- if(spkg == nil) {
- if(gopkg == nil)
- gopkg = mkpkg(newstrlit("go"));
- spkg = gopkg;
- }
- sym = pkglookup(p, spkg);
- free(p);
- if(sym->flags & SymUniq)
- return sym->def;
- sym->flags |= SymUniq;
-
- savecurfn = curfn;
- curfn = N;
-
- xtype = nod(OTFUNC, N, N);
- i = 0;
- l = nil;
- callargs = nil;
- ddd = 0;
- xfunc = nod(ODCLFUNC, N, N);
- curfn = xfunc;
- for(t = getinargx(t0)->type; t; t = t->down) {
- snprint(namebuf, sizeof namebuf, "a%d", i++);
- n = newname(lookup(namebuf));
- n->class = PPARAM;
- xfunc->dcl = list(xfunc->dcl, n);
- callargs = list(callargs, n);
- fld = nod(ODCLFIELD, n, typenod(t->type));
- if(t->isddd) {
- fld->isddd = 1;
- ddd = 1;
- }
- l = list(l, fld);
- }
- xtype->list = l;
- i = 0;
- l = nil;
- retargs = nil;
- for(t = getoutargx(t0)->type; t; t = t->down) {
- snprint(namebuf, sizeof namebuf, "r%d", i++);
- n = newname(lookup(namebuf));
- n->class = PPARAMOUT;
- xfunc->dcl = list(xfunc->dcl, n);
- retargs = list(retargs, n);
- l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
- }
- xtype->rlist = l;
-
- xfunc->dupok = 1;
- xfunc->nname = newname(sym);
- xfunc->nname->sym->flags |= SymExported; // disable export
- xfunc->nname->ntype = xtype;
- xfunc->nname->defn = xfunc;
- declare(xfunc->nname, PFUNC);
-
- // Declare and initialize variable holding receiver.
- body = nil;
- xfunc->needctxt = 1;
- cv = nod(OCLOSUREVAR, N, N);
- cv->xoffset = widthptr;
- cv->type = rcvrtype;
- if(cv->type->align > widthptr)
- cv->xoffset = cv->type->align;
- ptr = nod(ONAME, N, N);
- ptr->sym = lookup("rcvr");
- ptr->class = PAUTO;
- ptr->addable = 1;
- ptr->ullman = 1;
- ptr->used = 1;
- ptr->curfn = xfunc;
- xfunc->dcl = list(xfunc->dcl, ptr);
- if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
- ptr->ntype = typenod(rcvrtype);
- body = list(body, nod(OAS, ptr, cv));
- } else {
- ptr->ntype = typenod(ptrto(rcvrtype));
- body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
- }
-
- call = nod(OCALL, nod(OXDOT, ptr, meth), N);
- call->list = callargs;
- call->isddd = ddd;
- if(t0->outtuple == 0) {
- body = list(body, call);
- } else {
- n = nod(OAS2, N, N);
- n->list = retargs;
- n->rlist = list1(call);
- body = list(body, n);
- n = nod(ORETURN, N, N);
- body = list(body, n);
- }
-
- xfunc->nbody = body;
-
- typecheck(&xfunc, Etop);
- sym->def = xfunc;
- xtop = list(xtop, xfunc);
- curfn = savecurfn;
-
- return xfunc;
-}
-
-Node*
-walkpartialcall(Node *n, NodeList **init)
-{
- Node *clos, *typ;
-
- // Create closure in the form of a composite literal.
- // For x.M with receiver (x) type T, the generated code looks like:
- //
- // clos = &struct{F uintptr; R T}{M.T·f, x}
- //
- // Like walkclosure above.
-
- if(isinter(n->left->type)) {
- // Trigger panic for method on nil interface now.
- // Otherwise it happens in the wrapper and is confusing.
- n->left = cheapexpr(n->left, init);
- checknil(n->left, init);
- }
-
- typ = nod(OTSTRUCT, N, N);
- typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
- typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
-
- clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
- clos->esc = n->esc;
- clos->right->implicit = 1;
- clos->list = list1(nod(OCFUNC, n->nname->nname, N));
- clos->list = list(clos->list, n->left);
-
- // Force type conversion from *struct to the func type.
- clos = nod(OCONVNOP, clos, N);
- clos->type = n->type;
-
- typecheck(&clos, Erv);
- // typecheck will insert a PTRLIT node under CONVNOP,
- // tag it with escape analysis result.
- clos->left->esc = n->esc;
- // non-escaping temp to use, if any.
- // orderexpr did not compute the type; fill it in now.
- if(n->alloc != N) {
- n->alloc->type = clos->left->left->type;
- n->alloc->orig->type = n->alloc->type;
- clos->left->right = n->alloc;
- n->alloc = N;
- }
- walkexpr(&clos, init);
-
- return clos;
-}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
deleted file mode 100644
index 50accb93a3..0000000000
--- a/src/cmd/gc/const.c
+++ /dev/null
@@ -1,1678 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#define TUP(x,y) (((x)<<16)|(y))
-/*c2go int TUP(int, int); */
-
-static Val tocplx(Val);
-static Val toflt(Val);
-static Val tostr(Val);
-static Val copyval(Val);
-static void cmplxmpy(Mpcplx*, Mpcplx*);
-static void cmplxdiv(Mpcplx*, Mpcplx*);
-
-/*
- * truncate float literal fv to 32-bit or 64-bit precision
- * according to type; return truncated value.
- */
-Mpflt*
-truncfltlit(Mpflt *oldv, Type *t)
-{
- double d;
- Mpflt *fv;
- Val v;
-
- if(t == T)
- return oldv;
-
- memset(&v, 0, sizeof v);
- v.ctype = CTFLT;
- v.u.fval = oldv;
- overflow(v, t);
-
- fv = mal(sizeof *fv);
- *fv = *oldv;
-
- // convert large precision literal floating
- // into limited precision (float64 or float32)
- switch(t->etype) {
- case TFLOAT64:
- d = mpgetflt(fv);
- mpmovecflt(fv, d);
- break;
-
- case TFLOAT32:
- d = mpgetflt32(fv);
- mpmovecflt(fv, d);
-
- break;
- }
- return fv;
-}
-
-/*
- * convert n, if literal, to type t.
- * implicit conversion.
- */
-void
-convlit(Node **np, Type *t)
-{
- convlit1(np, t, 0);
-}
-
-/*
- * convert n, if literal, to type t.
- * return a new node if necessary
- * (if n is a named constant, can't edit n->type directly).
- */
-void
-convlit1(Node **np, Type *t, int explicit)
-{
- int ct, et;
- Node *n, *nn;
-
- n = *np;
- if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
- return;
- if(!explicit && !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- switch(n->op) {
- default:
- if(n->type == idealbool) {
- if(t->etype == TBOOL)
- n->type = t;
- else
- n->type = types[TBOOL];
- }
- if(n->type->etype == TIDEAL) {
- convlit(&n->left, t);
- convlit(&n->right, t);
- n->type = t;
- }
- return;
- case OLITERAL:
- // target is invalid type for a constant? leave alone.
- if(!okforconst[t->etype] && n->type->etype != TNIL) {
- defaultlit(&n, T);
- *np = n;
- return;
- }
- break;
- case OLSH:
- case ORSH:
- convlit1(&n->left, t, explicit && isideal(n->left->type));
- t = n->left->type;
- if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
- n->val = toint(n->val);
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- case OCOMPLEX:
- if(n->type->etype == TIDEAL) {
- switch(t->etype) {
- default:
- // If trying to convert to non-complex type,
- // leave as complex128 and let typechecker complain.
- t = types[TCOMPLEX128];
- //fallthrough
- case TCOMPLEX128:
- n->type = t;
- convlit(&n->left, types[TFLOAT64]);
- convlit(&n->right, types[TFLOAT64]);
- break;
- case TCOMPLEX64:
- n->type = t;
- convlit(&n->left, types[TFLOAT32]);
- convlit(&n->right, types[TFLOAT32]);
- break;
- }
- }
- return;
- }
-
- // avoided repeated calculations, errors
- if(eqtype(n->type, t))
- return;
-
- ct = consttype(n);
- if(ct < 0)
- goto bad;
-
- et = t->etype;
- if(et == TINTER) {
- if(ct == CTNIL && n->type == types[TNIL]) {
- n->type = t;
- return;
- }
- defaultlit(np, T);
- return;
- }
-
- switch(ct) {
- default:
- goto bad;
-
- case CTNIL:
- switch(et) {
- default:
- n->type = T;
- goto bad;
-
- case TSTRING:
- // let normal conversion code handle it
- return;
-
- case TARRAY:
- if(!isslice(t))
- goto bad;
- break;
-
- case TPTR32:
- case TPTR64:
- case TINTER:
- case TMAP:
- case TCHAN:
- case TFUNC:
- case TUNSAFEPTR:
- break;
-
- case TUINTPTR:
- // A nil literal may be converted to uintptr
- // if it is an unsafe.Pointer
- if(n->type->etype == TUNSAFEPTR) {
- n->val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(n->val.u.xval, 0);
- n->val.ctype = CTINT;
- } else
- goto bad;
- }
- break;
-
- case CTSTR:
- case CTBOOL:
- if(et != n->type->etype)
- goto bad;
- break;
-
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- ct = n->val.ctype;
- if(isint[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTFLT:
- case CTRUNE:
- n->val = toint(n->val);
- // flowthrough
- case CTINT:
- overflow(n->val, t);
- break;
- }
- } else
- if(isfloat[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTINT:
- case CTRUNE:
- n->val = toflt(n->val);
- // flowthrough
- case CTFLT:
- n->val.u.fval = truncfltlit(n->val.u.fval, t);
- break;
- }
- } else
- if(iscomplex[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTFLT:
- case CTINT:
- case CTRUNE:
- n->val = tocplx(n->val);
- break;
- case CTCPLX:
- overflow(n->val, t);
- break;
- }
- } else
- if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
- n->val = tostr(n->val);
- else
- goto bad;
- break;
- }
- n->type = t;
- return;
-
-bad:
- if(!n->diag) {
- if(!t->broke)
- yyerror("cannot convert %N to type %T", n, t);
- n->diag = 1;
- }
- if(isideal(n->type)) {
- defaultlit(&n, T);
- *np = n;
- }
- return;
-}
-
-static Val
-copyval(Val v)
-{
- Mpint *i;
- Mpflt *f;
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- i = mal(sizeof(*i));
- mpmovefixfix(i, v.u.xval);
- v.u.xval = i;
- break;
- case CTFLT:
- f = mal(sizeof(*f));
- mpmovefltflt(f, v.u.fval);
- v.u.fval = f;
- break;
- case CTCPLX:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, &v.u.cval->real);
- mpmovefltflt(&c->imag, &v.u.cval->imag);
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-tocplx(Val v)
-{
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- c = mal(sizeof(*c));
- mpmovefixflt(&c->real, v.u.xval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- case CTFLT:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, v.u.fval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-toflt(Val v)
-{
- Mpflt *f;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- f = mal(sizeof(*f));
- mpmovefixflt(f, v.u.xval);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- case CTCPLX:
- f = mal(sizeof(*f));
- mpmovefltflt(f, &v.u.cval->real);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- }
- return v;
-}
-
-Val
-toint(Val v)
-{
- Mpint *i;
-
- switch(v.ctype) {
- case CTRUNE:
- v.ctype = CTINT;
- break;
- case CTFLT:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, v.u.fval) < 0)
- yyerror("constant %#F truncated to integer", v.u.fval);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- case CTCPLX:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- }
- return v;
-}
-
-int
-doesoverflow(Val v, Type *t)
-{
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- if(!isint[t->etype])
- fatal("overflow: %T integer constant", t);
- if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
- return 1;
- break;
- case CTFLT:
- if(!isfloat[t->etype])
- fatal("overflow: %T floating-point constant", t);
- if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
- return 1;
- break;
- case CTCPLX:
- if(!iscomplex[t->etype])
- fatal("overflow: %T complex constant", t);
- if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
- mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
- return 1;
- break;
- }
- return 0;
-}
-
-void
-overflow(Val v, Type *t)
-{
- // v has already been converted
- // to appropriate form for t.
- if(t == T || t->etype == TIDEAL)
- return;
-
- if(!doesoverflow(v, t))
- return;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- yyerror("constant %B overflows %T", v.u.xval, t);
- break;
- case CTFLT:
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- case CTCPLX:
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- }
-}
-
-static Val
-tostr(Val v)
-{
- Rune rune;
- int l;
- Strlit *s;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
- yyerror("overflow in int -> string");
- rune = mpgetfix(v.u.xval);
- l = runelen(rune);
- s = mal(sizeof(*s)+l);
- s->len = l;
- runetochar((char*)s->s, &rune);
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = s;
- break;
-
- case CTFLT:
- yyerror("no float -> string");
-
- case CTNIL:
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = mal(sizeof *s);
- break;
- }
- return v;
-}
-
-int
-consttype(Node *n)
-{
- if(n == N || n->op != OLITERAL)
- return -1;
- return n->val.ctype;
-}
-
-int
-isconst(Node *n, int ct)
-{
- int t;
-
- t = consttype(n);
- // If the caller is asking for CTINT, allow CTRUNE too.
- // Makes life easier for back ends.
- return t == ct || (ct == CTINT && t == CTRUNE);
-}
-
-static Node*
-saveorig(Node *n)
-{
- Node *n1;
-
- if(n == n->orig) {
- // duplicate node for n->orig.
- n1 = nod(OLITERAL, N, N);
- n->orig = n1;
- *n1 = *n;
- }
- return n->orig;
-}
-
-/*
- * if n is constant, rewrite as OLITERAL node.
- */
-void
-evconst(Node *n)
-{
- Node *nl, *nr, *norig;
- int32 len;
- Strlit *str;
- int wl, wr, lno, et;
- Val v, rv;
- Mpint b;
- NodeList *l1, *l2;
-
- // pick off just the opcodes that can be
- // constant evaluated.
- switch(n->op) {
- default:
- return;
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OARRAYBYTESTR:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- break;
- case OCONV:
- if(n->type == T)
- return;
- if(!okforconst[n->type->etype] && n->type->etype != TNIL)
- return;
- break;
-
- case OADDSTR:
- // merge adjacent constants in the argument list.
- for(l1=n->list; l1 != nil; l1= l1->next) {
- if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) {
- l2 = l1;
- len = 0;
- while(l2 != nil && isconst(l2->n, CTSTR)) {
- nr = l2->n;
- len += nr->val.u.sval->len;
- l2 = l2->next;
- }
- // merge from l1 up to but not including l2
- str = mal(sizeof(*str) + len);
- str->len = len;
- len = 0;
- l2 = l1;
- while(l2 != nil && isconst(l2->n, CTSTR)) {
- nr = l2->n;
- memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len);
- len += nr->val.u.sval->len;
- l2 = l2->next;
- }
- nl = nod(OXXX, N, N);
- *nl = *l1->n;
- nl->orig = nl;
- nl->val.ctype = CTSTR;
- nl->val.u.sval = str;
- l1->n = nl;
- l1->next = l2;
- }
- }
- // fix list end pointer.
- for(l2=n->list; l2 != nil; l2=l2->next)
- n->list->end = l2;
- // collapse single-constant list to single constant.
- if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) {
- n->op = OLITERAL;
- n->val = n->list->n->val;
- }
- return;
- }
-
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- if(consttype(nl) < 0)
- return;
- wl = nl->type->etype;
- if(isint[wl] || isfloat[wl] || iscomplex[wl])
- wl = TIDEAL;
-
- nr = n->right;
- if(nr == N)
- goto unary;
- if(nr->type == T)
- return;
- if(consttype(nr) < 0)
- return;
- wr = nr->type->etype;
- if(isint[wr] || isfloat[wr] || iscomplex[wr])
- wr = TIDEAL;
-
- // check for compatible general types (numeric, string, etc)
- if(wl != wr)
- goto illegal;
-
- // check for compatible types.
- switch(n->op) {
- default:
- // ideal const mixes with anything but otherwise must match.
- if(nl->type->etype != TIDEAL) {
- defaultlit(&nr, nl->type);
- n->right = nr;
- }
- if(nr->type->etype != TIDEAL) {
- defaultlit(&nl, nr->type);
- n->left = nl;
- }
- if(nl->type->etype != nr->type->etype)
- goto illegal;
- break;
-
- case OLSH:
- case ORSH:
- // right must be unsigned.
- // left can be ideal.
- defaultlit(&nr, types[TUINT]);
- n->right = nr;
- if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
- goto illegal;
- if(nl->val.ctype != CTRUNE)
- nl->val = toint(nl->val);
- nr->val = toint(nr->val);
- break;
- }
-
- // copy numeric value to avoid modifying
- // n->left, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- rv = nr->val;
-
- // convert to common ideal
- if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
- v = tocplx(v);
- rv = tocplx(rv);
- }
- if(v.ctype == CTFLT || rv.ctype == CTFLT) {
- v = toflt(v);
- rv = toflt(rv);
- }
-
- // Rune and int turns into rune.
- if(v.ctype == CTRUNE && rv.ctype == CTINT)
- rv.ctype = CTRUNE;
- if(v.ctype == CTINT && rv.ctype == CTRUNE) {
- if(n->op == OLSH || n->op == ORSH)
- rv.ctype = CTINT;
- else
- v.ctype = CTRUNE;
- }
-
- if(v.ctype != rv.ctype) {
- // Use of undefined name as constant?
- if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
- return;
- fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
- }
-
- // run op
- switch(TUP(n->op, v.ctype)) {
- default:
- goto illegal;
- case TUP(OADD, CTINT):
- case TUP(OADD, CTRUNE):
- mpaddfixfix(v.u.xval, rv.u.xval, 0);
- break;
- case TUP(OSUB, CTINT):
- case TUP(OSUB, CTRUNE):
- mpsubfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMUL, CTINT):
- case TUP(OMUL, CTRUNE):
- mpmulfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ODIV, CTINT):
- case TUP(ODIV, CTRUNE):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpdivfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMOD, CTINT):
- case TUP(OMOD, CTRUNE):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpmodfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OLSH, CTINT):
- case TUP(OLSH, CTRUNE):
- mplshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ORSH, CTINT):
- case TUP(ORSH, CTRUNE):
- mprshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OOR, CTINT):
- case TUP(OOR, CTRUNE):
- mporfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OAND, CTINT):
- case TUP(OAND, CTRUNE):
- mpandfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OANDNOT, CTINT):
- case TUP(OANDNOT, CTRUNE):
- mpandnotfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OXOR, CTINT):
- case TUP(OXOR, CTRUNE):
- mpxorfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OADD, CTFLT):
- mpaddfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OSUB, CTFLT):
- mpsubfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMUL, CTFLT):
- mpmulfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(ODIV, CTFLT):
- if(mpcmpfltc(rv.u.fval, 0) == 0) {
- yyerror("division by zero");
- mpmovecflt(v.u.fval, 1.0);
- break;
- }
- mpdivfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMOD, CTFLT):
- // The default case above would print 'ideal % ideal',
- // which is not quite an ideal error.
- if(!n->diag) {
- yyerror("illegal constant expression: floating-point %% operation");
- n->diag = 1;
- }
- return;
-
- case TUP(OADD, CTCPLX):
- mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OSUB, CTCPLX):
- mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OMUL, CTCPLX):
- cmplxmpy(v.u.cval, rv.u.cval);
- break;
- case TUP(ODIV, CTCPLX):
- if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
- mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
- yyerror("complex division by zero");
- mpmovecflt(&rv.u.cval->real, 1.0);
- mpmovecflt(&rv.u.cval->imag, 0.0);
- break;
- }
- cmplxdiv(v.u.cval, rv.u.cval);
- break;
-
- case TUP(OEQ, CTNIL):
- goto settrue;
- case TUP(ONE, CTNIL):
- goto setfalse;
-
- case TUP(OEQ, CTINT):
- case TUP(OEQ, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTINT):
- case TUP(ONE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTINT):
- case TUP(OLT, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTINT):
- case TUP(OLE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTINT):
- case TUP(OGE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTINT):
- case TUP(OGT, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTSTR):
- if(cmpslit(nl, nr) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTSTR):
- if(cmpslit(nl, nr) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTSTR):
- if(cmpslit(nl, nr) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTSTR):
- if(cmpslit(nl, nr) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTSTR):
- if(cmpslit(nl, nr) >= 0l)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTSTR):
- if(cmpslit(nl, nr) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OOROR, CTBOOL):
- if(v.u.bval || rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OANDAND, CTBOOL):
- if(v.u.bval && rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OEQ, CTBOOL):
- if(v.u.bval == rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTBOOL):
- if(v.u.bval != rv.u.bval)
- goto settrue;
- goto setfalse;
- }
- goto ret;
-
-unary:
- // copy numeric value to avoid modifying
- // nl, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- switch(TUP(n->op, v.ctype)) {
- default:
- if(!n->diag) {
- yyerror("illegal constant expression %O %T", n->op, nl->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OCONV, CTNIL):
- case TUP(OARRAYBYTESTR, CTNIL):
- if(n->type->etype == TSTRING) {
- v = tostr(v);
- nl->type = n->type;
- break;
- }
- // fall through
- case TUP(OCONV, CTINT):
- case TUP(OCONV, CTRUNE):
- case TUP(OCONV, CTFLT):
- case TUP(OCONV, CTSTR):
- convlit1(&nl, n->type, 1);
- v = nl->val;
- break;
-
- case TUP(OPLUS, CTINT):
- case TUP(OPLUS, CTRUNE):
- break;
- case TUP(OMINUS, CTINT):
- case TUP(OMINUS, CTRUNE):
- mpnegfix(v.u.xval);
- break;
- case TUP(OCOM, CTINT):
- case TUP(OCOM, CTRUNE):
- et = Txxx;
- if(nl->type != T)
- et = nl->type->etype;
-
- // calculate the mask in b
- // result will be (a ^ mask)
- switch(et) {
- default:
- // signed guys change sign
- mpmovecfix(&b, -1);
- break;
-
- case TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- case TUINT:
- case TUINTPTR:
- // unsigned guys invert their bits
- mpmovefixfix(&b, maxintval[et]);
- break;
- }
- mpxorfixfix(v.u.xval, &b);
- break;
-
- case TUP(OPLUS, CTFLT):
- break;
- case TUP(OMINUS, CTFLT):
- mpnegflt(v.u.fval);
- break;
-
- case TUP(OPLUS, CTCPLX):
- break;
- case TUP(OMINUS, CTCPLX):
- mpnegflt(&v.u.cval->real);
- mpnegflt(&v.u.cval->imag);
- break;
-
- case TUP(ONOT, CTBOOL):
- if(!v.u.bval)
- goto settrue;
- goto setfalse;
- }
-
-ret:
- norig = saveorig(n);
- *n = *nl;
- // restore value of n->orig.
- n->orig = norig;
- n->val = v;
-
- // check range.
- lno = setlineno(n);
- overflow(v, n->type);
- lineno = lno;
-
- // truncate precision for non-ideal float.
- if(v.ctype == CTFLT && n->type->etype != TIDEAL)
- n->val.u.fval = truncfltlit(v.u.fval, n->type);
- return;
-
-settrue:
- norig = saveorig(n);
- *n = *nodbool(1);
- n->orig = norig;
- return;
-
-setfalse:
- norig = saveorig(n);
- *n = *nodbool(0);
- n->orig = norig;
- return;
-
-illegal:
- if(!n->diag) {
- yyerror("illegal constant expression: %T %O %T",
- nl->type, n->op, nr->type);
- n->diag = 1;
- }
- return;
-}
-
-Node*
-nodlit(Val v)
-{
- Node *n;
-
- n = nod(OLITERAL, N, N);
- n->val = v;
- switch(v.ctype) {
- default:
- fatal("nodlit ctype %d", v.ctype);
- case CTSTR:
- n->type = idealstring;
- break;
- case CTBOOL:
- n->type = idealbool;
- break;
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- n->type = types[TIDEAL];
- break;
- case CTNIL:
- n->type = types[TNIL];
- break;
- }
- return n;
-}
-
-Node*
-nodcplxlit(Val r, Val i)
-{
- Node *n;
- Mpcplx *c;
-
- r = toflt(r);
- i = toflt(i);
-
- c = mal(sizeof(*c));
- n = nod(OLITERAL, N, N);
- n->type = types[TIDEAL];
- n->val.u.cval = c;
- n->val.ctype = CTCPLX;
-
- if(r.ctype != CTFLT || i.ctype != CTFLT)
- fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
-
- mpmovefltflt(&c->real, r.u.fval);
- mpmovefltflt(&c->imag, i.u.fval);
- return n;
-}
-
-// idealkind returns a constant kind like consttype
-// but for an arbitrary "ideal" (untyped constant) expression.
-static int
-idealkind(Node *n)
-{
- int k1, k2;
-
- if(n == N || !isideal(n->type))
- return CTxxx;
-
- switch(n->op) {
- default:
- return CTxxx;
- case OLITERAL:
- return n->val.ctype;
- case OADD:
- case OAND:
- case OANDNOT:
- case OCOM:
- case ODIV:
- case OMINUS:
- case OMOD:
- case OMUL:
- case OSUB:
- case OXOR:
- case OOR:
- case OPLUS:
- // numeric kinds.
- k1 = idealkind(n->left);
- k2 = idealkind(n->right);
- if(k1 > k2)
- return k1;
- else
- return k2;
- case OREAL:
- case OIMAG:
- return CTFLT;
- case OCOMPLEX:
- return CTCPLX;
- case OADDSTR:
- return CTSTR;
- case OANDAND:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case ONE:
- case ONOT:
- case OOROR:
- case OCMPSTR:
- case OCMPIFACE:
- return CTBOOL;
- case OLSH:
- case ORSH:
- // shifts (beware!).
- return idealkind(n->left);
- }
-}
-
-void
-defaultlit(Node **np, Type *t)
-{
- int lno;
- int ctype;
- Node *n, *nn;
- Type *t1;
-
- n = *np;
- if(n == N || !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- lno = setlineno(n);
- ctype = idealkind(n);
- switch(ctype) {
- default:
- if(t != T) {
- convlit(np, t);
- return;
- }
- if(n->val.ctype == CTNIL) {
- lineno = lno;
- if(!n->diag) {
- yyerror("use of untyped nil");
- n->diag = 1;
- }
- n->type = T;
- break;
- }
- if(n->val.ctype == CTSTR) {
- t1 = types[TSTRING];
- convlit(np, t1);
- break;
- }
- yyerror("defaultlit: unknown literal: %N", n);
- break;
- case CTxxx:
- fatal("defaultlit: idealkind is CTxxx: %+N", n);
- break;
- case CTBOOL:
- t1 = types[TBOOL];
- if(t != T && t->etype == TBOOL)
- t1 = t;
- convlit(np, t1);
- break;
- case CTINT:
- t1 = types[TINT];
- goto num;
- case CTRUNE:
- t1 = runetype;
- goto num;
- case CTFLT:
- t1 = types[TFLOAT64];
- goto num;
- case CTCPLX:
- t1 = types[TCOMPLEX128];
- goto num;
- }
- lineno = lno;
- return;
-
-num:
- if(t != T) {
- if(isint[t->etype]) {
- t1 = t;
- n->val = toint(n->val);
- }
- else
- if(isfloat[t->etype]) {
- t1 = t;
- n->val = toflt(n->val);
- }
- else
- if(iscomplex[t->etype]) {
- t1 = t;
- n->val = tocplx(n->val);
- }
- }
- overflow(n->val, t1);
- convlit(np, t1);
- lineno = lno;
- return;
-}
-
-/*
- * defaultlit on both nodes simultaneously;
- * if they're both ideal going in they better
- * get the same type going out.
- * force means must assign concrete (non-ideal) type.
- */
-void
-defaultlit2(Node **lp, Node **rp, int force)
-{
- Node *l, *r;
- int lkind, rkind;
-
- l = *lp;
- r = *rp;
- if(l->type == T || r->type == T)
- return;
- if(!isideal(l->type)) {
- convlit(rp, l->type);
- return;
- }
- if(!isideal(r->type)) {
- convlit(lp, r->type);
- return;
- }
- if(!force)
- return;
- if(l->type->etype == TBOOL) {
- convlit(lp, types[TBOOL]);
- convlit(rp, types[TBOOL]);
- }
- lkind = idealkind(l);
- rkind = idealkind(r);
- if(lkind == CTCPLX || rkind == CTCPLX) {
- convlit(lp, types[TCOMPLEX128]);
- convlit(rp, types[TCOMPLEX128]);
- return;
- }
- if(lkind == CTFLT || rkind == CTFLT) {
- convlit(lp, types[TFLOAT64]);
- convlit(rp, types[TFLOAT64]);
- return;
- }
-
- if(lkind == CTRUNE || rkind == CTRUNE) {
- convlit(lp, runetype);
- convlit(rp, runetype);
- return;
- }
-
- convlit(lp, types[TINT]);
- convlit(rp, types[TINT]);
-}
-
-int
-cmpslit(Node *l, Node *r)
-{
- int32 l1, l2, i, m;
- uchar *s1, *s2;
-
- l1 = l->val.u.sval->len;
- l2 = r->val.u.sval->len;
- s1 = (uchar*)l->val.u.sval->s;
- s2 = (uchar*)r->val.u.sval->s;
-
- m = l1;
- if(l2 < m)
- m = l2;
-
- for(i=0; i<m; i++) {
- if(s1[i] == s2[i])
- continue;
- if(s1[i] > s2[i])
- return +1;
- return -1;
- }
- if(l1 == l2)
- return 0;
- if(l1 > l2)
- return +1;
- return -1;
-}
-
-int
-smallintconst(Node *n)
-{
- if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TBOOL:
- case TPTR32:
- return 1;
- case TIDEAL:
- case TINT64:
- case TUINT64:
- case TPTR64:
- if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return 1;
- }
- return 0;
-}
-
-long
-nonnegconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TIDEAL:
- // check negative and 2^31
- if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return mpgetfix(n->val.u.xval);
- }
- return -1;
-}
-
-/*
- * convert x to type et and back to int64
- * for sign extension and truncation.
- */
-static int64
-iconv(int64 x, int et)
-{
- switch(et) {
- case TINT8:
- x = (int8)x;
- break;
- case TUINT8:
- x = (uint8)x;
- break;
- case TINT16:
- x = (int16)x;
- break;
- case TUINT16:
- x = (uint64)x;
- break;
- case TINT32:
- x = (int32)x;
- break;
- case TUINT32:
- x = (uint32)x;
- break;
- case TINT64:
- case TUINT64:
- break;
- }
- return x;
-}
-
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-void
-convconst(Node *con, Type *t, Val *val)
-{
- int64 i;
- int tt;
-
- tt = simsimtype(t);
-
- // copy the constant for conversion
- nodconst(con, types[TINT8], 0);
- con->type = t;
- con->val = *val;
-
- if(isint[tt]) {
- con->val.ctype = CTINT;
- con->val.u.xval = mal(sizeof *con->val.u.xval);
- switch(val->ctype) {
- default:
- fatal("convconst ctype=%d %lT", val->ctype, t);
- case CTINT:
- case CTRUNE:
- i = mpgetfix(val->u.xval);
- break;
- case CTBOOL:
- i = val->u.bval;
- break;
- case CTNIL:
- i = 0;
- break;
- }
- i = iconv(i, tt);
- mpmovecfix(con->val.u.xval, i);
- return;
- }
-
- if(isfloat[tt]) {
- con->val = toflt(con->val);
- if(con->val.ctype != CTFLT)
- fatal("convconst ctype=%d %T", con->val.ctype, t);
- if(tt == TFLOAT32)
- con->val.u.fval = truncfltlit(con->val.u.fval, t);
- return;
- }
-
- if(iscomplex[tt]) {
- con->val = tocplx(con->val);
- if(tt == TCOMPLEX64) {
- con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
- con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
- }
- return;
- }
-
- fatal("convconst %lT constant", t);
-
-}
-
-// complex multiply v *= rv
-// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
-static void
-cmplxmpy(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad;
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpsubfltflt(&v->real, &bd); // ac-bd
-
- mpmovefltflt(&v->imag, &bc);
- mpaddfltflt(&v->imag, &ad); // bc+ad
-}
-
-// complex divide v /= rv
-// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-static void
-cmplxdiv(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad, cc_plus_dd;
-
- mpmovefltflt(&cc_plus_dd, &rv->real);
- mpmulfltflt(&cc_plus_dd, &rv->real); // cc
-
- mpmovefltflt(&ac, &rv->imag);
- mpmulfltflt(&ac, &rv->imag); // dd
-
- mpaddfltflt(&cc_plus_dd, &ac); // cc+dd
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpaddfltflt(&v->real, &bd); // ac+bd
- mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd)
-
- mpmovefltflt(&v->imag, &bc);
- mpsubfltflt(&v->imag, &ad); // bc-ad
- mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
-}
-
-static int hascallchan(Node*);
-
-// Is n a Go language constant (as opposed to a compile-time constant)?
-// Expressions derived from nil, like string([]byte(nil)), while they
-// may be known at compile time, are not Go language constants.
-// Only called for expressions known to evaluated to compile-time
-// constants.
-int
-isgoconst(Node *n)
-{
- Node *l;
- Type *t;
-
- if(n->orig != N)
- n = n->orig;
-
- switch(n->op) {
- case OADD:
- case OADDSTR:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- case OIOTA:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
- return 1;
- break;
-
- case OCONV:
- if(okforconst[n->type->etype] && isgoconst(n->left))
- return 1;
- break;
-
- case OLEN:
- case OCAP:
- l = n->left;
- if(isgoconst(l))
- return 1;
- // Special case: len/cap is constant when applied to array or
- // pointer to array when the expression does not contain
- // function calls or channel receive operations.
- t = l->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t) && !hascallchan(l))
- return 1;
- break;
-
- case OLITERAL:
- if(n->val.ctype != CTNIL)
- return 1;
- break;
-
- case ONAME:
- l = n->sym->def;
- if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
- return 1;
- break;
-
- case ONONAME:
- if(n->sym->def != N && n->sym->def->op == OIOTA)
- return 1;
- break;
-
- case OCALL:
- // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
- l = n->left;
- while(l->op == OPAREN)
- l = l->left;
- if(l->op != ONAME || l->sym->pkg != unsafepkg)
- break;
- if(strcmp(l->sym->name, "Alignof") == 0 ||
- strcmp(l->sym->name, "Offsetof") == 0 ||
- strcmp(l->sym->name, "Sizeof") == 0)
- return 1;
- break;
- }
-
- //dump("nonconst", n);
- return 0;
-}
-
-static int
-hascallchan(Node *n)
-{
- NodeList *l;
-
- if(n == N)
- return 0;
- switch(n->op) {
- case OAPPEND:
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- case OCAP:
- case OCLOSE:
- case OCOMPLEX:
- case OCOPY:
- case ODELETE:
- case OIMAG:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case OREAL:
- case ORECOVER:
- case ORECV:
- return 1;
- }
-
- if(hascallchan(n->left) ||
- hascallchan(n->right))
- return 1;
-
- for(l=n->list; l; l=l->next)
- if(hascallchan(l->n))
- return 1;
- for(l=n->rlist; l; l=l->next)
- if(hascallchan(l->n))
- return 1;
-
- return 0;
-}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
deleted file mode 100644
index 26c21df82a..0000000000
--- a/src/cmd/gc/cplx.c
+++ /dev/null
@@ -1,494 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static void subnode(Node *nr, Node *ni, Node *nc);
-static void minus(Node *nl, Node *res);
- void complexminus(Node*, Node*);
- void complexadd(int op, Node*, Node*, Node*);
- void complexmul(Node*, Node*, Node*);
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-/*c2go
-static int
-CASE(int a, int b)
-{
- return a<<16 | b;
-}
-*/
-
-static int
-overlap(Node *f, Node *t)
-{
- // check whether f and t could be overlapping stack references.
- // not exact, because it's hard to check for the stack register
- // in portable code. close enough: worst case we will allocate
- // an extra temporary and the registerizer will clean it up.
- return f->op == OINDREG &&
- t->op == OINDREG &&
- f->xoffset+f->type->width >= t->xoffset &&
- t->xoffset+t->type->width >= f->xoffset;
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-complexmove(Node *f, Node *t)
-{
- int ft, tt;
- Node n1, n2, n3, n4, tmp;
-
- if(debug['g']) {
- dump("\ncomplexmove-f", f);
- dump("complexmove-t", t);
- }
-
- if(!t->addable)
- fatal("complexmove: to not addable");
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- switch(CASE(ft,tt)) {
-
- default:
- fatal("complexmove: unknown conversion: %T -> %T\n",
- f->type, t->type);
-
- case CASE(TCOMPLEX64,TCOMPLEX64):
- case CASE(TCOMPLEX64,TCOMPLEX128):
- case CASE(TCOMPLEX128,TCOMPLEX64):
- case CASE(TCOMPLEX128,TCOMPLEX128):
- // complex to complex move/convert.
- // make f addable.
- // also use temporary if possible stack overlap.
- if(!f->addable || overlap(f, t)) {
- tempname(&tmp, f->type);
- complexmove(f, &tmp);
- f = &tmp;
- }
-
- subnode(&n1, &n2, f);
- subnode(&n3, &n4, t);
-
- thearch.cgen(&n1, &n3);
- thearch.cgen(&n2, &n4);
- break;
- }
-}
-
-int
-complexop(Node *n, Node *res)
-{
- if(n != N && n->type != T)
- if(iscomplex[n->type->etype]) {
- goto maybe;
- }
- if(res != N && res->type != T)
- if(iscomplex[res->type->etype]) {
- goto maybe;
- }
-
- if(n->op == OREAL || n->op == OIMAG)
- goto yes;
-
- goto no;
-
-maybe:
- switch(n->op) {
- case OCONV: // implemented ops
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- goto yes;
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME:
- goto yes;
- }
-
-no:
-//dump("\ncomplex-no", n);
- return 0;
-yes:
-//dump("\ncomplex-yes", n);
- return 1;
-}
-
-void
-complexgen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node tnl, tnr;
- Node n1, n2, tmp;
- int tl, tr;
-
- if(debug['g']) {
- dump("\ncomplexgen-n", n);
- dump("complexgen-res", res);
- }
-
- while(n->op == OCONVNOP)
- n = n->left;
-
- // pick off float/complex opcodes
- switch(n->op) {
- case OCOMPLEX:
- if(res->addable) {
- subnode(&n1, &n2, res);
- tempname(&tmp, n1.type);
- thearch.cgen(n->left, &tmp);
- thearch.cgen(n->right, &n2);
- thearch.cgen(&tmp, &n1);
- return;
- }
- break;
-
- case OREAL:
- case OIMAG:
- nl = n->left;
- if(!nl->addable) {
- tempname(&tmp, nl->type);
- complexgen(nl, &tmp);
- nl = &tmp;
- }
- subnode(&n1, &n2, nl);
- if(n->op == OREAL) {
- thearch.cgen(&n1, res);
- return;
- }
- thearch.cgen(&n2, res);
- return;
- }
-
- // perform conversion from n to res
- tl = simsimtype(res->type);
- tl = cplxsubtype(tl);
- tr = simsimtype(n->type);
- tr = cplxsubtype(tr);
- if(tl != tr) {
- if(!n->addable) {
- tempname(&n1, n->type);
- complexmove(n, &n1);
- n = &n1;
- }
- complexmove(n, res);
- return;
- }
-
- if(!res->addable) {
- thearch.igen(res, &n1, N);
- thearch.cgen(n, &n1);
- thearch.regfree(&n1);
- return;
- }
- if(n->addable) {
- complexmove(n, res);
- return;
- }
-
- switch(n->op) {
- default:
- dump("complexgen: unknown op", n);
- fatal("complexgen: unknown op %O", n->op);
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME: // PHEAP or PPARAMREF var
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- thearch.igen(n, &n1, res);
- complexmove(&n1, res);
- thearch.regfree(&n1);
- return;
-
- case OCONV:
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- break;
- }
-
- nl = n->left;
- if(nl == N)
- return;
- nr = n->right;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- thearch.cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- thearch.cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- thearch.cgen(nl, &tnl);
- nl = &tnl;
- }
-
- switch(n->op) {
- default:
- fatal("complexgen: unknown op %O", n->op);
- break;
-
- case OCONV:
- complexmove(nl, res);
- break;
-
- case OMINUS:
- complexminus(nl, res);
- break;
-
- case OADD:
- case OSUB:
- complexadd(n->op, nl, nr, res);
- break;
-
- case OMUL:
- complexmul(nl, nr, res);
- break;
- }
-}
-
-void
-complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
-{
- Node tnl, tnr;
- Node n1, n2, n3, n4;
- Node na, nb, nc;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- thearch.cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- thearch.cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- thearch.cgen(nl, &tnl);
- nl = &tnl;
- }
-
- // build tree
- // real(l) == real(r) && imag(l) == imag(r)
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
-
- memset(&na, 0, sizeof(na));
- na.op = OANDAND;
- na.left = &nb;
- na.right = &nc;
- na.type = types[TBOOL];
-
- memset(&nb, 0, sizeof(nb));
- nb.op = OEQ;
- nb.left = &n1;
- nb.right = &n3;
- nb.type = types[TBOOL];
-
- memset(&nc, 0, sizeof(nc));
- nc.op = OEQ;
- nc.left = &n2;
- nc.right = &n4;
- nc.type = types[TBOOL];
-
- if(op == ONE)
- true = !true;
-
- thearch.bgen(&na, true, likely, to);
-}
-
-void
-nodfconst(Node *n, Type *t, Mpflt* fval)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.fval = fval;
- n->val.ctype = CTFLT;
- n->type = t;
-
- if(!isfloat[t->etype])
- fatal("nodfconst: bad type %T", t);
-}
-
-// break addable nc-complex into nr-real and ni-imaginary
-static void
-subnode(Node *nr, Node *ni, Node *nc)
-{
- int tc;
- Type *t;
-
- if(!nc->addable)
- fatal("subnode not addable");
-
- tc = simsimtype(nc->type);
- tc = cplxsubtype(tc);
- t = types[tc];
-
- if(nc->op == OLITERAL) {
- nodfconst(nr, t, &nc->val.u.cval->real);
- nodfconst(ni, t, &nc->val.u.cval->imag);
- return;
- }
-
- *nr = *nc;
- nr->type = t;
-
- *ni = *nc;
- ni->type = t;
- ni->xoffset += t->width;
-}
-
-// generate code res = -nl
-static void
-minus(Node *nl, Node *res)
-{
- Node ra;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OMINUS;
- ra.left = nl;
- ra.type = nl->type;
- thearch.cgen(&ra, res);
-}
-
-// build and execute tree
-// real(res) = -real(nl)
-// imag(res) = -imag(nl)
-void
-complexminus(Node *nl, Node *res)
-{
- Node n1, n2, n5, n6;
-
- subnode(&n1, &n2, nl);
- subnode(&n5, &n6, res);
-
- minus(&n1, &n5);
- minus(&n2, &n6);
-}
-
-
-// build and execute tree
-// real(res) = real(nl) op real(nr)
-// imag(res) = imag(nl) op imag(nr)
-void
-complexadd(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node ra;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n1;
- ra.right = &n3;
- ra.type = n1.type;
- thearch.cgen(&ra, &n5);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n2;
- ra.right = &n4;
- ra.type = n2.type;
- thearch.cgen(&ra, &n6);
-}
-
-// build and execute tree
-// tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
-// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
-// real(res) = tmp
-void
-complexmul(Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node rm1, rm2, ra, tmp;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
- tempname(&tmp, n5.type);
-
- // real part -> tmp
- memset(&rm1, 0, sizeof(rm1));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n3;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(rm2));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n4;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OSUB;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- thearch.cgen(&ra, &tmp);
-
- // imag part
- memset(&rm1, 0, sizeof(rm1));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n4;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(rm2));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n3;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OADD;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- thearch.cgen(&ra, &n6);
-
- // tmp ->real part
- thearch.cgen(&tmp, &n5);
-}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
deleted file mode 100644
index 9a6c0023f5..0000000000
--- a/src/cmd/gc/dcl.c
+++ /dev/null
@@ -1,1479 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "y.tab.h"
-
-static void funcargs(Node*);
-static void funcargs2(Type*);
-
-static int
-dflag(void)
-{
- if(!debug['d'])
- return 0;
- if(debug['y'])
- return 1;
- if(incannedimport)
- return 0;
- return 1;
-}
-
-/*
- * declaration stack & operations
- */
-
-static void
-dcopy(Sym *a, Sym *b)
-{
- a->pkg = b->pkg;
- a->name = b->name;
- a->def = b->def;
- a->block = b->block;
- a->lastlineno = b->lastlineno;
-}
-
-static Sym*
-push(void)
-{
- Sym *d;
-
- d = mal(sizeof(*d));
- d->lastlineno = lineno;
- d->link = dclstack;
- dclstack = d;
- return d;
-}
-
-static Sym*
-pushdcl(Sym *s)
-{
- Sym *d;
-
- d = push();
- dcopy(d, s);
- if(dflag())
- print("\t%L push %S %p\n", lineno, s, s->def);
- return d;
-}
-
-void
-popdcl(void)
-{
- Sym *d, *s;
- int lno;
-
-// if(dflag())
-// print("revert\n");
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->pkg);
- lno = s->lastlineno;
- dcopy(s, d);
- d->lastlineno = lno;
- if(dflag())
- print("\t%L pop %S %p\n", lineno, s, s->def);
- }
- if(d == S)
- fatal("popdcl: no mark");
- dclstack = d->link;
- block = d->block;
-}
-
-void
-poptodcl(void)
-{
- // pop the old marker and push a new one
- // (cannot reuse the existing one)
- // because we use the markers to identify blocks
- // for the goto restriction checks.
- popdcl();
- markdcl();
-}
-
-void
-markdcl(void)
-{
- Sym *d;
-
- d = push();
- d->name = nil; // used as a mark in fifo
- d->block = block;
-
- blockgen++;
- block = blockgen;
-
-// if(dflag())
-// print("markdcl\n");
-}
-
-void
-dumpdcl(char *st)
-{
- Sym *s, *d;
- int i;
-
- USED(st);
-
- i = 0;
- for(d=dclstack; d!=S; d=d->link) {
- i++;
- print(" %.2d %p", i, d);
- if(d->name == nil) {
- print("\n");
- continue;
- }
- print(" '%s'", d->name);
- s = pkglookup(d->name, d->pkg);
- print(" %S\n", s);
- }
-}
-
-void
-testdclstack(void)
-{
- Sym *d;
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil) {
- if(nerrors != 0)
- errorexit();
- yyerror("mark left on the stack");
- continue;
- }
- }
-}
-
-void
-redeclare(Sym *s, char *where)
-{
- Strlit *pkgstr;
- int line1, line2;
-
- if(s->lastlineno == 0) {
- pkgstr = s->origpkg ? s->origpkg->path : s->pkg->path;
- yyerror("%S redeclared %s\n"
- "\tprevious declaration during import \"%Z\"",
- s, where, pkgstr);
- } else {
- line1 = parserline();
- line2 = s->lastlineno;
-
- // When an import and a declaration collide in separate files,
- // present the import as the "redeclared", because the declaration
- // is visible where the import is, but not vice versa.
- // See issue 4510.
- if(s->def == N) {
- line2 = line1;
- line1 = s->lastlineno;
- }
-
- yyerrorl(line1, "%S redeclared %s\n"
- "\tprevious declaration at %L",
- s, where, line2);
- }
-}
-
-static int vargen;
-
-/*
- * declare individual names - var, typ, const
- */
-void
-declare(Node *n, int ctxt)
-{
- Sym *s;
- int gen;
- static int typegen;
-
- if(ctxt == PDISCARD)
- return;
-
- if(isblank(n))
- return;
-
- n->lineno = parserline();
- s = n->sym;
-
- // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
- if(importpkg == nil && !typecheckok && s->pkg != localpkg)
- yyerror("cannot declare name %S", s);
-
- if(ctxt == PEXTERN && strcmp(s->name, "init") == 0)
- yyerror("cannot declare init - must be func", s);
-
- gen = 0;
- if(ctxt == PEXTERN) {
- externdcl = list(externdcl, n);
- if(dflag())
- print("\t%L global decl %S %p\n", lineno, s, n);
- } else {
- if(curfn == nil && ctxt == PAUTO)
- fatal("automatic outside function");
- if(curfn != nil)
- curfn->dcl = list(curfn->dcl, n);
- if(n->op == OTYPE)
- gen = ++typegen;
- else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil)
- gen = ++vargen;
- pushdcl(s);
- n->curfn = curfn;
- }
- if(ctxt == PAUTO)
- n->xoffset = 0;
-
- if(s->block == block) {
- // functype will print errors about duplicate function arguments.
- // Don't repeat the error here.
- if(ctxt != PPARAM && ctxt != PPARAMOUT)
- redeclare(s, "in this block");
- }
-
- s->block = block;
- s->lastlineno = parserline();
- s->def = n;
- n->vargen = gen;
- n->funcdepth = funcdepth;
- n->class = ctxt;
-
- autoexport(n, ctxt);
-}
-
-void
-addvar(Node *n, Type *t, int ctxt)
-{
- if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
- fatal("addvar: n=%N t=%T nil", n, t);
-
- n->op = ONAME;
- declare(n, ctxt);
- n->type = t;
-}
-
-/*
- * declare variables from grammar
- * new_name_list (type | [type] = expr_list)
- */
-NodeList*
-variter(NodeList *vl, Node *t, NodeList *el)
-{
- int doexpr;
- Node *v, *e, *as2;
- NodeList *init;
-
- init = nil;
- doexpr = el != nil;
-
- if(count(el) == 1 && count(vl) > 1) {
- e = el->n;
- as2 = nod(OAS2, N, N);
- as2->list = vl;
- as2->rlist = list1(e);
- for(; vl; vl=vl->next) {
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
- v->defn = as2;
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- }
- return list(init, as2);
- }
-
- for(; vl; vl=vl->next) {
- if(doexpr) {
- if(el == nil) {
- yyerror("missing expression in var declaration");
- break;
- }
- e = el->n;
- el = el->next;
- } else
- e = N;
-
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
-
- if(e != N || funcdepth > 0 || isblank(v)) {
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- e = nod(OAS, v, e);
- init = list(init, e);
- if(e->right != N)
- v->defn = e;
- }
- }
- if(el != nil)
- yyerror("extra expression in var declaration");
- return init;
-}
-
-/*
- * declare constants from grammar
- * new_name_list [[type] = expr_list]
- */
-NodeList*
-constiter(NodeList *vl, Node *t, NodeList *cl)
-{
- Node *v, *c;
- NodeList *vv;
-
- vv = nil;
- if(cl == nil) {
- if(t != N)
- yyerror("const declaration cannot have type without expression");
- cl = lastconst;
- t = lasttype;
- } else {
- lastconst = cl;
- lasttype = t;
- }
- cl = listtreecopy(cl);
-
- for(; vl; vl=vl->next) {
- if(cl == nil) {
- yyerror("missing value in const declaration");
- break;
- }
- c = cl->n;
- cl = cl->next;
-
- v = vl->n;
- v->op = OLITERAL;
- declare(v, dclcontext);
-
- v->ntype = t;
- v->defn = c;
-
- vv = list(vv, nod(ODCLCONST, v, N));
- }
- if(cl != nil)
- yyerror("extra expression in const declaration");
- iota += 1;
- return vv;
-}
-
-/*
- * this generates a new name node,
- * typically for labels or other one-off names.
- */
-Node*
-newname(Sym *s)
-{
- Node *n;
-
- if(s == S)
- fatal("newname nil");
-
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = T;
- n->addable = 1;
- n->ullman = 1;
- n->xoffset = 0;
- return n;
-}
-
-/*
- * this generates a new name node for a name
- * being declared.
- */
-Node*
-dclname(Sym *s)
-{
- Node *n;
-
- n = newname(s);
- n->op = ONONAME; // caller will correct it
- return n;
-}
-
-Node*
-typenod(Type *t)
-{
- // if we copied another type with *t = *u
- // then t->nod might be out of date, so
- // check t->nod->type too
- if(t->nod == N || t->nod->type != t) {
- t->nod = nod(OTYPE, N, N);
- t->nod->type = t;
- t->nod->sym = t->sym;
- }
- return t->nod;
-}
-
-
-/*
- * this will return an old name
- * that has already been pushed on the
- * declaration list. a diagnostic is
- * generated if no name has been defined.
- */
-Node*
-oldname(Sym *s)
-{
- Node *n;
- Node *c;
-
- n = s->def;
- if(n == N) {
- // maybe a top-level name will come along
- // to give this a definition later.
- // walkdef will check s->def again once
- // all the input source has been processed.
- n = newname(s);
- n->op = ONONAME;
- n->iota = iota; // save current iota value in const declarations
- }
- if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
- // inner func is referring to var in outer func.
- //
- // TODO(rsc): If there is an outer variable x and we
- // are parsing x := 5 inside the closure, until we get to
- // the := it looks like a reference to the outer x so we'll
- // make x a closure variable unnecessarily.
- if(n->closure == N || n->closure->funcdepth != funcdepth) {
- // create new closure var.
- c = nod(ONAME, N, N);
- c->sym = s;
- c->class = PPARAMREF;
- c->isddd = n->isddd;
- c->defn = n;
- c->addable = 0;
- c->ullman = 2;
- c->funcdepth = funcdepth;
- c->outer = n->closure;
- n->closure = c;
- c->closure = n;
- c->xoffset = 0;
- curfn->cvars = list(curfn->cvars, c);
- }
- // return ref to closure var, not original
- return n->closure;
- }
- return n;
-}
-
-/*
- * := declarations
- */
-
-static int
-colasname(Node *n)
-{
- switch(n->op) {
- case ONAME:
- case ONONAME:
- case OPACK:
- case OTYPE:
- case OLITERAL:
- return n->sym != S;
- }
- return 0;
-}
-
-void
-colasdefn(NodeList *left, Node *defn)
-{
- int nnew, nerr;
- NodeList *l;
- Node *n;
-
- for(l=left; l; l=l->next)
- if(l->n->sym != S)
- l->n->sym->flags |= SymUniq;
-
- nnew = 0;
- nerr = 0;
- for(l=left; l; l=l->next) {
- n = l->n;
- if(isblank(n))
- continue;
- if(!colasname(n)) {
- yyerrorl(defn->lineno, "non-name %N on left side of :=", n);
- nerr++;
- continue;
- }
- if((n->sym->flags & SymUniq) == 0) {
- yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym);
- n->diag++;
- nerr++;
- continue;
- }
- n->sym->flags &= ~SymUniq;
- if(n->sym->block == block)
- continue;
-
- nnew++;
- n = newname(n->sym);
- declare(n, dclcontext);
- n->defn = defn;
- defn->ninit = list(defn->ninit, nod(ODCL, n, N));
- l->n = n;
- }
- if(nnew == 0 && nerr == 0)
- yyerrorl(defn->lineno, "no new variables on left side of :=");
-}
-
-Node*
-colas(NodeList *left, NodeList *right, int32 lno)
-{
- Node *as;
-
- as = nod(OAS2, N, N);
- as->list = left;
- as->rlist = right;
- as->colas = 1;
- as->lineno = lno;
- colasdefn(left, as);
-
- // make the tree prettier; not necessary
- if(count(left) == 1 && count(right) == 1) {
- as->left = as->list->n;
- as->right = as->rlist->n;
- as->list = nil;
- as->rlist = nil;
- as->op = OAS;
- }
-
- return as;
-}
-
-/*
- * declare the arguments in an
- * interface field declaration.
- */
-void
-ifacedcl(Node *n)
-{
- if(n->op != ODCLFIELD || n->right == N)
- fatal("ifacedcl");
-
- if(isblank(n->left))
- yyerror("methods must have a unique non-blank name");
-
- dclcontext = PPARAM;
- markdcl();
- funcdepth++;
- n->outer = curfn;
- curfn = n;
- funcargs(n->right);
-
- // funcbody is normally called after the parser has
- // seen the body of a function but since an interface
- // field declaration does not have a body, we must
- // call it now to pop the current declaration context.
- dclcontext = PAUTO;
- funcbody(n);
-}
-
-/*
- * declare the function proper
- * and declare the arguments.
- * called in extern-declaration context
- * returns in auto-declaration context.
- */
-void
-funchdr(Node *n)
-{
- // change the declaration context from extern to auto
- if(funcdepth == 0 && dclcontext != PEXTERN)
- fatal("funchdr: dclcontext");
-
- dclcontext = PAUTO;
- markdcl();
- funcdepth++;
-
- n->outer = curfn;
- curfn = n;
-
- if(n->nname)
- funcargs(n->nname->ntype);
- else if (n->ntype)
- funcargs(n->ntype);
- else
- funcargs2(n->type);
-}
-
-static void
-funcargs(Node *nt)
-{
- Node *n, *nn;
- NodeList *l;
- int gen;
-
- if(nt->op != OTFUNC)
- fatal("funcargs %O", nt->op);
-
- // re-start the variable generation number
- // we want to use small numbers for the return variables,
- // so let them have the chunk starting at 1.
- vargen = count(nt->rlist);
-
- // declare the receiver and in arguments.
- // no n->defn because type checking of func header
- // will not fill in the types until later
- if(nt->left != N) {
- n = nt->left;
- if(n->op != ODCLFIELD)
- fatal("funcargs receiver %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- if(dclcontext == PAUTO)
- n->left->vargen = ++vargen;
- }
- }
- for(l=nt->list; l; l=l->next) {
- n = l->n;
- if(n->op != ODCLFIELD)
- fatal("funcargs in %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- if(dclcontext == PAUTO)
- n->left->vargen = ++vargen;
- }
- }
-
- // declare the out arguments.
- gen = count(nt->list);
- int i = 0;
- for(l=nt->rlist; l; l=l->next) {
- n = l->n;
-
- if(n->op != ODCLFIELD)
- fatal("funcargs out %O", n->op);
-
- if(n->left == N) {
- // Name so that escape analysis can track it. ~r stands for 'result'.
- snprint(namebuf, sizeof(namebuf), "~r%d", gen++);
- n->left = newname(lookup(namebuf));
- // TODO: n->left->missing = 1;
- }
-
- n->left->op = ONAME;
-
- if(isblank(n->left)) {
- // Give it a name so we can assign to it during return. ~b stands for 'blank'.
- // The name must be different from ~r above because if you have
- // func f() (_ int)
- // func g() int
- // f is allowed to use a plain 'return' with no arguments, while g is not.
- // So the two cases must be distinguished.
- // We do not record a pointer to the original node (n->orig).
- // Having multiple names causes too much confusion in later passes.
- nn = nod(OXXX, N, N);
- *nn = *n->left;
- nn->orig = nn;
- snprint(namebuf, sizeof(namebuf), "~b%d", gen++);
- nn->sym = lookup(namebuf);
- n->left = nn;
- }
-
- n->left->ntype = n->right;
- declare(n->left, PPARAMOUT);
- if(dclcontext == PAUTO)
- n->left->vargen = ++i;
- }
-}
-
-/*
- * Same as funcargs, except run over an already constructed TFUNC.
- * This happens during import, where the hidden_fndcl rule has
- * used functype directly to parse the function's type.
- */
-static void
-funcargs2(Type *t)
-{
- Type *ft;
- Node *n;
-
- if(t->etype != TFUNC)
- fatal("funcargs2 %T", t);
-
- if(t->thistuple)
- for(ft=getthisx(t)->type; ft; ft=ft->down) {
- if(!ft->nname || !ft->nname->sym)
- continue;
- n = ft->nname; // no need for newname(ft->nname->sym)
- n->type = ft->type;
- declare(n, PPARAM);
- }
-
- if(t->intuple)
- for(ft=getinargx(t)->type; ft; ft=ft->down) {
- if(!ft->nname || !ft->nname->sym)
- continue;
- n = ft->nname;
- n->type = ft->type;
- declare(n, PPARAM);
- }
-
- if(t->outtuple)
- for(ft=getoutargx(t)->type; ft; ft=ft->down) {
- if(!ft->nname || !ft->nname->sym)
- continue;
- n = ft->nname;
- n->type = ft->type;
- declare(n, PPARAMOUT);
- }
-}
-
-/*
- * finish the body.
- * called in auto-declaration context.
- * returns in extern-declaration context.
- */
-void
-funcbody(Node *n)
-{
- // change the declaration context from auto to extern
- if(dclcontext != PAUTO)
- fatal("funcbody: dclcontext");
- popdcl();
- funcdepth--;
- curfn = n->outer;
- n->outer = N;
- if(funcdepth == 0)
- dclcontext = PEXTERN;
-}
-
-/*
- * new type being defined with name s.
- */
-Node*
-typedcl0(Sym *s)
-{
- Node *n;
-
- n = newname(s);
- n->op = OTYPE;
- declare(n, dclcontext);
- return n;
-}
-
-/*
- * node n, which was returned by typedcl0
- * is being declared to have uncompiled type t.
- * return the ODCLTYPE node to use.
- */
-Node*
-typedcl1(Node *n, Node *t, int local)
-{
- n->ntype = t;
- n->local = local;
- return nod(ODCLTYPE, n, N);
-}
-
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
-
-static void
-checkembeddedtype(Type *t)
-{
- if (t == T)
- return;
-
- if(t->sym == S && isptr[t->etype]) {
- t = t->type;
- if(t->etype == TINTER)
- yyerror("embedded type cannot be a pointer to interface");
- }
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- else if(t->etype == TFORW && t->embedlineno == 0)
- t->embedlineno = lineno;
-}
-
-static Type*
-structfield(Node *n)
-{
- Type *f;
- int lno;
-
- lno = lineno;
- lineno = n->lineno;
-
- if(n->op != ODCLFIELD)
- fatal("structfield: oops %N\n", n);
-
- f = typ(TFIELD);
- f->isddd = n->isddd;
-
- if(n->right != N) {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- if(n->left != N)
- n->left->type = n->type;
- if(n->embedded)
- checkembeddedtype(n->type);
- }
- n->right = N;
-
- f->type = n->type;
- if(f->type == T)
- f->broke = 1;
-
- switch(n->val.ctype) {
- case CTSTR:
- f->note = n->val.u.sval;
- break;
- default:
- yyerror("field annotation must be string");
- // fallthrough
- case CTxxx:
- f->note = nil;
- break;
- }
-
- if(n->left && n->left->op == ONAME) {
- f->nname = n->left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- }
-
- lineno = lno;
- return f;
-}
-
-static uint32 uniqgen;
-
-static void
-checkdupfields(Type *t, char* what)
-{
- int lno;
-
- lno = lineno;
-
- for( ; t; t=t->down) {
- if(t->sym && t->nname && !isblank(t->nname)) {
- if(t->sym->uniqgen == uniqgen) {
- lineno = t->nname->lineno;
- yyerror("duplicate %s %s", what, t->sym->name);
- } else
- t->sym->uniqgen = uniqgen;
- }
- }
-
- lineno = lno;
-}
-
-/*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
-Type*
-tostruct(NodeList *l)
-{
- Type *t, *f, **tp;
- t = typ(TSTRUCT);
-
- for(tp = &t->type; l; l=l->next) {
- f = structfield(l->n);
-
- *tp = f;
- tp = &f->down;
- }
-
- for(f=t->type; f && !t->broke; f=f->down)
- if(f->broke)
- t->broke = 1;
-
- uniqgen++;
- checkdupfields(t->type, "field");
-
- if (!t->broke)
- checkwidth(t);
-
- return t;
-}
-
-static Type*
-tofunargs(NodeList *l)
-{
- Type *t, *f, **tp;
-
- t = typ(TSTRUCT);
- t->funarg = 1;
-
- for(tp = &t->type; l; l=l->next) {
- f = structfield(l->n);
- f->funarg = 1;
-
- // esc.c needs to find f given a PPARAM to add the tag.
- if(l->n->left && l->n->left->class == PPARAM)
- l->n->left->paramfld = f;
-
- *tp = f;
- tp = &f->down;
- }
-
- for(f=t->type; f && !t->broke; f=f->down)
- if(f->broke)
- t->broke = 1;
-
- return t;
-}
-
-static Type*
-interfacefield(Node *n)
-{
- Type *f;
- int lno;
-
- lno = lineno;
- lineno = n->lineno;
-
- if(n->op != ODCLFIELD)
- fatal("interfacefield: oops %N\n", n);
-
- if (n->val.ctype != CTxxx)
- yyerror("interface method cannot have annotation");
-
- f = typ(TFIELD);
- f->isddd = n->isddd;
-
- if(n->right != N) {
- if(n->left != N) {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n->type = typ(TINTERMETH);
- n->type->nname = n->right;
- n->left->type = n->type;
- queuemethod(n);
-
- if(n->left->op == ONAME) {
- f->nname = n->left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- }
-
- } else {
-
- typecheck(&n->right, Etype);
- n->type = n->right->type;
-
- if(n->embedded)
- checkembeddedtype(n->type);
-
- if(n->type)
- switch(n->type->etype) {
- case TINTER:
- break;
- case TFORW:
- yyerror("interface type loop involving %T", n->type);
- f->broke = 1;
- break;
- default:
- yyerror("interface contains embedded non-interface %T", n->type);
- f->broke = 1;
- break;
- }
- }
- }
-
- n->right = N;
-
- f->type = n->type;
- if(f->type == T)
- f->broke = 1;
-
- lineno = lno;
- return f;
-}
-
-Type*
-tointerface(NodeList *l)
-{
- Type *t, *f, **tp, *t1;
-
- t = typ(TINTER);
-
- tp = &t->type;
- for(; l; l=l->next) {
- f = interfacefield(l->n);
-
- if (l->n->left == N && f->type->etype == TINTER) {
- // embedded interface, inline methods
- for(t1=f->type->type; t1; t1=t1->down) {
- f = typ(TFIELD);
- f->type = t1->type;
- f->broke = t1->broke;
- f->sym = t1->sym;
- if(f->sym)
- f->nname = newname(f->sym);
- *tp = f;
- tp = &f->down;
- }
- } else {
- *tp = f;
- tp = &f->down;
- }
- }
-
- for(f=t->type; f && !t->broke; f=f->down)
- if(f->broke)
- t->broke = 1;
-
- uniqgen++;
- checkdupfields(t->type, "method");
- t = sortinter(t);
- checkwidth(t);
-
- return t;
-}
-
-Node*
-embedded(Sym *s, Pkg *pkg)
-{
- Node *n;
- char *name;
-
- // Names sometimes have disambiguation junk
- // appended after a center dot. Discard it when
- // making the name for the embedded struct field.
- enum { CenterDot = 0xB7 };
- name = s->name;
- if(utfrune(s->name, CenterDot)) {
- name = strdup(s->name);
- *utfrune(name, CenterDot) = 0;
- }
-
- if(exportname(name))
- n = newname(lookup(name));
- else if(s->pkg == builtinpkg)
- // The name of embedded builtins belongs to pkg.
- n = newname(pkglookup(name, pkg));
- else
- n = newname(pkglookup(name, s->pkg));
- n = nod(ODCLFIELD, n, oldname(s));
- n->embedded = 1;
- return n;
-}
-
-/*
- * check that the list of declarations is either all anonymous or all named
- */
-
-static Node*
-findtype(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return l->n->right;
- return N;
-}
-
-NodeList*
-checkarglist(NodeList *all, int input)
-{
- int named;
- Node *n, *t, *nextt;
- NodeList *l;
-
- named = 0;
- for(l=all; l; l=l->next) {
- if(l->n->op == OKEY) {
- named = 1;
- break;
- }
- }
- if(named) {
- n = N;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->op != OKEY && n->sym == S) {
- yyerror("mixed named and unnamed function parameters");
- break;
- }
- }
- if(l == nil && n != N && n->op != OKEY)
- yyerror("final function parameter must have type");
- }
-
- nextt = nil;
- for(l=all; l; l=l->next) {
- // can cache result from findtype to avoid
- // quadratic behavior here, but unlikely to matter.
- n = l->n;
- if(named) {
- if(n->op == OKEY) {
- t = n->right;
- n = n->left;
- nextt = nil;
- } else {
- if(nextt == nil)
- nextt = findtype(l);
- t = nextt;
- }
- } else {
- t = n;
- n = N;
- }
-
- // during import l->n->op is OKEY, but l->n->left->sym == S
- // means it was a '?', not that it was
- // a lone type This doesn't matter for the exported
- // declarations, which are parsed by rules that don't
- // use checkargs, but can happen for func literals in
- // the inline bodies.
- // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
- if(importpkg && n->sym == S)
- n = N;
-
- if(n != N && n->sym == S) {
- t = n;
- n = N;
- }
- if(n != N)
- n = newname(n->sym);
- n = nod(ODCLFIELD, n, t);
- if(n->right != N && n->right->op == ODDD) {
- if(!input)
- yyerror("cannot use ... in output argument list");
- else if(l->next != nil)
- yyerror("can only use ... as final argument in list");
- n->right->op = OTARRAY;
- n->right->right = n->right->left;
- n->right->left = N;
- n->isddd = 1;
- if(n->left != N)
- n->left->isddd = 1;
- }
- l->n = n;
- }
- return all;
-}
-
-
-Node*
-fakethis(void)
-{
- Node *n;
-
- n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
- return n;
-}
-
-/*
- * Is this field a method on an interface?
- * Those methods have an anonymous
- * *struct{} as the receiver.
- * (See fakethis above.)
- */
-int
-isifacemethod(Type *f)
-{
- Type *rcvr;
- Type *t;
-
- rcvr = getthisx(f)->type;
- if(rcvr->sym != S)
- return 0;
- t = rcvr->type;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t->sym != S || t->etype != TSTRUCT || t->type != T)
- return 0;
- return 1;
-}
-
-/*
- * turn a parsed function declaration
- * into a type
- */
-Type*
-functype(Node *this, NodeList *in, NodeList *out)
-{
- Type *t;
- NodeList *rcvr;
- Sym *s;
-
- t = typ(TFUNC);
-
- rcvr = nil;
- if(this)
- rcvr = list1(this);
- t->type = tofunargs(rcvr);
- t->type->down = tofunargs(out);
- t->type->down->down = tofunargs(in);
-
- uniqgen++;
- checkdupfields(t->type->type, "argument");
- checkdupfields(t->type->down->type, "argument");
- checkdupfields(t->type->down->down->type, "argument");
-
- if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
- t->broke = 1;
-
- if(this)
- t->thistuple = 1;
- t->outtuple = count(out);
- t->intuple = count(in);
- t->outnamed = 0;
- if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) {
- s = out->n->left->orig->sym;
- if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
- t->outnamed = 1;
- }
-
- return t;
-}
-
-Sym*
-methodsym(Sym *nsym, Type *t0, int iface)
-{
- Sym *s;
- char *p;
- Type *t;
- char *suffix;
- Pkg *spkg;
- static Pkg *toppkg;
-
- t = t0;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S && isptr[t->etype]) {
- t = t->type;
- if(t == T)
- goto bad;
- s = t->sym;
- }
- spkg = nil;
- if(s != S)
- spkg = s->pkg;
-
- // if t0 == *t and t0 has a sym,
- // we want to see *t, not t0, in the method name.
- if(t != t0 && t0->sym)
- t0 = ptrto(t);
-
- suffix = "";
- if(iface) {
- dowidth(t0);
- if(t0->width < types[tptr]->width)
- suffix = "·i";
- }
- if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
- if(t0->sym == S && isptr[t0->etype])
- p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
- else
- p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
- } else {
- if(t0->sym == S && isptr[t0->etype])
- p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
- else
- p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
- }
- if(spkg == nil) {
- if(toppkg == nil)
- toppkg = mkpkg(newstrlit("go"));
- spkg = toppkg;
- }
- s = pkglookup(p, spkg);
- free(p);
- return s;
-
-bad:
- yyerror("illegal receiver type: %T", t0);
- return S;
-}
-
-Node*
-methodname(Node *n, Type *t)
-{
- Sym *s;
-
- s = methodsym(n->sym, t, 0);
- if(s == S)
- return n;
- return newname(s);
-}
-
-Node*
-methodname1(Node *n, Node *t)
-{
- char *star;
- char *p;
-
- star = nil;
- if(t->op == OIND) {
- star = "*";
- t = t->left;
- }
- if(t->sym == S || isblank(n))
- return newname(n->sym);
-
- if(star)
- p = smprint("(%s%S).%S", star, t->sym, n->sym);
- else
- p = smprint("%S.%S", t->sym, n->sym);
-
- if(exportname(t->sym->name))
- n = newname(lookup(p));
- else
- n = newname(pkglookup(p, t->sym->pkg));
- free(p);
- return n;
-}
-
-/*
- * add a method, declared as a function,
- * n is fieldname, pa is base type, t is function type
- */
-void
-addmethod(Sym *sf, Type *t, int local, int nointerface)
-{
- Type *f, *d, *pa;
- Node *n;
-
- // get field sym
- if(sf == S)
- fatal("no method symbol");
-
- // get parent type sym
- pa = getthisx(t)->type; // ptr to this structure
- if(pa == T) {
- yyerror("missing receiver");
- return;
- }
-
- pa = pa->type;
- f = methtype(pa, 1);
- if(f == T) {
- t = pa;
- if(t == T) // rely on typecheck having complained before
- return;
- if(t != T) {
- if(isptr[t->etype]) {
- if(t->sym != S) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- t = t->type;
- }
- if(t->broke) // rely on typecheck having complained before
- return;
- if(t->sym == S) {
- yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
- return;
- }
- if(isptr[t->etype]) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- if(t->etype == TINTER) {
- yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
- return;
- }
- }
- // Should have picked off all the reasons above,
- // but just in case, fall back to generic error.
- yyerror("invalid receiver type %T (%lT / %lT)", pa, pa, t);
- return;
- }
-
- pa = f;
- if(pa->etype == TSTRUCT) {
- for(f=pa->type; f; f=f->down) {
- if(f->sym == sf) {
- yyerror("type %T has both field and method named %S", pa, sf);
- return;
- }
- }
- }
-
- if(local && !pa->local) {
- // defining method on non-local type.
- yyerror("cannot define new methods on non-local type %T", pa);
- return;
- }
-
- n = nod(ODCLFIELD, newname(sf), N);
- n->type = t;
-
- d = T; // last found
- for(f=pa->method; f!=T; f=f->down) {
- d = f;
- if(f->etype != TFIELD)
- fatal("addmethod: not TFIELD: %lT", f);
- if(strcmp(sf->name, f->sym->name) != 0)
- continue;
- if(!eqtype(t, f->type))
- yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
- return;
- }
-
- f = structfield(n);
- f->nointerface = nointerface;
-
- // during import unexported method names should be in the type's package
- if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
- fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
-
- if(d == T)
- pa->method = f;
- else
- d->down = f;
- return;
-}
-
-void
-funccompile(Node *n)
-{
- stksize = BADWIDTH;
- maxarg = 0;
-
- if(n->type == T) {
- if(nerrors == 0)
- fatal("funccompile missing type");
- return;
- }
-
- // assign parameter offsets
- checkwidth(n->type);
-
- if(curfn)
- fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
-
- stksize = 0;
- dclcontext = PAUTO;
- funcdepth = n->funcdepth + 1;
- compile(n);
- curfn = nil;
- funcdepth = 0;
- dclcontext = PEXTERN;
-}
-
-Sym*
-funcsym(Sym *s)
-{
- char *p;
- Sym *s1;
-
- p = smprint("%s·f", s->name);
- s1 = pkglookup(p, s->pkg);
- free(p);
- if(s1->def == N) {
- s1->def = newname(s1);
- s1->def->shortname = newname(s);
- funcsyms = list(funcsyms, s1->def);
- }
- return s1;
-}
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
deleted file mode 100644
index 03df93a3eb..0000000000
--- a/src/cmd/gc/doc.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-Gc is the generic label for the family of Go compilers
-that function as part of the (modified) Plan 9 tool chain. The C compiler
-documentation at
-
- http://plan9.bell-labs.com/sys/doc/comp.pdf (Tools overview)
- http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
-
-gives the overall design of the tool chain. Aside from a few adapted pieces,
-such as the optimizer, the Go compilers are wholly new programs.
-
-The compiler reads in a set of Go files, typically suffixed ".go". They
-must all be part of one package. The output is a single intermediate file
-representing the "binary assembly" of the compiled package, ready as input
-for the linker (6l, etc.).
-
-The generated files contain type information about the symbols exported by
-the package and about types used by symbols imported by the package from
-other packages. It is therefore not necessary when compiling client C of
-package P to read the files of P's dependencies, only the compiled output
-of P.
-
-Command Line
-
-Usage:
- go tool 6g [flags] file...
-The specified files must be Go source files and all part of the same package.
-Substitute 6g with 8g or 5g where appropriate.
-
-Flags:
- -o file
- output file, default file.6 for 6g, etc.
- -pack
- write an archive file rather than an object file
- -e
- normally the compiler quits after 10 errors; -e prints all errors
- -p path
- assume that path is the eventual import path for this code,
- and diagnose any attempt to import a package that depends on it.
- -D path
- treat a relative import as relative to path
- -L
- show entire file path when printing line numbers in errors
- -I dir1 -I dir2
- add dir1 and dir2 to the list of paths to check for imported packages
- -N
- disable optimizations
- -nolocalimports
- disallow local (relative) imports
- -S
- write assembly language text to standard output (code only)
- -S -S
- write assembly language text to standard output (code and data)
- -u
- disallow importing packages not marked as safe; implies -nolocalimports
- -V
- print the compiler version
- -race
- compile with race detection enabled
-
-There are also a number of debugging flags; run the command with no arguments
-to get a usage message.
-
-Compiler Directives
-
-The compiler accepts two compiler directives in the form of // comments at the
-beginning of a line. To distinguish them from non-directive comments, the directives
-require no space between the slashes and the name of the directive. However, since
-they are comments, tools unaware of the directive convention or of a particular
-directive can skip over a directive like any other comment.
-
- //line path/to/file:linenumber
-
-The //line directive specifies that the source line that follows should be recorded
-as having come from the given file path and line number. Successive lines are
-recorded using increasing line numbers, until the next directive. This directive
-typically appears in machine-generated code, so that compilers and debuggers
-will show lines in the original input to the generator.
-
- //go:noescape
-
-The //go:noescape directive specifies that the next declaration in the file, which
-must be a func without a body (meaning that it has an implementation not written
-in Go) does not allow any of the pointers passed as arguments to escape into the
-heap or into the values returned from the function. This information can be used as
-during the compiler's escape analysis of Go code calling the function.
-*/
-package main
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
deleted file mode 100644
index 5b09c0b7fb..0000000000
--- a/src/cmd/gc/esc.c
+++ /dev/null
@@ -1,1342 +0,0 @@
-// 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.
-
-// Escape analysis.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// Run analysis on minimal sets of mutually recursive functions
-// or single non-recursive functions, bottom up.
-//
-// Finding these sets is finding strongly connected components
-// in the static call graph. The algorithm for doing that is taken
-// from Sedgewick, Algorithms, Second Edition, p. 482, with two
-// adaptations.
-//
-// First, a hidden closure function (n->curfn != N) cannot be the
-// root of a connected component. Refusing to use it as a root
-// forces it into the component of the function in which it appears.
-// The analysis assumes that closures and the functions in which they
-// appear are analyzed together, so that the aliasing between their
-// variables can be modeled more precisely.
-//
-// Second, each function becomes two virtual nodes in the graph,
-// with numbers n and n+1. We record the function's node number as n
-// but search from node n+1. If the search tells us that the component
-// number (min) is n+1, we know that this is a trivial component: one function
-// plus its closures. If the search tells us that the component number is
-// n, then there was a path from node n+1 back to node n, meaning that
-// the function set is mutually recursive. The escape analysis can be
-// more precise when analyzing a single non-recursive function than
-// when analyzing a set of mutually recursive functions.
-
-static NodeList *stack;
-static uint32 visitgen;
-static uint32 visit(Node*);
-static uint32 visitcode(Node*, uint32);
-static uint32 visitcodelist(NodeList*, uint32);
-
-static void analyze(NodeList*, int);
-
-enum
-{
- EscFuncUnknown = 0,
- EscFuncPlanned,
- EscFuncStarted,
- EscFuncTagged,
-};
-
-void
-escapes(NodeList *all)
-{
- NodeList *l;
-
- for(l=all; l; l=l->next)
- l->n->walkgen = 0;
-
- visitgen = 0;
- for(l=all; l; l=l->next)
- if(l->n->op == ODCLFUNC && l->n->curfn == N)
- visit(l->n);
-
- for(l=all; l; l=l->next)
- l->n->walkgen = 0;
-}
-
-static uint32
-visit(Node *n)
-{
- uint32 min, recursive;
- NodeList *l, *block;
-
- if(n->walkgen > 0) {
- // already visited
- return n->walkgen;
- }
-
- visitgen++;
- n->walkgen = visitgen;
- visitgen++;
- min = visitgen;
-
- l = mal(sizeof *l);
- l->next = stack;
- l->n = n;
- stack = l;
- min = visitcodelist(n->nbody, min);
- if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
- // This node is the root of a strongly connected component.
-
- // The original min passed to visitcodelist was n->walkgen+1.
- // If visitcodelist found its way back to n->walkgen, then this
- // block is a set of mutually recursive functions.
- // Otherwise it's just a lone function that does not recurse.
- recursive = min == n->walkgen;
-
- // Remove connected component from stack.
- // Mark walkgen so that future visits return a large number
- // so as not to affect the caller's min.
- block = stack;
- for(l=stack; l->n != n; l=l->next)
- l->n->walkgen = (uint32)~0U;
- n->walkgen = (uint32)~0U;
- stack = l->next;
- l->next = nil;
-
- // Run escape analysis on this set of functions.
- analyze(block, recursive);
- }
-
- return min;
-}
-
-static uint32
-visitcodelist(NodeList *l, uint32 min)
-{
- for(; l; l=l->next)
- min = visitcode(l->n, min);
- return min;
-}
-
-static uint32
-visitcode(Node *n, uint32 min)
-{
- Node *fn;
- uint32 m;
-
- if(n == N)
- return min;
-
- min = visitcodelist(n->ninit, min);
- min = visitcode(n->left, min);
- min = visitcode(n->right, min);
- min = visitcodelist(n->list, min);
- min = visitcode(n->ntest, min);
- min = visitcode(n->nincr, min);
- min = visitcodelist(n->nbody, min);
- min = visitcodelist(n->nelse, min);
- min = visitcodelist(n->rlist, min);
-
- if(n->op == OCALLFUNC || n->op == OCALLMETH) {
- fn = n->left;
- if(n->op == OCALLMETH)
- fn = n->left->right->sym->def;
- if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn)
- if((m = visit(fn->defn)) < min)
- min = m;
- }
-
- if(n->op == OCLOSURE)
- if((m = visit(n->closure)) < min)
- min = m;
-
- return min;
-}
-
-// An escape analysis pass for a set of functions.
-//
-// First escfunc, esc and escassign recurse over the ast of each
-// function to dig out flow(dst,src) edges between any
-// pointer-containing nodes and store them in dst->escflowsrc. For
-// variables assigned to a variable in an outer scope or used as a
-// return value, they store a flow(theSink, src) edge to a fake node
-// 'the Sink'. For variables referenced in closures, an edge
-// flow(closure, &var) is recorded and the flow of a closure itself to
-// an outer scope is tracked the same way as other variables.
-//
-// Then escflood walks the graph starting at theSink and tags all
-// variables of it can reach an & node as escaping and all function
-// parameters it can reach as leaking.
-//
-// If a value's address is taken but the address does not escape,
-// then the value can stay on the stack. If the value new(T) does
-// not escape, then new(T) can be rewritten into a stack allocation.
-// The same is true of slice literals.
-//
-// If optimizations are disabled (-N), this code is not used.
-// Instead, the compiler assumes that any value whose address
-// is taken without being immediately dereferenced
-// needs to be moved to the heap, and new(T) and slice
-// literals are always real allocations.
-
-typedef struct EscState EscState;
-
-static void escfunc(EscState*, Node *func);
-static void esclist(EscState*, NodeList *l, Node *up);
-static void esc(EscState*, Node *n, Node *up);
-static void escloopdepthlist(EscState*, NodeList *l);
-static void escloopdepth(EscState*, Node *n);
-static void escassign(EscState*, Node *dst, Node *src);
-static void esccall(EscState*, Node*, Node *up);
-static void escflows(EscState*, Node *dst, Node *src);
-static void escflood(EscState*, Node *dst);
-static void escwalk(EscState*, int level, Node *dst, Node *src);
-static void esctag(EscState*, Node *func);
-
-struct EscState {
- // Fake node that all
- // - return values and output variables
- // - parameters on imported functions not marked 'safe'
- // - assignments to global variables
- // flow to.
- Node theSink;
-
- // If an analyzed function is recorded to return
- // pieces obtained via indirection from a parameter,
- // and later there is a call f(x) to that function,
- // we create a link funcParam <- x to record that fact.
- // The funcParam node is handled specially in escflood.
- Node funcParam;
-
- NodeList* dsts; // all dst nodes
- int loopdepth; // for detecting nested loop scopes
- int pdepth; // for debug printing in recursions.
- int dstcount, edgecount; // diagnostic
- NodeList* noesc; // list of possible non-escaping nodes, for printing
- int recursive; // recursive function or group of mutually recursive functions.
-};
-
-static Strlit *tags[16];
-
-static Strlit*
-mktag(int mask)
-{
- Strlit *s;
- char buf[40];
-
- switch(mask&EscMask) {
- case EscNone:
- case EscReturn:
- break;
- default:
- fatal("escape mktag");
- }
-
- mask >>= EscBits;
-
- if(mask < nelem(tags) && tags[mask] != nil)
- return tags[mask];
-
- snprint(buf, sizeof buf, "esc:0x%x", mask);
- s = newstrlit(buf);
- if(mask < nelem(tags))
- tags[mask] = s;
- return s;
-}
-
-static int
-parsetag(Strlit *note)
-{
- int em;
-
- if(note == nil)
- return EscUnknown;
- if(strncmp(note->s, "esc:", 4) != 0)
- return EscUnknown;
- em = atoi(note->s + 4);
- if (em == 0)
- return EscNone;
- return EscReturn | (em << EscBits);
-}
-
-static void
-analyze(NodeList *all, int recursive)
-{
- NodeList *l;
- EscState es, *e;
-
- memset(&es, 0, sizeof es);
- e = &es;
- e->theSink.op = ONAME;
- e->theSink.orig = &e->theSink;
- e->theSink.class = PEXTERN;
- e->theSink.sym = lookup(".sink");
- e->theSink.escloopdepth = -1;
- e->recursive = recursive;
-
- e->funcParam.op = ONAME;
- e->funcParam.orig = &e->funcParam;
- e->funcParam.class = PAUTO;
- e->funcParam.sym = lookup(".param");
- e->funcParam.escloopdepth = 10000000;
-
- for(l=all; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- l->n->esc = EscFuncPlanned;
-
- // flow-analyze functions
- for(l=all; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- escfunc(e, l->n);
-
- // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
-
- // visit the upstream of each dst, mark address nodes with
- // addrescapes, mark parameters unsafe
- for(l = e->dsts; l; l=l->next)
- escflood(e, l->n);
-
- // for all top level functions, tag the typenodes corresponding to the param nodes
- for(l=all; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- esctag(e, l->n);
-
- if(debug['m']) {
- for(l=e->noesc; l; l=l->next)
- if(l->n->esc == EscNone)
- warnl(l->n->lineno, "%S %hN does not escape",
- (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
- l->n);
- }
-}
-
-
-static void
-escfunc(EscState *e, Node *func)
-{
- Node *savefn;
- NodeList *ll;
- int saveld;
-
-// print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
-
- if(func->esc != 1)
- fatal("repeat escfunc %N", func->nname);
- func->esc = EscFuncStarted;
-
- saveld = e->loopdepth;
- e->loopdepth = 1;
- savefn = curfn;
- curfn = func;
-
- for(ll=curfn->dcl; ll; ll=ll->next) {
- if(ll->n->op != ONAME)
- continue;
- switch (ll->n->class) {
- case PPARAMOUT:
- // out params are in a loopdepth between the sink and all local variables
- ll->n->escloopdepth = 0;
- break;
- case PPARAM:
- ll->n->escloopdepth = 1;
- if(ll->n->type && !haspointers(ll->n->type))
- break;
- if(curfn->nbody == nil && !curfn->noescape)
- ll->n->esc = EscHeap;
- else
- ll->n->esc = EscNone; // prime for escflood later
- e->noesc = list(e->noesc, ll->n);
- break;
- }
- }
-
- // in a mutually recursive group we lose track of the return values
- if(e->recursive)
- for(ll=curfn->dcl; ll; ll=ll->next)
- if(ll->n->op == ONAME && ll->n->class == PPARAMOUT)
- escflows(e, &e->theSink, ll->n);
-
- escloopdepthlist(e, curfn->nbody);
- esclist(e, curfn->nbody, curfn);
- curfn = savefn;
- e->loopdepth = saveld;
-}
-
-// Mark labels that have no backjumps to them as not increasing e->loopdepth.
-// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
-// and set it to one of the following two. Then in esc we'll clear it again.
-static Label looping;
-static Label nonlooping;
-
-static void
-escloopdepthlist(EscState *e, NodeList *l)
-{
- for(; l; l=l->next)
- escloopdepth(e, l->n);
-}
-
-static void
-escloopdepth(EscState *e, Node *n)
-{
- if(n == N)
- return;
-
- escloopdepthlist(e, n->ninit);
-
- switch(n->op) {
- case OLABEL:
- if(!n->left || !n->left->sym)
- fatal("esc:label without label: %+N", n);
- // Walk will complain about this label being already defined, but that's not until
- // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
- // if(n->left->sym->label != nil)
- // fatal("escape analysis messed up analyzing label: %+N", n);
- n->left->sym->label = &nonlooping;
- break;
- case OGOTO:
- if(!n->left || !n->left->sym)
- fatal("esc:goto without label: %+N", n);
- // If we come past one that's uninitialized, this must be a (harmless) forward jump
- // but if it's set to nonlooping the label must have preceded this goto.
- if(n->left->sym->label == &nonlooping)
- n->left->sym->label = &looping;
- break;
- }
-
- escloopdepth(e, n->left);
- escloopdepth(e, n->right);
- escloopdepthlist(e, n->list);
- escloopdepth(e, n->ntest);
- escloopdepth(e, n->nincr);
- escloopdepthlist(e, n->nbody);
- escloopdepthlist(e, n->nelse);
- escloopdepthlist(e, n->rlist);
-
-}
-
-static void
-esclist(EscState *e, NodeList *l, Node *up)
-{
- for(; l; l=l->next)
- esc(e, l->n, up);
-}
-
-static void
-esc(EscState *e, Node *n, Node *up)
-{
- int lno;
- NodeList *ll, *lr;
- Node *a, *v;
-
- if(n == N)
- return;
-
- lno = setlineno(n);
-
- // ninit logically runs at a different loopdepth than the rest of the for loop.
- esclist(e, n->ninit, n);
-
- if(n->op == OFOR || n->op == ORANGE)
- e->loopdepth++;
-
- // type switch variables have no ODCL.
- // process type switch as declaration.
- // must happen before processing of switch body,
- // so before recursion.
- if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
- for(ll=n->list; ll; ll=ll->next) { // cases
- // ll->n->nname is the variable per case
- if(ll->n->nname)
- ll->n->nname->escloopdepth = e->loopdepth;
- }
- }
-
- esc(e, n->left, n);
- esc(e, n->right, n);
- esc(e, n->ntest, n);
- esc(e, n->nincr, n);
- esclist(e, n->nbody, n);
- esclist(e, n->nelse, n);
- esclist(e, n->list, n);
- esclist(e, n->rlist, n);
-
- if(n->op == OFOR || n->op == ORANGE)
- e->loopdepth--;
-
- if(debug['m'] > 1)
- print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
- (curfn && curfn->nname) ? curfn->nname->sym : S, n);
-
- switch(n->op) {
- case ODCL:
- // Record loop depth at declaration.
- if(n->left)
- n->left->escloopdepth = e->loopdepth;
- break;
-
- case OLABEL:
- if(n->left->sym->label == &nonlooping) {
- if(debug['m'] > 1)
- print("%L:%N non-looping label\n", lineno, n);
- } else if(n->left->sym->label == &looping) {
- if(debug['m'] > 1)
- print("%L: %N looping label\n", lineno, n);
- e->loopdepth++;
- }
- // See case OLABEL in escloopdepth above
- // else if(n->left->sym->label == nil)
- // fatal("escape analysis missed or messed up a label: %+N", n);
-
- n->left->sym->label = nil;
- break;
-
- case ORANGE:
- // Everything but fixed array is a dereference.
- if(isfixedarray(n->type) && n->list && n->list->next)
- escassign(e, n->list->next->n, n->right);
- break;
-
- case OSWITCH:
- if(n->ntest && n->ntest->op == OTYPESW) {
- for(ll=n->list; ll; ll=ll->next) { // cases
- // ntest->right is the argument of the .(type),
- // ll->n->nname is the variable per case
- escassign(e, ll->n->nname, n->ntest->right);
- }
- }
- break;
-
- case OAS:
- case OASOP:
- // Filter out the following special case.
- //
- // func (b *Buffer) Foo() {
- // n, m := ...
- // b.buf = b.buf[n:m]
- // }
- //
- // This assignment is a no-op for escape analysis,
- // it does not store any new pointers into b that were not already there.
- // However, without this special case b will escape, because we assign to OIND/ODOTPTR.
- if((n->left->op == OIND || n->left->op == ODOTPTR) && n->left->left->op == ONAME && // dst is ONAME dereference
- (n->right->op == OSLICE || n->right->op == OSLICE3 || n->right->op == OSLICESTR) && // src is slice operation
- (n->right->left->op == OIND || n->right->left->op == ODOTPTR) && n->right->left->left->op == ONAME && // slice is applied to ONAME dereference
- n->left->left == n->right->left->left) { // dst and src reference the same base ONAME
- // Here we also assume that the statement will not contain calls,
- // that is, that order will move any calls to init.
- // Otherwise base ONAME value could change between the moments
- // when we evaluate it for dst and for src.
- //
- // Note, this optimization does not apply to OSLICEARR,
- // because it does introduce a new pointer into b that was not already there
- // (pointer to b itself). After such assignment, if b contents escape,
- // b escapes as well. If we ignore such OSLICEARR, we will conclude
- // that b does not escape when b contents do.
- if(debug['m']) {
- warnl(n->lineno, "%S ignoring self-assignment to %hN",
- (n->curfn && n->curfn->nname) ? n->curfn->nname->sym : S, n->left);
- }
- break;
- }
- escassign(e, n->left, n->right);
- break;
-
- case OAS2: // x,y = a,b
- if(count(n->list) == count(n->rlist))
- for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
- escassign(e, ll->n, lr->n);
- break;
-
- case OAS2RECV: // v, ok = <-ch
- case OAS2MAPR: // v, ok = m[k]
- case OAS2DOTTYPE: // v, ok = x.(type)
- escassign(e, n->list->n, n->rlist->n);
- break;
-
- case OSEND: // ch <- x
- escassign(e, &e->theSink, n->right);
- break;
-
- case ODEFER:
- if(e->loopdepth == 1) // top level
- break;
- // arguments leak out of scope
- // TODO: leak to a dummy node instead
- // fallthrough
- case OPROC:
- // go f(x) - f and x escape
- escassign(e, &e->theSink, n->left->left);
- escassign(e, &e->theSink, n->left->right); // ODDDARG for call
- for(ll=n->left->list; ll; ll=ll->next)
- escassign(e, &e->theSink, ll->n);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- case OCALLINTER:
- esccall(e, n, up);
- break;
-
- case OAS2FUNC: // x,y = f()
- // esccall already done on n->rlist->n. tie it's escretval to n->list
- lr=n->rlist->n->escretval;
- for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next)
- escassign(e, ll->n, lr->n);
- if(lr || ll)
- fatal("esc oas2func");
- break;
-
- case ORETURN:
- ll=n->list;
- if(count(n->list) == 1 && curfn->type->outtuple > 1) {
- // OAS2FUNC in disguise
- // esccall already done on n->list->n
- // tie n->list->n->escretval to curfn->dcl PPARAMOUT's
- ll = n->list->n->escretval;
- }
-
- for(lr = curfn->dcl; lr && ll; lr=lr->next) {
- if (lr->n->op != ONAME || lr->n->class != PPARAMOUT)
- continue;
- escassign(e, lr->n, ll->n);
- ll = ll->next;
- }
- if (ll != nil)
- fatal("esc return list");
- break;
-
- case OPANIC:
- // Argument could leak through recover.
- escassign(e, &e->theSink, n->left);
- break;
-
- case OAPPEND:
- if(!n->isddd)
- for(ll=n->list->next; ll; ll=ll->next)
- escassign(e, &e->theSink, ll->n); // lose track of assign to dereference
- break;
-
- case OCONV:
- case OCONVNOP:
- case OCONVIFACE:
- escassign(e, n, n->left);
- break;
-
- case OARRAYLIT:
- if(isslice(n->type)) {
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- n->escloopdepth = e->loopdepth;
- // Values make it to memory, lose track.
- for(ll=n->list; ll; ll=ll->next)
- escassign(e, &e->theSink, ll->n->right);
- } else {
- // Link values to array.
- for(ll=n->list; ll; ll=ll->next)
- escassign(e, n, ll->n->right);
- }
- break;
-
- case OSTRUCTLIT:
- // Link values to struct.
- for(ll=n->list; ll; ll=ll->next)
- escassign(e, n, ll->n->right);
- break;
-
- case OPTRLIT:
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- n->escloopdepth = e->loopdepth;
- // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
- escassign(e, n, n->left);
- break;
-
- case OCALLPART:
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- n->escloopdepth = e->loopdepth;
- // Contents make it to memory, lose track.
- escassign(e, &e->theSink, n->left);
- break;
-
- case OMAPLIT:
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- n->escloopdepth = e->loopdepth;
- // Keys and values make it to memory, lose track.
- for(ll=n->list; ll; ll=ll->next) {
- escassign(e, &e->theSink, ll->n->left);
- escassign(e, &e->theSink, ll->n->right);
- }
- break;
-
- case OCLOSURE:
- // Link addresses of captured variables to closure.
- for(ll=n->cvars; ll; ll=ll->next) {
- v = ll->n;
- if(v->op == OXXX) // unnamed out argument; see dcl.c:/^funcargs
- continue;
- a = v->closure;
- if(!v->byval) {
- a = nod(OADDR, a, N);
- a->lineno = v->lineno;
- a->escloopdepth = e->loopdepth;
- typecheck(&a, Erv);
- }
- escassign(e, n, a);
- }
- // fallthrough
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case ONEW:
- case OARRAYRUNESTR:
- case OARRAYBYTESTR:
- case OSTRARRAYRUNE:
- case OSTRARRAYBYTE:
- case ORUNESTR:
- n->escloopdepth = e->loopdepth;
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- break;
-
- case OADDSTR:
- n->escloopdepth = e->loopdepth;
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- // Arguments of OADDSTR do not escape.
- break;
-
- case OADDR:
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- // current loop depth is an upper bound on actual loop depth
- // of addressed value.
- n->escloopdepth = e->loopdepth;
- // for &x, use loop depth of x if known.
- // it should always be known, but if not, be conservative
- // and keep the current loop depth.
- if(n->left->op == ONAME) {
- switch(n->left->class) {
- case PAUTO:
- if(n->left->escloopdepth != 0)
- n->escloopdepth = n->left->escloopdepth;
- break;
- case PPARAM:
- case PPARAMOUT:
- // PPARAM is loop depth 1 always.
- // PPARAMOUT is loop depth 0 for writes
- // but considered loop depth 1 for address-of,
- // so that writing the address of one result
- // to another (or the same) result makes the
- // first result move to the heap.
- n->escloopdepth = 1;
- break;
- }
- }
- break;
- }
-
- lineno = lno;
-}
-
-// Assert that expr somehow gets assigned to dst, if non nil. for
-// dst==nil, any name node expr still must be marked as being
-// evaluated in curfn. For expr==nil, dst must still be examined for
-// evaluations inside it (e.g *f(x) = y)
-static void
-escassign(EscState *e, Node *dst, Node *src)
-{
- int lno;
- NodeList *ll;
-
- if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
- return;
-
- if(debug['m'] > 1)
- print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
- (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
-
- setlineno(dst);
-
- // Analyze lhs of assignment.
- // Replace dst with e->theSink if we can't track it.
- switch(dst->op) {
- default:
- dump("dst", dst);
- fatal("escassign: unexpected dst");
-
- case OARRAYLIT:
- case OCLOSURE:
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case OMAPLIT:
- case OSTRUCTLIT:
- case OPTRLIT:
- case OCALLPART:
- break;
-
- case ONAME:
- if(dst->class == PEXTERN)
- dst = &e->theSink;
- break;
- case ODOT: // treat "dst.x = src" as "dst = src"
- escassign(e, dst->left, src);
- return;
- case OINDEX:
- if(isfixedarray(dst->left->type)) {
- escassign(e, dst->left, src);
- return;
- }
- dst = &e->theSink; // lose track of dereference
- break;
- case OIND:
- case ODOTPTR:
- dst = &e->theSink; // lose track of dereference
- break;
- case OINDEXMAP:
- // lose track of key and value
- escassign(e, &e->theSink, dst->right);
- dst = &e->theSink;
- break;
- }
-
- lno = setlineno(src);
- e->pdepth++;
-
- switch(src->op) {
- case OADDR: // dst = &x
- case OIND: // dst = *x
- case ODOTPTR: // dst = (*x).f
- case ONAME:
- case OPARAM:
- case ODDDARG:
- case OPTRLIT:
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case OARRAYRUNESTR:
- case OARRAYBYTESTR:
- case OSTRARRAYRUNE:
- case OSTRARRAYBYTE:
- case OADDSTR:
- case ONEW:
- case OCLOSURE:
- case OCALLPART:
- case ORUNESTR:
- escflows(e, dst, src);
- break;
-
- case OCALLMETH:
- case OCALLFUNC:
- case OCALLINTER:
- // Flowing multiple returns to a single dst happens when
- // analyzing "go f(g())": here g() flows to sink (issue 4529).
- for(ll=src->escretval; ll; ll=ll->next)
- escflows(e, dst, ll->n);
- break;
-
- case ODOT:
- // A non-pointer escaping from a struct does not concern us.
- if(src->type && !haspointers(src->type))
- break;
- // fallthrough
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
- // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
- case ODOTTYPE:
- case ODOTTYPE2:
- case OSLICE:
- case OSLICE3:
- case OSLICEARR:
- case OSLICE3ARR:
- case OSLICESTR:
- // Conversions, field access, slice all preserve the input value.
- escassign(e, dst, src->left);
- break;
-
- case OAPPEND:
- // Append returns first argument.
- escassign(e, dst, src->list->n);
- break;
-
- case OINDEX:
- // Index of array preserves input value.
- if(isfixedarray(src->left->type))
- escassign(e, dst, src->left);
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- case OMUL:
- case ODIV:
- case OMOD:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- case OPLUS:
- case OMINUS:
- case OCOM:
- // Might be pointer arithmetic, in which case
- // the operands flow into the result.
- // TODO(rsc): Decide what the story is here. This is unsettling.
- escassign(e, dst, src->left);
- escassign(e, dst, src->right);
- break;
- }
-
- e->pdepth--;
- lineno = lno;
-}
-
-static int
-escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
-{
- int em, em0;
-
- em = parsetag(note);
-
- if(em == EscUnknown) {
- escassign(e, &e->theSink, src);
- return em;
- }
-
- if(em == EscNone)
- return em;
-
- // If content inside parameter (reached via indirection)
- // escapes back to results, mark as such.
- if(em & EscContentEscapes)
- escassign(e, &e->funcParam, src);
-
- em0 = em;
- for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next)
- if(em & 1)
- escassign(e, dsts->n, src);
-
- if (em != 0 && dsts == nil)
- fatal("corrupt esc tag %Z or messed up escretval list\n", note);
- return em0;
-}
-
-// This is a bit messier than fortunate, pulled out of esc's big
-// switch for clarity. We either have the paramnodes, which may be
-// connected to other things through flows or we have the parameter type
-// nodes, which may be marked "noescape". Navigating the ast is slightly
-// different for methods vs plain functions and for imported vs
-// this-package
-static void
-esccall(EscState *e, Node *n, Node *up)
-{
- NodeList *ll, *lr;
- Node *a, *fn, *src;
- Type *t, *fntype;
- char buf[40];
- int i;
-
- fn = N;
- switch(n->op) {
- default:
- fatal("esccall");
-
- case OCALLFUNC:
- fn = n->left;
- fntype = fn->type;
- break;
-
- case OCALLMETH:
- fn = n->left->right->sym->def;
- if(fn)
- fntype = fn->type;
- else
- fntype = n->left->type;
- break;
-
- case OCALLINTER:
- fntype = n->left->type;
- break;
- }
-
- ll = n->list;
- if(n->list != nil && n->list->next == nil) {
- a = n->list->n;
- if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
- ll = a->escretval;
- }
-
- if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
- // function in same mutually recursive group. Incorporate into flow graph.
-// print("esc local fn: %N\n", fn->ntype);
- if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
- fatal("graph inconsistency");
-
- // set up out list on this call node
- for(lr=fn->ntype->rlist; lr; lr=lr->next)
- n->escretval = list(n->escretval, lr->n->left); // type.rlist -> dclfield -> ONAME (PPARAMOUT)
-
- // Receiver.
- if(n->op != OCALLFUNC)
- escassign(e, fn->ntype->left->left, n->left->left);
-
- for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
- src = ll->n;
- if(lr->n->isddd && !n->isddd) {
- // Introduce ODDDARG node to represent ... allocation.
- src = nod(ODDDARG, N, N);
- src->type = typ(TARRAY);
- src->type->type = lr->n->type->type;
- src->type->bound = count(ll);
- src->type = ptrto(src->type); // make pointer so it will be tracked
- src->escloopdepth = e->loopdepth;
- src->lineno = n->lineno;
- src->esc = EscNone; // until we find otherwise
- e->noesc = list(e->noesc, src);
- n->right = src;
- }
- if(lr->n->left != N)
- escassign(e, lr->n->left, src);
- if(src != ll->n)
- break;
- }
- // "..." arguments are untracked
- for(; ll; ll=ll->next)
- escassign(e, &e->theSink, ll->n);
-
- return;
- }
-
- // Imported or completely analyzed function. Use the escape tags.
- if(n->escretval != nil)
- fatal("esc already decorated call %+N\n", n);
-
- // set up out list on this call node with dummy auto ONAMES in the current (calling) function.
- i = 0;
- for(t=getoutargx(fntype)->type; t; t=t->down) {
- src = nod(ONAME, N, N);
- snprint(buf, sizeof buf, ".dum%d", i++);
- src->sym = lookup(buf);
- src->type = t->type;
- src->class = PAUTO;
- src->curfn = curfn;
- src->escloopdepth = e->loopdepth;
- src->used = 1;
- src->lineno = n->lineno;
- n->escretval = list(n->escretval, src);
- }
-
-// print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
-
- // Receiver.
- if(n->op != OCALLFUNC) {
- t = getthisx(fntype)->type;
- src = n->left->left;
- if(haspointers(t->type))
- escassignfromtag(e, t->note, n->escretval, src);
- }
-
- for(t=getinargx(fntype)->type; ll; ll=ll->next) {
- src = ll->n;
- if(t->isddd && !n->isddd) {
- // Introduce ODDDARG node to represent ... allocation.
- src = nod(ODDDARG, N, N);
- src->escloopdepth = e->loopdepth;
- src->lineno = n->lineno;
- src->type = typ(TARRAY);
- src->type->type = t->type->type;
- src->type->bound = count(ll);
- src->type = ptrto(src->type); // make pointer so it will be tracked
- src->esc = EscNone; // until we find otherwise
- e->noesc = list(e->noesc, src);
- n->right = src;
- }
- if(haspointers(t->type)) {
- if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) {
- a = src;
- while(a->op == OCONVNOP)
- a = a->left;
- switch(a->op) {
- case OCALLPART:
- case OCLOSURE:
- case ODDDARG:
- case OARRAYLIT:
- case OPTRLIT:
- case OSTRUCTLIT:
- // The callee has already been analyzed, so its arguments have esc tags.
- // The argument is marked as not escaping at all.
- // Record that fact so that any temporary used for
- // synthesizing this expression can be reclaimed when
- // the function returns.
- // This 'noescape' is even stronger than the usual esc == EscNone.
- // src->esc == EscNone means that src does not escape the current function.
- // src->noescape = 1 here means that src does not escape this statement
- // in the current function.
- a->noescape = 1;
- break;
- }
- }
- }
- if(src != ll->n)
- break;
- t = t->down;
- }
- // "..." arguments are untracked
- for(; ll; ll=ll->next)
- escassign(e, &e->theSink, ll->n);
-}
-
-// Store the link src->dst in dst, throwing out some quick wins.
-static void
-escflows(EscState *e, Node *dst, Node *src)
-{
- if(dst == nil || src == nil || dst == src)
- return;
-
- // Don't bother building a graph for scalars.
- if(src->type && !haspointers(src->type))
- return;
-
- if(debug['m']>2)
- print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
-
- if(dst->escflowsrc == nil) {
- e->dsts = list(e->dsts, dst);
- e->dstcount++;
- }
- e->edgecount++;
-
- dst->escflowsrc = list(dst->escflowsrc, src);
-}
-
-// Whenever we hit a reference node, the level goes up by one, and whenever
-// we hit an OADDR, the level goes down by one. as long as we're on a level > 0
-// finding an OADDR just means we're following the upstream of a dereference,
-// so this address doesn't leak (yet).
-// If level == 0, it means the /value/ of this node can reach the root of this flood.
-// so if this node is an OADDR, it's argument should be marked as escaping iff
-// it's currfn/e->loopdepth are different from the flood's root.
-// Once an object has been moved to the heap, all of it's upstream should be considered
-// escaping to the global scope.
-static void
-escflood(EscState *e, Node *dst)
-{
- NodeList *l;
-
- switch(dst->op) {
- case ONAME:
- case OCLOSURE:
- break;
- default:
- return;
- }
-
- if(debug['m']>1)
- print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
- (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
- dst->escloopdepth);
-
- for(l = dst->escflowsrc; l; l=l->next) {
- walkgen++;
- escwalk(e, 0, dst, l->n);
- }
-}
-
-// There appear to be some loops in the escape graph, causing
-// arbitrary recursion into deeper and deeper levels.
-// Cut this off safely by making minLevel sticky: once you
-// get that deep, you cannot go down any further but you also
-// cannot go up any further. This is a conservative fix.
-// Making minLevel smaller (more negative) would handle more
-// complex chains of indirections followed by address-of operations,
-// at the cost of repeating the traversal once for each additional
-// allowed level when a loop is encountered. Using -2 suffices to
-// pass all the tests we have written so far, which we assume matches
-// the level of complexity we want the escape analysis code to handle.
-#define MinLevel (-2)
-/*c2go enum { MinLevel = -2 };*/
-
-static void
-escwalk(EscState *e, int level, Node *dst, Node *src)
-{
- NodeList *ll;
- int leaks, newlevel;
-
- if(src->walkgen == walkgen && src->esclevel <= level)
- return;
- src->walkgen = walkgen;
- src->esclevel = level;
-
- if(debug['m']>1)
- print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
- level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
- (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
-
- e->pdepth++;
-
- // Input parameter flowing to output parameter?
- if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
- if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) {
- if(level == 0) {
- if(debug['m'])
- warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
- if((src->esc&EscMask) != EscReturn)
- src->esc = EscReturn;
- src->esc |= 1<<((dst->vargen-1) + EscReturnBits);
- goto recurse;
- } else if(level > 0) {
- if(debug['m'])
- warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym);
- if((src->esc&EscMask) != EscReturn)
- src->esc = EscReturn;
- src->esc |= EscContentEscapes;
- goto recurse;
- }
- }
- }
-
- // The second clause is for values pointed at by an object passed to a call
- // that returns something reached via indirect from the object.
- // We don't know which result it is or how many indirects, so we treat it as leaking.
- leaks = level <= 0 && dst->escloopdepth < src->escloopdepth ||
- level < 0 && dst == &e->funcParam && haspointers(src->type);
-
- switch(src->op) {
- case ONAME:
- if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
- src->esc = EscScope;
- if(debug['m'])
- warnl(src->lineno, "leaking param: %hN", src);
- }
-
- // Treat a PPARAMREF closure variable as equivalent to the
- // original variable.
- if(src->class == PPARAMREF) {
- if(leaks && debug['m'])
- warnl(src->lineno, "leaking closure reference %hN", src);
- escwalk(e, level, dst, src->closure);
- }
- break;
-
- case OPTRLIT:
- case OADDR:
- if(leaks) {
- src->esc = EscHeap;
- addrescapes(src->left);
- if(debug['m'])
- warnl(src->lineno, "%hN escapes to heap", src);
- }
- newlevel = level;
- if(level > MinLevel)
- newlevel--;
- escwalk(e, newlevel, dst, src->left);
- break;
-
- case OARRAYLIT:
- if(isfixedarray(src->type))
- break;
- // fall through
- case ODDDARG:
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case OARRAYRUNESTR:
- case OARRAYBYTESTR:
- case OSTRARRAYRUNE:
- case OSTRARRAYBYTE:
- case OADDSTR:
- case OMAPLIT:
- case ONEW:
- case OCLOSURE:
- case OCALLPART:
- case ORUNESTR:
- if(leaks) {
- src->esc = EscHeap;
- if(debug['m'])
- warnl(src->lineno, "%hN escapes to heap", src);
- }
- break;
-
- case ODOT:
- case OSLICE:
- case OSLICEARR:
- case OSLICE3:
- case OSLICE3ARR:
- case OSLICESTR:
- escwalk(e, level, dst, src->left);
- break;
-
- case OINDEX:
- if(isfixedarray(src->left->type)) {
- escwalk(e, level, dst, src->left);
- break;
- }
- // fall through
- case ODOTPTR:
- case OINDEXMAP:
- case OIND:
- newlevel = level;
- if(level > MinLevel)
- newlevel++;
- escwalk(e, newlevel, dst, src->left);
- }
-
-recurse:
- for(ll=src->escflowsrc; ll; ll=ll->next)
- escwalk(e, level, dst, ll->n);
-
- e->pdepth--;
-}
-
-static void
-esctag(EscState *e, Node *func)
-{
- Node *savefn;
- NodeList *ll;
- Type *t;
-
- USED(e);
- func->esc = EscFuncTagged;
-
- // External functions are assumed unsafe,
- // unless //go:noescape is given before the declaration.
- if(func->nbody == nil) {
- if(func->noescape) {
- for(t=getinargx(func->type)->type; t; t=t->down)
- if(haspointers(t->type))
- t->note = mktag(EscNone);
- }
- return;
- }
-
- savefn = curfn;
- curfn = func;
-
- for(ll=curfn->dcl; ll; ll=ll->next) {
- if(ll->n->op != ONAME || ll->n->class != PPARAM)
- continue;
-
- switch (ll->n->esc&EscMask) {
- case EscNone: // not touched by escflood
- case EscReturn:
- if(haspointers(ll->n->type)) // don't bother tagging for scalars
- ll->n->paramfld->note = mktag(ll->n->esc);
- break;
- case EscHeap: // touched by escflood, moved to heap
- case EscScope: // touched by escflood, value leaves scope
- break;
- }
- }
-
- curfn = savefn;
-}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
deleted file mode 100644
index 91f4957dc2..0000000000
--- a/src/cmd/gc/export.c
+++ /dev/null
@@ -1,563 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "y.tab.h"
-
-static NodeList *asmlist;
-
-static void dumpexporttype(Type *t);
-
-// Mark n's symbol as exported
-void
-exportsym(Node *n)
-{
- if(n == N || n->sym == S)
- return;
- if(n->sym->flags & (SymExport|SymPackage)) {
- if(n->sym->flags & SymPackage)
- yyerror("export/package mismatch: %S", n->sym);
- return;
- }
- n->sym->flags |= SymExport;
-
- if(debug['E'])
- print("export symbol %S\n", n->sym);
- exportlist = list(exportlist, n);
-}
-
-int
-exportname(char *s)
-{
- Rune r;
-
- if((uchar)s[0] < Runeself)
- return 'A' <= s[0] && s[0] <= 'Z';
- chartorune(&r, s);
- return isupperrune(r);
-}
-
-static int
-initname(char *s)
-{
- return strcmp(s, "init") == 0;
-}
-
-// exportedsym reports whether a symbol will be visible
-// to files that import our package.
-static int
-exportedsym(Sym *sym)
-{
- // Builtins are visible everywhere.
- if(sym->pkg == builtinpkg || sym->origpkg == builtinpkg)
- return 1;
-
- return sym->pkg == localpkg && exportname(sym->name);
-}
-
-void
-autoexport(Node *n, int ctxt)
-{
- if(n == N || n->sym == S)
- return;
- if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
- return;
- if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
- return;
- // -A is for cmd/gc/mkbuiltin script, so export everything
- if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name))
- exportsym(n);
- if(asmhdr && n->sym->pkg == localpkg && !(n->sym->flags & SymAsm)) {
- n->sym->flags |= SymAsm;
- asmlist = list(asmlist, n);
- }
-
-}
-
-static void
-dumppkg(Pkg *p)
-{
- char *suffix;
-
- if(p == nil || p == localpkg || p->exported || p == builtinpkg)
- return;
- p->exported = 1;
- suffix = "";
- if(!p->direct)
- suffix = " // indirect";
- Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
-}
-
-// Look for anything we need for the inline body
-static void reexportdep(Node *n);
-static void
-reexportdeplist(NodeList *ll)
-{
- for(; ll ;ll=ll->next)
- reexportdep(ll->n);
-}
-
-static void
-reexportdep(Node *n)
-{
- Type *t;
-
- if(!n)
- return;
-
- //print("reexportdep %+hN\n", n);
- switch(n->op) {
- case ONAME:
- switch(n->class&~PHEAP) {
- case PFUNC:
- // methods will be printed along with their type
- // nodes for T.Method expressions
- if(n->left && n->left->op == OTYPE)
- break;
- // nodes for method calls.
- if(!n->type || n->type->thistuple > 0)
- break;
- // fallthrough
- case PEXTERN:
- if(n->sym && !exportedsym(n->sym)) {
- if(debug['E'])
- print("reexport name %S\n", n->sym);
- exportlist = list(exportlist, n);
- }
- }
- break;
-
- case ODCL:
- // Local variables in the bodies need their type.
- t = n->left->type;
- if(t != types[t->etype] && t != idealbool && t != idealstring) {
- if(isptr[t->etype])
- t = t->type;
- if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
- if(debug['E'])
- print("reexport type %S from declaration\n", t->sym);
- exportlist = list(exportlist, t->sym->def);
- }
- }
- break;
-
- case OLITERAL:
- t = n->type;
- if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
- if(isptr[t->etype])
- t = t->type;
- if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
- if(debug['E'])
- print("reexport literal type %S\n", t->sym);
- exportlist = list(exportlist, t->sym->def);
- }
- }
- // fallthrough
- case OTYPE:
- if(n->sym && !exportedsym(n->sym)) {
- if(debug['E'])
- print("reexport literal/type %S\n", n->sym);
- exportlist = list(exportlist, n);
- }
- break;
-
- // for operations that need a type when rendered, put the type on the export list.
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case ORUNESTR:
- case OARRAYBYTESTR:
- case OARRAYRUNESTR:
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OSTRUCTLIT:
- case OARRAYLIT:
- case OPTRLIT:
- case OMAKEMAP:
- case OMAKESLICE:
- case OMAKECHAN:
- t = n->type;
- if(!t->sym && t->type)
- t = t->type;
- if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
- if(debug['E'])
- print("reexport type for expression %S\n", t->sym);
- exportlist = list(exportlist, t->sym->def);
- }
- break;
- }
-
- reexportdep(n->left);
- reexportdep(n->right);
- reexportdeplist(n->list);
- reexportdeplist(n->rlist);
- reexportdeplist(n->ninit);
- reexportdep(n->ntest);
- reexportdep(n->nincr);
- reexportdeplist(n->nbody);
- reexportdeplist(n->nelse);
-}
-
-
-static void
-dumpexportconst(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv);
- if(n == N || n->op != OLITERAL)
- fatal("dumpexportconst: oconst nil: %S", s);
-
- t = n->type; // may or may not be specified
- dumpexporttype(t);
-
- if(t != T && !isideal(t))
- Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
- else
- Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
-}
-
-static void
-dumpexportvar(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv|Ecall);
- if(n == N || n->type == T) {
- yyerror("variable exported but not defined: %S", s);
- return;
- }
-
- t = n->type;
- dumpexporttype(t);
-
- if(t->etype == TFUNC && n->class == PFUNC) {
- if (n->inl) {
- // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
- // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
- if(debug['l'] < 2)
- typecheckinl(n);
- // NOTE: The space after %#S here is necessary for ld's export data parser.
- Bprint(bout, "\tfunc %#S %#hT { %#H }\n", s, t, n->inl);
- reexportdeplist(n->inl);
- } else
- Bprint(bout, "\tfunc %#S %#hT\n", s, t);
- } else
- Bprint(bout, "\tvar %#S %#T\n", s, t);
-}
-
-static int
-methodbyname(const void *va, const void *vb)
-{
- Type *a, *b;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- return strcmp(a->sym->name, b->sym->name);
-}
-
-static void
-dumpexporttype(Type *t)
-{
- Type *f;
- Type **m;
- int i, n;
-
- if(t == T)
- return;
- if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
- return;
- t->printed = 1;
-
- if(t->sym != S && t->etype != TFIELD)
- dumppkg(t->sym->pkg);
-
- dumpexporttype(t->type);
- dumpexporttype(t->down);
-
- if (t->sym == S || t->etype == TFIELD)
- return;
-
- n = 0;
- for(f=t->method; f!=T; f=f->down) {
- dumpexporttype(f);
- n++;
- }
-
- m = mal(n*sizeof m[0]);
- i = 0;
- for(f=t->method; f!=T; f=f->down)
- m[i++] = f;
- qsort(m, n, sizeof m[0], methodbyname);
-
- Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
- for(i=0; i<n; i++) {
- f = m[i];
- if(f->nointerface)
- Bprint(bout, "\t//go:nointerface\n");
- if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
- // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
- // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
- if(debug['l'] < 2)
- typecheckinl(f->type->nname);
- Bprint(bout, "\tfunc (%#T) %#hhS %#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
- reexportdeplist(f->type->nname->inl);
- } else
- Bprint(bout, "\tfunc (%#T) %#hhS %#hT\n", getthisx(f->type)->type, f->sym, f->type);
- }
-}
-
-static void
-dumpsym(Sym *s)
-{
- if(s->flags & SymExported)
- return;
- s->flags |= SymExported;
-
- if(s->def == N) {
- yyerror("unknown export symbol: %S", s);
- return;
- }
-// print("dumpsym %O %+S\n", s->def->op, s);
- dumppkg(s->pkg);
-
- switch(s->def->op) {
- default:
- yyerror("unexpected export symbol: %O %S", s->def->op, s);
- break;
-
- case OLITERAL:
- dumpexportconst(s);
- break;
-
- case OTYPE:
- if(s->def->type->etype == TFORW)
- yyerror("export of incomplete type %S", s);
- else
- dumpexporttype(s->def->type);
- break;
-
- case ONAME:
- dumpexportvar(s);
- break;
- }
-}
-
-void
-dumpexport(void)
-{
- NodeList *l;
- int32 i, lno;
- Pkg *p;
-
- lno = lineno;
-
- Bprint(bout, "\n$$\npackage %s", localpkg->name);
- if(safemode)
- Bprint(bout, " safe");
- Bprint(bout, "\n");
-
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dumppkg(p);
-
- for(l=exportlist; l; l=l->next) {
- lineno = l->n->lineno;
- dumpsym(l->n->sym);
- }
-
- Bprint(bout, "\n$$\n");
- lineno = lno;
-}
-
-/*
- * import
- */
-
-/*
- * return the sym for ss, which should match lexical
- */
-Sym*
-importsym(Sym *s, int op)
-{
- char *pkgstr;
-
- if(s->def != N && s->def->op != op) {
- pkgstr = smprint("during import \"%Z\"", importpkg->path);
- redeclare(s, pkgstr);
- }
-
- // mark the symbol so it is not reexported
- if(s->def == N) {
- if(exportname(s->name) || initname(s->name))
- s->flags |= SymExport;
- else
- s->flags |= SymPackage; // package scope
- }
- return s;
-}
-
-/*
- * return the type pkg.name, forward declaring if needed
- */
-Type*
-pkgtype(Sym *s)
-{
- Type *t;
-
- importsym(s, OTYPE);
- if(s->def == N || s->def->op != OTYPE) {
- t = typ(TFORW);
- t->sym = s;
- s->def = typenod(t);
- }
- if(s->def->type == T)
- yyerror("pkgtype %S", s);
- return s->def->type;
-}
-
-void
-importimport(Sym *s, Strlit *z)
-{
- // Informational: record package name
- // associated with import path, for use in
- // human-readable messages.
- Pkg *p;
-
- if(isbadimport(z))
- errorexit();
- p = mkpkg(z);
- if(p->name == nil) {
- p->name = s->name;
- pkglookup(s->name, nil)->npkg++;
- } else if(strcmp(p->name, s->name) != 0)
- yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
-
- if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
- yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
- errorexit();
- }
-}
-
-void
-importconst(Sym *s, Type *t, Node *n)
-{
- Node *n1;
-
- importsym(s, OLITERAL);
- convlit(&n, t);
-
- if(s->def != N) // TODO: check if already the same.
- return;
-
- if(n->op != OLITERAL) {
- yyerror("expression must be a constant");
- return;
- }
-
- if(n->sym != S) {
- n1 = nod(OXXX, N, N);
- *n1 = *n;
- n = n1;
- }
- n->orig = newname(s);
- n->sym = s;
- declare(n, PEXTERN);
-
- if(debug['E'])
- print("import const %S\n", s);
-}
-
-void
-importvar(Sym *s, Type *t)
-{
- Node *n;
-
- importsym(s, ONAME);
- if(s->def != N && s->def->op == ONAME) {
- if(eqtype(t, s->def->type))
- return;
- yyerror("inconsistent definition for var %S during import\n\t%T (in \"%Z\")\n\t%T (in \"%Z\")", s, s->def->type, s->importdef->path, t, importpkg->path);
- }
- n = newname(s);
- s->importdef = importpkg;
- n->type = t;
- declare(n, PEXTERN);
-
- if(debug['E'])
- print("import var %S %lT\n", s, t);
-}
-
-void
-importtype(Type *pt, Type *t)
-{
- Node *n;
-
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if(incannedimport &&
- strcmp(importpkg->name, "unsafe") == 0 &&
- strcmp(pt->nod->sym->name, "Pointer") == 0) {
- t = types[TUNSAFEPTR];
- }
-
- if(pt->etype == TFORW) {
- n = pt->nod;
- copytype(pt->nod, t);
- pt->nod = n; // unzero nod
- pt->sym->importdef = importpkg;
- pt->sym->lastlineno = parserline();
- declare(n, PEXTERN);
- checkwidth(pt);
- } else if(!eqtype(pt->orig, t))
- yyerror("inconsistent definition for type %S during import\n\t%lT (in \"%Z\")\n\t%lT (in \"%Z\")", pt->sym, pt, pt->sym->importdef->path, t, importpkg->path);
-
- if(debug['E'])
- print("import type %T %lT\n", pt, t);
-}
-
-void
-dumpasmhdr(void)
-{
- Biobuf *b;
- NodeList *l;
- Node *n;
- Type *t;
-
- b = Bopen(asmhdr, OWRITE);
- if(b == nil)
- fatal("open %s: %r", asmhdr);
- Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thearch.thechar, localpkg->name);
- for(l=asmlist; l; l=l->next) {
- n = l->n;
- if(isblanksym(n->sym))
- continue;
- switch(n->op) {
- case OLITERAL:
- Bprint(b, "#define const_%s %#V\n", n->sym->name, &n->val);
- break;
- case OTYPE:
- t = n->type;
- if(t->etype != TSTRUCT || t->map != T || t->funarg)
- break;
- Bprint(b, "#define %s__size %d\n", t->sym->name, (int)t->width);
- for(t=t->type; t != T; t=t->down)
- if(!isblanksym(t->sym))
- Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width);
- break;
- }
- }
-
- Bterm(b);
-}
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
deleted file mode 100644
index bd0a29f6e1..0000000000
--- a/src/cmd/gc/fmt.c
+++ /dev/null
@@ -1,1697 +0,0 @@
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "opnames.h"
-
-//
-// Format conversions
-// %L int Line numbers
-//
-// %E int etype values (aka 'Kind')
-//
-// %O int Node Opcodes
-// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
-//
-// %J Node* Node details
-// Flags: "%hJ" suppresses things not relevant until walk.
-//
-// %V Val* Constant values
-//
-// %S Sym* Symbols
-// Flags: +,- #: mode (see below)
-// "%hS" unqualified identifier in any mode
-// "%hhS" in export mode: unqualified identifier if exported, qualified if not
-//
-// %T Type* Types
-// Flags: +,- #: mode (see below)
-// 'l' definition instead of name.
-// 'h' omit "func" and receiver in function types
-// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
-//
-// %N Node* Nodes
-// Flags: +,- #: mode (see below)
-// 'h' (only in +/debug mode) suppress recursion
-// 'l' (only in Error mode) print "foo (type Bar)"
-//
-// %H NodeList* NodeLists
-// Flags: those of %N
-// ',' separate items with ',' instead of ';'
-//
-// %Z Strlit* String literals
-//
-// In mparith1.c:
-// %B Mpint* Big integers
-// %F Mpflt* Big floats
-//
-// %S, %T and %N obey use the following flags to set the format mode:
-enum {
- FErr, // error mode (default)
- FDbg, // "%+N" debug mode
- FExp, // "%#N" export mode
- FTypeId, // "%-N" turning-types-into-symbols-mode: identical types give identical strings
-};
-static int fmtmode;
-static int fmtpkgpfx; // %uT stickyness
-//
-// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
-//
-// The mode flags +, - and # are sticky, meaning they persist through
-// recursions of %N, %T and %S, but not the h and l flags. The u flag is
-// sticky only on %T recursions and only used in %-/Sym mode.
-
-//
-// Useful format combinations:
-//
-// %+N %+H multiline recursive debug dump of node/nodelist
-// %+hN %+hH non recursive debug dump
-//
-// %#N %#T export format
-// %#lT type definition instead of name
-// %#hT omit"func" and receiver in function signature
-//
-// %lN "foo (type Bar)" for error messages
-//
-// %-T type identifiers
-// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
-// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
-//
-
-
-static int
-setfmode(unsigned long *flags)
-{
- int fm;
-
- fm = fmtmode;
- if(*flags & FmtSign)
- fmtmode = FDbg;
- else if(*flags & FmtSharp)
- fmtmode = FExp;
- else if(*flags & FmtLeft)
- fmtmode = FTypeId;
-
- *flags &= ~(FmtSharp|FmtLeft|FmtSign);
- return fm;
-}
-
-// Fmt "%L": Linenumbers
-static int
-Lconv(Fmt *fp)
-{
- return linklinefmt(ctxt, fp);
-}
-
-static char*
-goopnames[] =
-{
- [OADDR] = "&",
- [OADD] = "+",
- [OADDSTR] = "+",
- [OANDAND] = "&&",
- [OANDNOT] = "&^",
- [OAND] = "&",
- [OAPPEND] = "append",
- [OAS] = "=",
- [OAS2] = "=",
- [OBREAK] = "break",
- [OCALL] = "function call", // not actual syntax
- [OCAP] = "cap",
- [OCASE] = "case",
- [OCLOSE] = "close",
- [OCOMPLEX] = "complex",
- [OCOM] = "^",
- [OCONTINUE] = "continue",
- [OCOPY] = "copy",
- [ODEC] = "--",
- [ODELETE] = "delete",
- [ODEFER] = "defer",
- [ODIV] = "/",
- [OEQ] = "==",
- [OFALL] = "fallthrough",
- [OFOR] = "for",
- [OGE] = ">=",
- [OGOTO] = "goto",
- [OGT] = ">",
- [OIF] = "if",
- [OIMAG] = "imag",
- [OINC] = "++",
- [OIND] = "*",
- [OLEN] = "len",
- [OLE] = "<=",
- [OLSH] = "<<",
- [OLT] = "<",
- [OMAKE] = "make",
- [OMINUS] = "-",
- [OMOD] = "%",
- [OMUL] = "*",
- [ONEW] = "new",
- [ONE] = "!=",
- [ONOT] = "!",
- [OOROR] = "||",
- [OOR] = "|",
- [OPANIC] = "panic",
- [OPLUS] = "+",
- [OPRINTN] = "println",
- [OPRINT] = "print",
- [ORANGE] = "range",
- [OREAL] = "real",
- [ORECV] = "<-",
- [ORECOVER] = "recover",
- [ORETURN] = "return",
- [ORSH] = ">>",
- [OSELECT] = "select",
- [OSEND] = "<-",
- [OSUB] = "-",
- [OSWITCH] = "switch",
- [OXOR] = "^",
-};
-
-// Fmt "%O": Node opcodes
-int
-Oconv(Fmt *fp)
-{
- int o;
-
- o = va_arg(fp->args, int);
- if((fp->flags & FmtSharp) || fmtmode != FDbg)
- if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
- return fmtstrcpy(fp, goopnames[o]);
-
- if(o >= 0 && o < nelem(opnames) && opnames[o] != nil)
- return fmtstrcpy(fp, opnames[o]);
-
- return fmtprint(fp, "O-%d", o);
-}
-
-static const char* classnames[] = {
- "Pxxx",
- "PEXTERN",
- "PAUTO",
- "PPARAM",
- "PPARAMOUT",
- "PPARAMREF",
- "PFUNC",
-};
-
-// Fmt "%J": Node details.
-static int
-Jconv(Fmt *fp)
-{
- Node *n;
- char *s;
- int c;
-
- n = va_arg(fp->args, Node*);
-
- c = fp->flags&FmtShort;
-
- if(!c && n->ullman != 0)
- fmtprint(fp, " u(%d)", n->ullman);
-
- if(!c && n->addable != 0)
- fmtprint(fp, " a(%d)", n->addable);
-
- if(!c && n->vargen != 0)
- fmtprint(fp, " g(%d)", n->vargen);
-
- if(n->lineno != 0)
- fmtprint(fp, " l(%d)", n->lineno);
-
- if(!c && n->xoffset != BADWIDTH)
- fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
-
- if(n->class != 0) {
- s = "";
- if(n->class & PHEAP) s = ",heap";
- if((n->class & ~PHEAP) < nelem(classnames))
- fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
- else
- fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
- }
-
- if(n->colas != 0)
- fmtprint(fp, " colas(%d)", n->colas);
-
- if(n->funcdepth != 0)
- fmtprint(fp, " f(%d)", n->funcdepth);
-
- switch(n->esc) {
- case EscUnknown:
- break;
- case EscHeap:
- fmtprint(fp, " esc(h)");
- break;
- case EscScope:
- fmtprint(fp, " esc(s)");
- break;
- case EscNone:
- fmtprint(fp, " esc(no)");
- break;
- case EscNever:
- if(!c)
- fmtprint(fp, " esc(N)");
- break;
- default:
- fmtprint(fp, " esc(%d)", n->esc);
- break;
- }
-
- if(n->escloopdepth)
- fmtprint(fp, " ld(%d)", n->escloopdepth);
-
- if(!c && n->typecheck != 0)
- fmtprint(fp, " tc(%d)", n->typecheck);
-
- if(!c && n->dodata != 0)
- fmtprint(fp, " dd(%d)", n->dodata);
-
- if(n->isddd != 0)
- fmtprint(fp, " isddd(%d)", n->isddd);
-
- if(n->implicit != 0)
- fmtprint(fp, " implicit(%d)", n->implicit);
-
- if(n->embedded != 0)
- fmtprint(fp, " embedded(%d)", n->embedded);
-
- if(n->addrtaken != 0)
- fmtprint(fp, " addrtaken");
-
- if(n->assigned != 0)
- fmtprint(fp, " assigned");
-
- if(!c && n->used != 0)
- fmtprint(fp, " used(%d)", n->used);
- return 0;
-}
-
-// Fmt "%V": Values
-static int
-Vconv(Fmt *fp)
-{
- Val *v;
- vlong x;
-
- v = va_arg(fp->args, Val*);
-
- switch(v->ctype) {
- case CTINT:
- if((fp->flags & FmtSharp) || fmtmode == FExp)
- return fmtprint(fp, "%#B", v->u.xval);
- return fmtprint(fp, "%B", v->u.xval);
- case CTRUNE:
- x = mpgetfix(v->u.xval);
- if(' ' <= x && x < 0x80 && x != '\\' && x != '\'')
- return fmtprint(fp, "'%c'", (int)x);
- if(0 <= x && x < (1<<16))
- return fmtprint(fp, "'\\u%04ux'", (int)x);
- if(0 <= x && x <= Runemax)
- return fmtprint(fp, "'\\U%08llux'", x);
- return fmtprint(fp, "('\\x00' + %B)", v->u.xval);
- case CTFLT:
- if((fp->flags & FmtSharp) || fmtmode == FExp)
- return fmtprint(fp, "%F", v->u.fval);
- return fmtprint(fp, "%#F", v->u.fval);
- case CTCPLX:
- if((fp->flags & FmtSharp) || fmtmode == FExp)
- return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag);
- if(mpcmpfltc(&v->u.cval->real, 0) == 0)
- return fmtprint(fp, "%#Fi", &v->u.cval->imag);
- if(mpcmpfltc(&v->u.cval->imag, 0) == 0)
- return fmtprint(fp, "%#F", &v->u.cval->real);
- if(mpcmpfltc(&v->u.cval->imag, 0) < 0)
- return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag);
- return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag);
- case CTSTR:
- return fmtprint(fp, "\"%Z\"", v->u.sval);
- case CTBOOL:
- if( v->u.bval)
- return fmtstrcpy(fp, "true");
- return fmtstrcpy(fp, "false");
- case CTNIL:
- return fmtstrcpy(fp, "nil");
- }
- return fmtprint(fp, "<ctype=%d>", v->ctype);
-}
-
-// Fmt "%Z": escaped string literals
-static int
-Zconv(Fmt *fp)
-{
- Rune r;
- Strlit *sp;
- char *s, *se;
- int n;
-
- sp = va_arg(fp->args, Strlit*);
- if(sp == nil)
- return fmtstrcpy(fp, "<nil>");
-
- s = sp->s;
- se = s + sp->len;
-
- // NOTE: Keep in sync with ../ld/go.c:/^Zconv.
- while(s < se) {
- n = chartorune(&r, s);
- s += n;
- switch(r) {
- case Runeerror:
- if(n == 1) {
- fmtprint(fp, "\\x%02x", (uchar)*(s-1));
- break;
- }
- // fall through
- default:
- if(r < ' ') {
- fmtprint(fp, "\\x%02x", r);
- break;
- }
- fmtrune(fp, r);
- break;
- case '\t':
- fmtstrcpy(fp, "\\t");
- break;
- case '\n':
- fmtstrcpy(fp, "\\n");
- break;
- case '\"':
- case '\\':
- fmtrune(fp, '\\');
- fmtrune(fp, r);
- break;
- case 0xFEFF: // BOM, basically disallowed in source code
- fmtstrcpy(fp, "\\uFEFF");
- break;
- }
- }
- return 0;
-}
-
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[ ]*T%%g
-s%,.*%%g
-s%.+% [T&] = "&",%g
-s%^ ........*\]%&~%g
-s%~ %%g
-*/
-
-static char*
-etnames[] =
-{
- [TINT] = "INT",
- [TUINT] = "UINT",
- [TINT8] = "INT8",
- [TUINT8] = "UINT8",
- [TINT16] = "INT16",
- [TUINT16] = "UINT16",
- [TINT32] = "INT32",
- [TUINT32] = "UINT32",
- [TINT64] = "INT64",
- [TUINT64] = "UINT64",
- [TUINTPTR] = "UINTPTR",
- [TFLOAT32] = "FLOAT32",
- [TFLOAT64] = "FLOAT64",
- [TCOMPLEX64] = "COMPLEX64",
- [TCOMPLEX128] = "COMPLEX128",
- [TBOOL] = "BOOL",
- [TPTR32] = "PTR32",
- [TPTR64] = "PTR64",
- [TFUNC] = "FUNC",
- [TARRAY] = "ARRAY",
- [TSTRUCT] = "STRUCT",
- [TCHAN] = "CHAN",
- [TMAP] = "MAP",
- [TINTER] = "INTER",
- [TFORW] = "FORW",
- [TFIELD] = "FIELD",
- [TSTRING] = "STRING",
- [TANY] = "ANY",
-};
-
-// Fmt "%E": etype
-static int
-Econv(Fmt *fp)
-{
- int et;
-
- et = va_arg(fp->args, int);
- if(et >= 0 && et < nelem(etnames) && etnames[et] != nil)
- return fmtstrcpy(fp, etnames[et]);
- return fmtprint(fp, "E-%d", et);
-}
-
-// Fmt "%S": syms
-static int
-symfmt(Fmt *fp, Sym *s)
-{
- char *p;
-
- if(s->pkg && !(fp->flags&FmtShort)) {
- switch(fmtmode) {
- case FErr: // This is for the user
- if(s->pkg == localpkg)
- return fmtstrcpy(fp, s->name);
- // If the name was used by multiple packages, display the full path,
- if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
- return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
- return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
- case FDbg:
- return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
- case FTypeId:
- if(fp->flags&FmtUnsigned)
- return fmtprint(fp, "%s.%s", s->pkg->name, s->name); // dcommontype, typehash
- return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name); // (methodsym), typesym, weaksym
- case FExp:
- if(s->name && s->name[0] == '.')
- fatal("exporting synthetic symbol %s", s->name);
- if(s->pkg != builtinpkg)
- return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
- }
- }
-
- if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h)
- // skip leading "type." in method name
- p = utfrrune(s->name, '.');
- if(p)
- p++;
- else
- p = s->name;
-
- // exportname needs to see the name without the prefix too.
- if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
- return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
-
- return fmtstrcpy(fp, p);
- }
-
- return fmtstrcpy(fp, s->name);
-}
-
-static char*
-basicnames[] =
-{
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TBOOL] = "bool",
- [TANY] = "any",
- [TSTRING] = "string",
- [TNIL] = "nil",
- [TIDEAL] = "untyped number",
- [TBLANK] = "blank",
-};
-
-static int
-typefmt(Fmt *fp, Type *t)
-{
- Type *t1;
- Sym *s;
-
- if(t == T)
- return fmtstrcpy(fp, "<T>");
-
- if (t == bytetype || t == runetype) {
- // in %-T mode collapse rune and byte with their originals.
- if(fmtmode != FTypeId)
- return fmtprint(fp, "%hS", t->sym);
- t = types[t->etype];
- }
-
- if(t == errortype)
- return fmtstrcpy(fp, "error");
-
- // Unless the 'l' flag was specified, if the type has a name, just print that name.
- if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) {
- switch(fmtmode) {
- case FTypeId:
- if(fp->flags&FmtShort) {
- if(t->vargen)
- return fmtprint(fp, "%hS·%d", t->sym, t->vargen);
- return fmtprint(fp, "%hS", t->sym);
- }
- if(fp->flags&FmtUnsigned)
- return fmtprint(fp, "%uS", t->sym);
- // fallthrough
- case FExp:
- if(t->sym->pkg == localpkg && t->vargen)
- return fmtprint(fp, "%S·%d", t->sym, t->vargen);
- break;
- }
- return fmtprint(fp, "%S", t->sym);
- }
-
- if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
- if(fmtmode == FErr && (t == idealbool || t == idealstring))
- fmtstrcpy(fp, "untyped ");
- return fmtstrcpy(fp, basicnames[t->etype]);
- }
-
- if(fmtmode == FDbg)
- fmtprint(fp, "%E-", t->etype);
-
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- if(fmtmode == FTypeId && (fp->flags&FmtShort))
- return fmtprint(fp, "*%hT", t->type);
- return fmtprint(fp, "*%T", t->type);
-
- case TARRAY:
- if(t->bound >= 0)
- return fmtprint(fp, "[%lld]%T", t->bound, t->type);
- if(t->bound == -100)
- return fmtprint(fp, "[...]%T", t->type);
- return fmtprint(fp, "[]%T", t->type);
-
- case TCHAN:
- switch(t->chan) {
- case Crecv:
- return fmtprint(fp, "<-chan %T", t->type);
- case Csend:
- return fmtprint(fp, "chan<- %T", t->type);
- }
-
- if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
- return fmtprint(fp, "chan (%T)", t->type);
- return fmtprint(fp, "chan %T", t->type);
-
- case TMAP:
- return fmtprint(fp, "map[%T]%T", t->down, t->type);
-
- case TINTER:
- fmtstrcpy(fp, "interface {");
- for(t1=t->type; t1!=T; t1=t1->down)
- if(exportname(t1->sym->name)) {
- if(t1->down)
- fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
- else
- fmtprint(fp, " %hS%hT ", t1->sym, t1->type);
- } else {
- // non-exported method names must be qualified
- if(t1->down)
- fmtprint(fp, " %uS%hT;", t1->sym, t1->type);
- else
- fmtprint(fp, " %uS%hT ", t1->sym, t1->type);
- }
- fmtstrcpy(fp, "}");
- return 0;
-
- case TFUNC:
- if(fp->flags & FmtShort) {
- fmtprint(fp, "%T", getinargx(t));
- } else {
- if(t->thistuple)
- fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t));
- else
- fmtprint(fp, "func%T", getinargx(t));
- }
- switch(t->outtuple) {
- case 0:
- break;
- case 1:
- if(fmtmode != FExp) {
- fmtprint(fp, " %T", getoutargx(t)->type->type); // struct->field->field's type
- break;
- }
- default:
- fmtprint(fp, " %T", getoutargx(t));
- break;
- }
- return 0;
-
- case TSTRUCT:
- // Format the bucket struct for map[x]y as map.bucket[x]y.
- // This avoids a recursive print that generates very long names.
- if(t->map != T) {
- if(t->map->bucket == t) {
- return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type);
- }
- if(t->map->hmap == t) {
- return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type);
- }
- if(t->map->hiter == t) {
- return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type);
- }
- yyerror("unknown internal map type");
- }
-
- if(t->funarg) {
- fmtstrcpy(fp, "(");
- if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape"/"nosplit" tags
- for(t1=t->type; t1!=T; t1=t1->down)
- if(t1->down)
- fmtprint(fp, "%hT, ", t1);
- else
- fmtprint(fp, "%hT", t1);
- } else {
- for(t1=t->type; t1!=T; t1=t1->down)
- if(t1->down)
- fmtprint(fp, "%T, ", t1);
- else
- fmtprint(fp, "%T", t1);
- }
- fmtstrcpy(fp, ")");
- } else {
- fmtstrcpy(fp, "struct {");
- for(t1=t->type; t1!=T; t1=t1->down)
- if(t1->down)
- fmtprint(fp, " %lT;", t1);
- else
- fmtprint(fp, " %lT ", t1);
- fmtstrcpy(fp, "}");
- }
- return 0;
-
- case TFIELD:
- if(!(fp->flags&FmtShort)) {
- s = t->sym;
-
- // Take the name from the original, lest we substituted it with ~r%d or ~b%d.
- // ~r%d is a (formerly) unnamed result.
- if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) {
- if(t->nname->orig != N) {
- s = t->nname->orig->sym;
- if(s != S && s->name[0] == '~') {
- if(s->name[1] == 'r') // originally an unnamed result
- s = S;
- else if(s->name[1] == 'b') // originally the blank identifier _
- s = lookup("_");
- }
- } else
- s = S;
- }
-
- if(s != S && !t->embedded) {
- if(t->funarg)
- fmtprint(fp, "%N ", t->nname);
- else if(fp->flags&FmtLong)
- fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg)
- else
- fmtprint(fp, "%S ", s);
- } else if(fmtmode == FExp) {
- // TODO(rsc) this breaks on the eliding of unused arguments in the backend
- // when this is fixed, the special case in dcl.c checkarglist can go.
- //if(t->funarg)
- // fmtstrcpy(fp, "_ ");
- //else
- if(t->embedded && s->pkg != nil && s->pkg->path->len > 0)
- fmtprint(fp, "@\"%Z\".? ", s->pkg->path);
- else
- fmtstrcpy(fp, "? ");
- }
- }
-
- if(t->isddd)
- fmtprint(fp, "...%T", t->type->type);
- else
- fmtprint(fp, "%T", t->type);
-
- if(!(fp->flags&FmtShort) && t->note)
- fmtprint(fp, " \"%Z\"", t->note);
- return 0;
-
- case TFORW:
- if(t->sym)
- return fmtprint(fp, "undefined %S", t->sym);
- return fmtstrcpy(fp, "undefined");
-
- case TUNSAFEPTR:
- if(fmtmode == FExp)
- return fmtprint(fp, "@\"unsafe\".Pointer");
- return fmtprint(fp, "unsafe.Pointer");
- }
-
- if(fmtmode == FExp)
- fatal("missing %E case during export", t->etype);
- // Don't know how to handle - fall back to detailed prints.
- return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type);
-}
-
-// Statements which may be rendered with a simplestmt as init.
-static int
-stmtwithinit(int op)
-{
- switch(op) {
- case OIF:
- case OFOR:
- case OSWITCH:
- return 1;
- }
- return 0;
-}
-
-static int
-stmtfmt(Fmt *f, Node *n)
-{
- int complexinit, simpleinit, extrablock;
-
- // some statements allow for an init, but at most one,
- // but we may have an arbitrary number added, eg by typecheck
- // and inlining. If it doesn't fit the syntax, emit an enclosing
- // block starting with the init statements.
-
- // if we can just say "for" n->ninit; ... then do so
- simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op);
- // otherwise, print the inits as separate statements
- complexinit = n->ninit && !simpleinit && (fmtmode != FErr);
- // but if it was for if/for/switch, put in an extra surrounding block to limit the scope
- extrablock = complexinit && stmtwithinit(n->op);
-
- if(extrablock)
- fmtstrcpy(f, "{");
-
- if(complexinit)
- fmtprint(f, " %H; ", n->ninit);
-
- switch(n->op){
- case ODCL:
- if(fmtmode == FExp) {
- switch(n->left->class&~PHEAP) {
- case PPARAM:
- case PPARAMOUT:
- case PAUTO:
- fmtprint(f, "var %N %T", n->left, n->left->type);
- goto ret;
- }
- }
- fmtprint(f, "var %S %T", n->left->sym, n->left->type);
- break;
-
- case ODCLFIELD:
- if(n->left)
- fmtprint(f, "%N %N", n->left, n->right);
- else
- fmtprint(f, "%N", n->right);
- break;
-
- case OAS:
- // Don't export "v = <N>" initializing statements, hope they're always
- // preceded by the DCL which will be re-parsed and typecheck to reproduce
- // the "v = <N>" again.
- if(fmtmode == FExp && n->right == N)
- break;
-
- if(n->colas && !complexinit)
- fmtprint(f, "%N := %N", n->left, n->right);
- else
- fmtprint(f, "%N = %N", n->left, n->right);
- break;
-
- case OASOP:
- if(n->implicit) {
- if(n->etype == OADD)
- fmtprint(f, "%N++", n->left);
- else
- fmtprint(f, "%N--", n->left);
- break;
- }
- fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
- break;
-
- case OAS2:
- if(n->colas && !complexinit) {
- fmtprint(f, "%,H := %,H", n->list, n->rlist);
- break;
- }
- // fallthrough
- case OAS2DOTTYPE:
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2RECV:
- fmtprint(f, "%,H = %,H", n->list, n->rlist);
- break;
-
- case ORETURN:
- fmtprint(f, "return %,H", n->list);
- break;
-
- case ORETJMP:
- fmtprint(f, "retjmp %S", n->sym);
- break;
-
- case OPROC:
- fmtprint(f, "go %N", n->left);
- break;
-
- case ODEFER:
- fmtprint(f, "defer %N", n->left);
- break;
-
- case OIF:
- if(simpleinit)
- fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody);
- else
- fmtprint(f, "if %N { %H }", n->ntest, n->nbody);
- if(n->nelse)
- fmtprint(f, " else { %H }", n->nelse);
- break;
-
- case OFOR:
- if(fmtmode == FErr) { // TODO maybe only if FmtShort, same below
- fmtstrcpy(f, "for loop");
- break;
- }
-
- fmtstrcpy(f, "for");
- if(simpleinit)
- fmtprint(f, " %N;", n->ninit->n);
- else if(n->nincr)
- fmtstrcpy(f, " ;");
-
- if(n->ntest)
- fmtprint(f, " %N", n->ntest);
-
- if(n->nincr)
- fmtprint(f, "; %N", n->nincr);
- else if(simpleinit)
- fmtstrcpy(f, ";");
-
-
- fmtprint(f, " { %H }", n->nbody);
- break;
-
- case ORANGE:
- if(fmtmode == FErr) {
- fmtstrcpy(f, "for loop");
- break;
- }
-
- if(n->list == nil) {
- fmtprint(f, "for range %N { %H }", n->right, n->nbody);
- break;
- }
- fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
- break;
-
- case OSELECT:
- case OSWITCH:
- if(fmtmode == FErr) {
- fmtprint(f, "%O statement", n->op);
- break;
- }
-
- fmtprint(f, "%#O", n->op);
- if(simpleinit)
- fmtprint(f, " %N;", n->ninit->n);
- if(n->ntest)
- fmtprint(f, "%N", n->ntest);
-
- fmtprint(f, " { %H }", n->list);
- break;
-
- case OCASE:
- case OXCASE:
- if(n->list)
- fmtprint(f, "case %,H: %H", n->list, n->nbody);
- else
- fmtprint(f, "default: %H", n->nbody);
- break;
-
- case OBREAK:
- case OCONTINUE:
- case OGOTO:
- case OFALL:
- case OXFALL:
- if(n->left)
- fmtprint(f, "%#O %N", n->op, n->left);
- else
- fmtprint(f, "%#O", n->op);
- break;
-
- case OEMPTY:
- break;
-
- case OLABEL:
- fmtprint(f, "%N: ", n->left);
- break;
-
- }
-ret:
-
- if(extrablock)
- fmtstrcpy(f, "}");
-
- return 0;
-}
-
-
-static int opprec[] = {
- [OAPPEND] = 8,
- [OARRAYBYTESTR] = 8,
- [OARRAYLIT] = 8,
- [OARRAYRUNESTR] = 8,
- [OCALLFUNC] = 8,
- [OCALLINTER] = 8,
- [OCALLMETH] = 8,
- [OCALL] = 8,
- [OCAP] = 8,
- [OCLOSE] = 8,
- [OCONVIFACE] = 8,
- [OCONVNOP] = 8,
- [OCONV] = 8,
- [OCOPY] = 8,
- [ODELETE] = 8,
- [OLEN] = 8,
- [OLITERAL] = 8,
- [OMAKESLICE] = 8,
- [OMAKE] = 8,
- [OMAPLIT] = 8,
- [ONAME] = 8,
- [ONEW] = 8,
- [ONONAME] = 8,
- [OPACK] = 8,
- [OPANIC] = 8,
- [OPAREN] = 8,
- [OPRINTN] = 8,
- [OPRINT] = 8,
- [ORUNESTR] = 8,
- [OSTRARRAYBYTE] = 8,
- [OSTRARRAYRUNE] = 8,
- [OSTRUCTLIT] = 8,
- [OTARRAY] = 8,
- [OTCHAN] = 8,
- [OTFUNC] = 8,
- [OTINTER] = 8,
- [OTMAP] = 8,
- [OTSTRUCT] = 8,
-
- [OINDEXMAP] = 8,
- [OINDEX] = 8,
- [OSLICE] = 8,
- [OSLICESTR] = 8,
- [OSLICEARR] = 8,
- [OSLICE3] = 8,
- [OSLICE3ARR] = 8,
- [ODOTINTER] = 8,
- [ODOTMETH] = 8,
- [ODOTPTR] = 8,
- [ODOTTYPE2] = 8,
- [ODOTTYPE] = 8,
- [ODOT] = 8,
- [OXDOT] = 8,
- [OCALLPART] = 8,
-
- [OPLUS] = 7,
- [ONOT] = 7,
- [OCOM] = 7,
- [OMINUS] = 7,
- [OADDR] = 7,
- [OIND] = 7,
- [ORECV] = 7,
-
- [OMUL] = 6,
- [ODIV] = 6,
- [OMOD] = 6,
- [OLSH] = 6,
- [ORSH] = 6,
- [OAND] = 6,
- [OANDNOT] = 6,
-
- [OADD] = 5,
- [OSUB] = 5,
- [OOR] = 5,
- [OXOR] = 5,
-
- [OEQ] = 4,
- [OLT] = 4,
- [OLE] = 4,
- [OGE] = 4,
- [OGT] = 4,
- [ONE] = 4,
- [OCMPSTR] = 4,
- [OCMPIFACE] = 4,
-
- [OSEND] = 3,
- [OANDAND] = 2,
- [OOROR] = 1,
-
- // Statements handled by stmtfmt
- [OAS] = -1,
- [OAS2] = -1,
- [OAS2DOTTYPE] = -1,
- [OAS2FUNC] = -1,
- [OAS2MAPR] = -1,
- [OAS2RECV] = -1,
- [OASOP] = -1,
- [OBREAK] = -1,
- [OCASE] = -1,
- [OCONTINUE] = -1,
- [ODCL] = -1,
- [ODCLFIELD] = -1,
- [ODEFER] = -1,
- [OEMPTY] = -1,
- [OFALL] = -1,
- [OFOR] = -1,
- [OGOTO] = -1,
- [OIF] = -1,
- [OLABEL] = -1,
- [OPROC] = -1,
- [ORANGE] = -1,
- [ORETURN] = -1,
- [OSELECT] = -1,
- [OSWITCH] = -1,
- [OXCASE] = -1,
- [OXFALL] = -1,
-
- [OEND] = 0
-};
-
-static int
-exprfmt(Fmt *f, Node *n, int prec)
-{
- int nprec;
- int ptrlit;
- NodeList *l;
-
- while(n && n->implicit && (n->op == OIND || n->op == OADDR))
- n = n->left;
-
- if(n == N)
- return fmtstrcpy(f, "<N>");
-
- nprec = opprec[n->op];
- if(n->op == OTYPE && n->sym != S)
- nprec = 8;
-
- if(prec > nprec)
- return fmtprint(f, "(%N)", n);
-
- switch(n->op) {
- case OPAREN:
- return fmtprint(f, "(%N)", n->left);
-
- case ODDDARG:
- return fmtprint(f, "... argument");
-
- case OREGISTER:
- return fmtprint(f, "%R", n->val.u.reg);
-
- case OLITERAL: // this is a bit of a mess
- if(fmtmode == FErr && n->sym != S)
- return fmtprint(f, "%S", n->sym);
- if(n->val.ctype == CTNIL && n->orig != N && n->orig != n)
- return exprfmt(f, n->orig, prec);
- if(n->type != T && n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) {
- // Need parens when type begins with what might
- // be misinterpreted as a unary operator: * or <-.
- if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv))
- return fmtprint(f, "(%T)(%V)", n->type, &n->val);
- else
- return fmtprint(f, "%T(%V)", n->type, &n->val);
- }
- return fmtprint(f, "%V", &n->val);
-
- case ONAME:
- // Special case: name used as local variable in export.
- // _ becomes ~b%d internally; print as _ for export
- if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
- return fmtprint(f, "_");
- if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
- return fmtprint(f, "%S·%d", n->sym, n->vargen);
-
- // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
- // but for export, this should be rendered as (*pkg.T).meth.
- // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
- if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) {
- if(isptr[n->left->type->etype])
- return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym);
- else
- return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym);
- }
- //fallthrough
- case OPACK:
- case ONONAME:
- return fmtprint(f, "%S", n->sym);
-
- case OTYPE:
- if(n->type == T && n->sym != S)
- return fmtprint(f, "%S", n->sym);
- return fmtprint(f, "%T", n->type);
-
- case OTARRAY:
- if(n->left)
- return fmtprint(f, "[]%N", n->left);
- return fmtprint(f, "[]%N", n->right); // happens before typecheck
-
- case OTMAP:
- return fmtprint(f, "map[%N]%N", n->left, n->right);
-
- case OTCHAN:
- switch(n->etype) {
- case Crecv:
- return fmtprint(f, "<-chan %N", n->left);
- case Csend:
- return fmtprint(f, "chan<- %N", n->left);
- default:
- if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv)
- return fmtprint(f, "chan (%N)", n->left);
- else
- return fmtprint(f, "chan %N", n->left);
- }
-
- case OTSTRUCT:
- return fmtprint(f, "<struct>");
-
- case OTINTER:
- return fmtprint(f, "<inter>");
-
- case OTFUNC:
- return fmtprint(f, "<func>");
-
- case OCLOSURE:
- if(fmtmode == FErr)
- return fmtstrcpy(f, "func literal");
- if(n->nbody)
- return fmtprint(f, "%T { %H }", n->type, n->nbody);
- return fmtprint(f, "%T { %H }", n->type, n->closure->nbody);
-
- case OCOMPLIT:
- ptrlit = n->right != N && n->right->implicit && n->right->type && isptr[n->right->type->etype];
- if(fmtmode == FErr) {
- if(n->right != N && n->right->type != T && !n->implicit) {
- if(ptrlit)
- return fmtprint(f, "&%T literal", n->right->type->type);
- else
- return fmtprint(f, "%T literal", n->right->type);
- }
- return fmtstrcpy(f, "composite literal");
- }
- if(fmtmode == FExp && ptrlit)
- // typecheck has overwritten OIND by OTYPE with pointer type.
- return fmtprint(f, "(&%T{ %,H })", n->right->type->type, n->list);
- return fmtprint(f, "(%N{ %,H })", n->right, n->list);
-
- case OPTRLIT:
- if(fmtmode == FExp && n->left->implicit)
- return fmtprint(f, "%N", n->left);
- return fmtprint(f, "&%N", n->left);
-
- case OSTRUCTLIT:
- if(fmtmode == FExp) { // requires special handling of field names
- if(n->implicit)
- fmtstrcpy(f, "{");
- else
- fmtprint(f, "(%T{", n->type);
- for(l=n->list; l; l=l->next) {
- fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right);
-
- if(l->next)
- fmtstrcpy(f, ",");
- else
- fmtstrcpy(f, " ");
- }
- if(!n->implicit)
- return fmtstrcpy(f, "})");
- return fmtstrcpy(f, "}");
- }
- // fallthrough
-
- case OARRAYLIT:
- case OMAPLIT:
- if(fmtmode == FErr)
- return fmtprint(f, "%T literal", n->type);
- if(fmtmode == FExp && n->implicit)
- return fmtprint(f, "{ %,H }", n->list);
- return fmtprint(f, "(%T{ %,H })", n->type, n->list);
-
- case OKEY:
- if(n->left && n->right) {
- if(fmtmode == FExp && n->left->type && n->left->type->etype == TFIELD) {
- // requires special handling of field names
- return fmtprint(f, "%hhS:%N", n->left->sym, n->right);
- } else
- return fmtprint(f, "%N:%N", n->left, n->right);
- }
- if(!n->left && n->right)
- return fmtprint(f, ":%N", n->right);
- if(n->left && !n->right)
- return fmtprint(f, "%N:", n->left);
- return fmtstrcpy(f, ":");
-
- case OXDOT:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- case OCALLPART:
- exprfmt(f, n->left, nprec);
- if(n->right == N || n->right->sym == S)
- return fmtstrcpy(f, ".<nil>");
- return fmtprint(f, ".%hhS", n->right->sym);
-
- case ODOTTYPE:
- case ODOTTYPE2:
- exprfmt(f, n->left, nprec);
- if(n->right != N)
- return fmtprint(f, ".(%N)", n->right);
- return fmtprint(f, ".(%T)", n->type);
-
- case OINDEX:
- case OINDEXMAP:
- case OSLICE:
- case OSLICESTR:
- case OSLICEARR:
- case OSLICE3:
- case OSLICE3ARR:
- exprfmt(f, n->left, nprec);
- return fmtprint(f, "[%N]", n->right);
-
- case OCOPY:
- case OCOMPLEX:
- return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right);
-
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case OARRAYBYTESTR:
- case OARRAYRUNESTR:
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- case ORUNESTR:
- if(n->type == T || n->type->sym == S)
- return fmtprint(f, "(%T)(%N)", n->type, n->left);
- if(n->left)
- return fmtprint(f, "%T(%N)", n->type, n->left);
- return fmtprint(f, "%T(%,H)", n->type, n->list);
-
- case OREAL:
- case OIMAG:
- case OAPPEND:
- case OCAP:
- case OCLOSE:
- case ODELETE:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case ORECOVER:
- case OPRINT:
- case OPRINTN:
- if(n->left)
- return fmtprint(f, "%#O(%N)", n->op, n->left);
- if(n->isddd)
- return fmtprint(f, "%#O(%,H...)", n->op, n->list);
- return fmtprint(f, "%#O(%,H)", n->op, n->list);
-
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- exprfmt(f, n->left, nprec);
- if(n->isddd)
- return fmtprint(f, "(%,H...)", n->list);
- return fmtprint(f, "(%,H)", n->list);
-
- case OMAKEMAP:
- case OMAKECHAN:
- case OMAKESLICE:
- if(n->list) // pre-typecheck
- return fmtprint(f, "make(%T, %,H)", n->type, n->list);
- if(n->right)
- return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
- if(n->left)
- return fmtprint(f, "make(%T, %N)", n->type, n->left);
- return fmtprint(f, "make(%T)", n->type);
-
- // Unary
- case OPLUS:
- case OMINUS:
- case OADDR:
- case OCOM:
- case OIND:
- case ONOT:
- case ORECV:
- if(n->left->op == n->op)
- fmtprint(f, "%#O ", n->op);
- else
- fmtprint(f, "%#O", n->op);
- return exprfmt(f, n->left, nprec+1);
-
- // Binary
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case ORSH:
- case OSEND:
- case OSUB:
- case OXOR:
- exprfmt(f, n->left, nprec);
- fmtprint(f, " %#O ", n->op);
- exprfmt(f, n->right, nprec+1);
- return 0;
-
- case OADDSTR:
- for(l=n->list; l; l=l->next) {
- if(l != n->list)
- fmtprint(f, " + ");
- exprfmt(f, l->n, nprec);
- }
- return 0;
-
- case OCMPSTR:
- case OCMPIFACE:
- exprfmt(f, n->left, nprec);
- fmtprint(f, " %#O ", n->etype);
- exprfmt(f, n->right, nprec+1);
- return 0;
- }
-
- return fmtprint(f, "<node %O>", n->op);
-}
-
-static int
-nodefmt(Fmt *f, Node *n)
-{
- Type *t;
-
- t = n->type;
-
- // we almost always want the original, except in export mode for literals
- // this saves the importer some work, and avoids us having to redo some
- // special casing for package unsafe
- if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N)
- n = n->orig;
-
- if(f->flags&FmtLong && t != T) {
- if(t->etype == TNIL)
- return fmtprint(f, "nil");
- else
- return fmtprint(f, "%N (type %T)", n, t);
- }
-
- // TODO inlining produces expressions with ninits. we can't print these yet.
-
- if(opprec[n->op] < 0)
- return stmtfmt(f, n);
-
- return exprfmt(f, n, 0);
-}
-
-static int dumpdepth;
-
-static void
-indent(Fmt *fp)
-{
- int i;
-
- fmtstrcpy(fp, "\n");
- for(i = 0; i < dumpdepth; ++i)
- fmtstrcpy(fp, ". ");
-}
-
-static int
-nodedump(Fmt *fp, Node *n)
-{
- int recur;
-
- if(n == N)
- return 0;
-
- recur = !(fp->flags&FmtShort);
-
- if(recur) {
- indent(fp);
- if(dumpdepth > 10)
- return fmtstrcpy(fp, "...");
-
- if(n->ninit != nil) {
- fmtprint(fp, "%O-init%H", n->op, n->ninit);
- indent(fp);
- }
- }
-
-// fmtprint(fp, "[%p]", n);
-
- switch(n->op) {
- default:
- fmtprint(fp, "%O%J", n->op, n);
- break;
- case OREGISTER:
- case OINDREG:
- fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
- break;
- case OLITERAL:
- fmtprint(fp, "%O-%V%J", n->op, &n->val, n);
- break;
- case ONAME:
- case ONONAME:
- if(n->sym != S)
- fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
- else
- fmtprint(fp, "%O%J", n->op, n);
- if(recur && n->type == T && n->ntype) {
- indent(fp);
- fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
- }
- break;
- case OASOP:
- fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
- break;
- case OTYPE:
- fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type);
- if(recur && n->type == T && n->ntype) {
- indent(fp);
- fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
- }
- break;
- }
-
- if(n->sym != S && n->op != ONAME)
- fmtprint(fp, " %S G%d", n->sym, n->vargen);
-
- if(n->type != T)
- fmtprint(fp, " %T", n->type);
-
- if(recur) {
- if(n->left)
- fmtprint(fp, "%N", n->left);
- if(n->right)
- fmtprint(fp, "%N", n->right);
- if(n->list) {
- indent(fp);
- fmtprint(fp, "%O-list%H", n->op, n->list);
- }
- if(n->rlist) {
- indent(fp);
- fmtprint(fp, "%O-rlist%H", n->op, n->rlist);
- }
- if(n->ntest) {
- indent(fp);
- fmtprint(fp, "%O-test%N", n->op, n->ntest);
- }
- if(n->nbody) {
- indent(fp);
- fmtprint(fp, "%O-body%H", n->op, n->nbody);
- }
- if(n->nelse) {
- indent(fp);
- fmtprint(fp, "%O-else%H", n->op, n->nelse);
- }
- if(n->nincr) {
- indent(fp);
- fmtprint(fp, "%O-incr%N", n->op, n->nincr);
- }
- }
-
- return 0;
-}
-
-// Fmt "%S": syms
-// Flags: "%hS" suppresses qualifying with package
-static int
-Sconv(Fmt *fp)
-{
- Sym *s;
- int r, sm;
- unsigned long sf;
-
- if(fp->flags&FmtLong)
- return linksymfmt(fp);
-
- s = va_arg(fp->args, Sym*);
- if(s == S)
- return fmtstrcpy(fp, "<S>");
-
- if(s->name && s->name[0] == '_' && s->name[1] == '\0')
- return fmtstrcpy(fp, "_");
-
- sf = fp->flags;
- sm = setfmode(&fp->flags);
- r = symfmt(fp, s);
- fp->flags = sf;
- fmtmode = sm;
- return r;
-}
-
-// Fmt "%T": types.
-// Flags: 'l' print definition, not name
-// 'h' omit 'func' and receiver from function types, short type names
-// 'u' package name, not prefix (FTypeId mode, sticky)
-int
-Tconv(Fmt *fp)
-{
- Type *t;
- int r, sm;
- unsigned long sf;
-
- t = va_arg(fp->args, Type*);
- if(t == T)
- return fmtstrcpy(fp, "<T>");
-
- if(t->trecur > 4)
- return fmtstrcpy(fp, "<...>");
-
- t->trecur++;
- sf = fp->flags;
- sm = setfmode(&fp->flags);
-
- if(fmtmode == FTypeId && (sf&FmtUnsigned))
- fmtpkgpfx++;
- if(fmtpkgpfx)
- fp->flags |= FmtUnsigned;
-
- r = typefmt(fp, t);
-
- if(fmtmode == FTypeId && (sf&FmtUnsigned))
- fmtpkgpfx--;
-
- fp->flags = sf;
- fmtmode = sm;
- t->trecur--;
- return r;
-}
-
-// Fmt '%N': Nodes.
-// Flags: 'l' suffix with "(type %T)" where possible
-// '+h' in debug mode, don't recurse, no multiline output
-static int
-Nconv(Fmt *fp)
-{
- Node *n;
- int r, sm;
- unsigned long sf;
-
- n = va_arg(fp->args, Node*);
- if(n == N)
- return fmtstrcpy(fp, "<N>");
- sf = fp->flags;
- sm = setfmode(&fp->flags);
-
- r = -1;
- switch(fmtmode) {
- case FErr:
- case FExp:
- r = nodefmt(fp, n);
- break;
- case FDbg:
- dumpdepth++;
- r = nodedump(fp, n);
- dumpdepth--;
- break;
- default:
- fatal("unhandled %%N mode");
- }
-
- fp->flags = sf;
- fmtmode = sm;
- return r;
-}
-
-// Fmt '%H': NodeList.
-// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
-static int
-Hconv(Fmt *fp)
-{
- NodeList *l;
- int r, sm;
- unsigned long sf;
- char *sep;
-
- l = va_arg(fp->args, NodeList*);
-
- if(l == nil && fmtmode == FDbg)
- return fmtstrcpy(fp, "<nil>");
-
- sf = fp->flags;
- sm = setfmode(&fp->flags);
- r = 0;
- sep = "; ";
- if(fmtmode == FDbg)
- sep = "\n";
- else if(fp->flags & FmtComma)
- sep = ", ";
-
- for(;l; l=l->next) {
- r += fmtprint(fp, "%N", l->n);
- if(l->next)
- r += fmtstrcpy(fp, sep);
- }
-
- fp->flags = sf;
- fmtmode = sm;
- return r;
-}
-
-void
-fmtinstallgo(void)
-{
- fmtmode = FErr;
- fmtinstall('E', Econv); // etype opcodes
- fmtinstall('J', Jconv); // all the node flags
- fmtinstall('H', Hconv); // node lists
- fmtinstall('L', Lconv); // line number
- fmtinstall('N', Nconv); // node pointer
- fmtinstall('O', Oconv); // node opcodes
- fmtinstall('S', Sconv); // sym pointer
- fmtinstall('T', Tconv); // type pointer
- fmtinstall('V', Vconv); // val pointer
- fmtinstall('Z', Zconv); // escaped string
-
- // These are in mparith1.c
- fmtinstall('B', Bconv); // big numbers
- fmtinstall('F', Fconv); // big float numbers
-
-}
-
-void
-dumplist(char *s, NodeList *l)
-{
- print("%s%+H\n", s, l);
-}
-
-void
-dump(char *s, Node *n)
-{
- print("%s [%p]%+N\n", s, n, n);
-}
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
deleted file mode 100644
index 72bcc492a5..0000000000
--- a/src/cmd/gc/gen.c
+++ /dev/null
@@ -1,987 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * portable half of code generator.
- * mainly statements and control flow.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static void cgen_dcl(Node *n);
-static void cgen_proc(Node *n, int proc);
-static void checkgoto(Node*, Node*);
-
-static Label *labellist;
-static Label *lastlabel;
-
-Node*
-sysfunc(char *name)
-{
- Node *n;
-
- n = newname(pkglookup(name, runtimepkg));
- n->class = PFUNC;
- return n;
-}
-
-/*
- * the address of n has been taken and might be used after
- * the current function returns. mark any local vars
- * as needing to move to the heap.
- */
-void
-addrescapes(Node *n)
-{
- char buf[100];
- Node *oldfn;
-
- switch(n->op) {
- default:
- // probably a type error already.
- // dump("addrescapes", n);
- break;
-
- case ONAME:
- if(n == nodfp)
- break;
-
- // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
- // on PPARAM it means something different.
- if(n->class == PAUTO && n->esc == EscNever)
- break;
-
- switch(n->class) {
- case PPARAMREF:
- addrescapes(n->defn);
- break;
- case PPARAM:
- case PPARAMOUT:
- // if func param, need separate temporary
- // to hold heap pointer.
- // the function type has already been checked
- // (we're in the function body)
- // so the param already has a valid xoffset.
-
- // expression to refer to stack copy
- n->stackparam = nod(OPARAM, n, N);
- n->stackparam->type = n->type;
- n->stackparam->addable = 1;
- if(n->xoffset == BADWIDTH)
- fatal("addrescapes before param assignment");
- n->stackparam->xoffset = n->xoffset;
- // fallthrough
-
- case PAUTO:
- n->class |= PHEAP;
- n->addable = 0;
- n->ullman = 2;
- n->xoffset = 0;
-
- // create stack variable to hold pointer to heap
- oldfn = curfn;
- curfn = n->curfn;
- n->heapaddr = temp(ptrto(n->type));
- snprint(buf, sizeof buf, "&%S", n->sym);
- n->heapaddr->sym = lookup(buf);
- n->heapaddr->orig->sym = n->heapaddr->sym;
- n->esc = EscHeap;
- if(debug['m'])
- print("%L: moved to heap: %N\n", n->lineno, n);
- curfn = oldfn;
- break;
- }
- break;
-
- case OIND:
- case ODOTPTR:
- break;
-
- case ODOT:
- case OINDEX:
- // ODOTPTR has already been introduced,
- // so these are the non-pointer ODOT and OINDEX.
- // In &x[0], if x is a slice, then x does not
- // escape--the pointer inside x does, but that
- // is always a heap pointer anyway.
- if(!isslice(n->left->type))
- addrescapes(n->left);
- break;
- }
-}
-
-void
-clearlabels(void)
-{
- Label *l;
-
- for(l=labellist; l!=L; l=l->link)
- l->sym->label = L;
-
- labellist = L;
- lastlabel = L;
-}
-
-static Label*
-newlab(Node *n)
-{
- Sym *s;
- Label *lab;
-
- s = n->left->sym;
- if((lab = s->label) == L) {
- lab = mal(sizeof(*lab));
- if(lastlabel == nil)
- labellist = lab;
- else
- lastlabel->link = lab;
- lastlabel = lab;
- lab->sym = s;
- s->label = lab;
- }
-
- if(n->op == OLABEL) {
- if(lab->def != N)
- yyerror("label %S already defined at %L", s, lab->def->lineno);
- else
- lab->def = n;
- } else
- lab->use = list(lab->use, n);
-
- return lab;
-}
-
-void
-checklabels(void)
-{
- Label *lab;
- NodeList *l;
-
- for(lab=labellist; lab!=L; lab=lab->link) {
- if(lab->def == N) {
- for(l=lab->use; l; l=l->next)
- yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
- continue;
- }
- if(lab->use == nil && !lab->used) {
- yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
- continue;
- }
- if(lab->gotopc != P)
- fatal("label %S never resolved", lab->sym);
- for(l=lab->use; l; l=l->next)
- checkgoto(l->n, lab->def);
- }
-}
-
-static void
-checkgoto(Node *from, Node *to)
-{
- int nf, nt;
- Sym *block, *dcl, *fs, *ts;
- int lno;
-
- if(from->sym == to->sym)
- return;
-
- nf = 0;
- for(fs=from->sym; fs; fs=fs->link)
- nf++;
- nt = 0;
- for(fs=to->sym; fs; fs=fs->link)
- nt++;
- fs = from->sym;
- for(; nf > nt; nf--)
- fs = fs->link;
- if(fs != to->sym) {
- lno = lineno;
- setlineno(from);
-
- // decide what to complain about.
- // prefer to complain about 'into block' over declarations,
- // so scan backward to find most recent block or else dcl.
- block = S;
- dcl = S;
- ts = to->sym;
- for(; nt > nf; nt--) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- }
- while(ts != fs) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- fs = fs->link;
- }
-
- if(block)
- yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
- else
- yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
- lineno = lno;
- }
-}
-
-static Label*
-stmtlabel(Node *n)
-{
- Label *lab;
-
- if(n->sym != S)
- if((lab = n->sym->label) != L)
- if(lab->def != N)
- if(lab->def->defn == n)
- return lab;
- return L;
-}
-
-/*
- * compile statements
- */
-void
-genlist(NodeList *l)
-{
- for(; l; l=l->next)
- gen(l->n);
-}
-
-void
-gen(Node *n)
-{
- int32 lno;
- Prog *scontin, *sbreak;
- Prog *p1, *p2, *p3;
- Label *lab;
- int32 wasregalloc;
-
-//dump("gen", n);
-
- lno = setlineno(n);
- wasregalloc = thearch.anyregalloc();
-
- if(n == N)
- goto ret;
-
- if(n->ninit)
- genlist(n->ninit);
-
- setlineno(n);
-
- switch(n->op) {
- default:
- fatal("gen: unknown op %+hN", n);
- break;
-
- case OCASE:
- case OFALL:
- case OXCASE:
- case OXFALL:
- case ODCLCONST:
- case ODCLFUNC:
- case ODCLTYPE:
- break;
-
- case OEMPTY:
- break;
-
- case OBLOCK:
- genlist(n->list);
- break;
-
- case OLABEL:
- if(isblanksym(n->left->sym))
- break;
-
- lab = newlab(n);
-
- // if there are pending gotos, resolve them all to the current pc.
- for(p1=lab->gotopc; p1; p1=p2) {
- p2 = unpatch(p1);
- patch(p1, pc);
- }
- lab->gotopc = P;
- if(lab->labelpc == P)
- lab->labelpc = pc;
-
- if(n->defn) {
- switch(n->defn->op) {
- case OFOR:
- case OSWITCH:
- case OSELECT:
- // so stmtlabel can find the label
- n->defn->sym = lab->sym;
- }
- }
- break;
-
- case OGOTO:
- // if label is defined, emit jump to it.
- // otherwise save list of pending gotos in lab->gotopc.
- // the list is linked through the normal jump target field
- // to avoid a second list. (the jumps are actually still
- // valid code, since they're just going to another goto
- // to the same label. we'll unwind it when we learn the pc
- // of the label in the OLABEL case above.)
- lab = newlab(n);
- if(lab->labelpc != P)
- gjmp(lab->labelpc);
- else
- lab->gotopc = gjmp(lab->gotopc);
- break;
-
- case OBREAK:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("break label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->breakpc == P) {
- yyerror("invalid break label %S", n->left->sym);
- break;
- }
- gjmp(lab->breakpc);
- break;
- }
- if(breakpc == P) {
- yyerror("break is not in a loop");
- break;
- }
- gjmp(breakpc);
- break;
-
- case OCONTINUE:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("continue label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->continpc == P) {
- yyerror("invalid continue label %S", n->left->sym);
- break;
- }
- gjmp(lab->continpc);
- break;
- }
- if(continpc == P) {
- yyerror("continue is not in a loop");
- break;
- }
- gjmp(continpc);
- break;
-
- case OFOR:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
- scontin = continpc;
- continpc = pc;
-
- // define break and continue labels
- if((lab = stmtlabel(n)) != L) {
- lab->breakpc = breakpc;
- lab->continpc = continpc;
- }
- gen(n->nincr); // contin: incr
- patch(p1, pc); // test:
- thearch.bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break
- genlist(n->nbody); // body
- gjmp(continpc);
- patch(breakpc, pc); // done:
- continpc = scontin;
- breakpc = sbreak;
- if(lab) {
- lab->breakpc = P;
- lab->continpc = P;
- }
- break;
-
- case OIF:
- p1 = gjmp(P); // goto test
- p2 = gjmp(P); // p2: goto else
- patch(p1, pc); // test:
- thearch.bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2
- genlist(n->nbody); // then
- p3 = gjmp(P); // goto done
- patch(p2, pc); // else:
- genlist(n->nelse); // else
- patch(p3, pc); // done:
- break;
-
- case OSWITCH:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // switch(test) body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OSELECT:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // select() body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case ODCL:
- cgen_dcl(n->left);
- break;
-
- case OAS:
- if(gen_as_init(n))
- break;
- cgen_as(n->left, n->right);
- break;
-
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
-
- case OCALLINTER:
- thearch.cgen_callinter(n, N, 0);
- break;
-
- case OCALLFUNC:
- thearch.cgen_call(n, 0);
- break;
-
- case OPROC:
- cgen_proc(n, 1);
- break;
-
- case ODEFER:
- cgen_proc(n, 2);
- break;
-
- case ORETURN:
- case ORETJMP:
- thearch.cgen_ret(n);
- break;
-
- case OCHECKNIL:
- cgen_checknil(n->left);
- break;
-
- case OVARKILL:
- gvarkill(n->left);
- break;
- }
-
-ret:
- if(thearch.anyregalloc() != wasregalloc) {
- dump("node", n);
- fatal("registers left allocated");
- }
-
- lineno = lno;
-}
-
-/*
- * generate call to non-interface method
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_callmeth(Node *n, int proc)
-{
- Node n2;
- Node *l;
-
- // generate a rewrite in n2 for the method call
- // (p.f)(...) goes to (f)(p,...)
-
- l = n->left;
- if(l->op != ODOTMETH)
- fatal("cgen_callmeth: not dotmethod: %N");
-
- n2 = *n;
- n2.op = OCALLFUNC;
- n2.left = l->right;
- n2.left->type = l->type;
-
- if(n2.left->op == ONAME)
- n2.left->class = PFUNC;
- thearch.cgen_call(&n2, proc);
-}
-
-/*
- * generate code to start new proc running call n.
- */
-static void
-cgen_proc(Node *n, int proc)
-{
- switch(n->left->op) {
- default:
- fatal("cgen_proc: unknown call %O", n->left->op);
-
- case OCALLMETH:
- cgen_callmeth(n->left, proc);
- break;
-
- case OCALLINTER:
- thearch.cgen_callinter(n->left, N, proc);
- break;
-
- case OCALLFUNC:
- thearch.cgen_call(n->left, proc);
- break;
- }
-
-}
-
-/*
- * generate declaration.
- * have to allocate heap copy
- * for escaped variables.
- */
-static void
-cgen_dcl(Node *n)
-{
- if(debug['g'])
- dump("\ncgen-dcl", n);
- if(n->op != ONAME) {
- dump("cgen_dcl", n);
- fatal("cgen_dcl");
- }
- if(!(n->class & PHEAP))
- return;
- if(compiling_runtime)
- yyerror("%N escapes to heap, not allowed in runtime.", n);
- if(n->alloc == nil)
- n->alloc = callnew(n->type);
- cgen_as(n->heapaddr, n->alloc);
-}
-
-/*
- * generate discard of value
- */
-static void
-cgen_discard(Node *nr)
-{
- Node tmp;
-
- if(nr == N)
- return;
-
- switch(nr->op) {
- case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
- gused(nr);
- break;
-
- // unary
- case OADD:
- case OAND:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case ORSH:
- case OSUB:
- case OXOR:
- cgen_discard(nr->left);
- cgen_discard(nr->right);
- break;
-
- // binary
- case OCAP:
- case OCOM:
- case OLEN:
- case OMINUS:
- case ONOT:
- case OPLUS:
- cgen_discard(nr->left);
- break;
-
- case OIND:
- cgen_checknil(nr->left);
- break;
-
- // special enough to just evaluate
- default:
- tempname(&tmp, nr->type);
- cgen_as(&tmp, nr);
- gused(&tmp);
- }
-}
-
-/*
- * clearslim generates code to zero a slim node.
- */
-void
-clearslim(Node *n)
-{
- Node z;
- Mpflt zero;
-
- memset(&z, 0, sizeof(z));
- z.op = OLITERAL;
- z.type = n->type;
- z.addable = 1;
-
- switch(simtype[n->type->etype]) {
- case TCOMPLEX64:
- case TCOMPLEX128:
- z.val.u.cval = mal(sizeof(*z.val.u.cval));
- mpmovecflt(&z.val.u.cval->real, 0.0);
- mpmovecflt(&z.val.u.cval->imag, 0.0);
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- mpmovecflt(&zero, 0.0);
- z.val.ctype = CTFLT;
- z.val.u.fval = &zero;
- break;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TMAP:
- z.val.ctype = CTNIL;
- break;
-
- case TBOOL:
- z.val.ctype = CTBOOL;
- break;
-
- case TINT8:
- case TINT16:
- case TINT32:
- case TINT64:
- case TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- z.val.ctype = CTINT;
- z.val.u.xval = mal(sizeof(*z.val.u.xval));
- mpmovecfix(z.val.u.xval, 0);
- break;
-
- default:
- fatal("clearslim called on type %T", n->type);
- }
-
- ullmancalc(&z);
- thearch.cgen(&z, n);
-}
-
-/*
- * generate assignment:
- * nl = nr
- * nr == N means zero nl.
- */
-void
-cgen_as(Node *nl, Node *nr)
-{
- Type *tl;
-
- if(debug['g']) {
- dump("cgen_as", nl);
- dump("cgen_as = ", nr);
- }
-
- while(nr != N && nr->op == OCONVNOP)
- nr = nr->left;
-
- if(nl == N || isblank(nl)) {
- cgen_discard(nr);
- return;
- }
-
- if(nr == N || iszero(nr)) {
- // heaps should already be clear
- if(nr == N && (nl->class & PHEAP))
- return;
-
- tl = nl->type;
- if(tl == T)
- return;
- if(isfat(tl)) {
- if(nl->op == ONAME)
- gvardef(nl);
- thearch.clearfat(nl);
- return;
- }
- clearslim(nl);
- return;
- }
-
- tl = nl->type;
- if(tl == T)
- return;
-
- thearch.cgen(nr, nl);
-}
-
-/*
- * generate:
- * res = iface{typ, data}
- * n->left is typ
- * n->right is data
- */
-void
-cgen_eface(Node *n, Node *res)
-{
- /*
- * the right node of an eface may contain function calls that uses res as an argument,
- * so it's important that it is done first
- */
- Node dst;
- Node *tmp;
-
- tmp = temp(types[tptr]);
- thearch.cgen(n->right, tmp);
-
- gvardef(res);
-
- dst = *res;
- dst.type = types[tptr];
- dst.xoffset += widthptr;
- thearch.cgen(tmp, &dst);
-
- dst.xoffset -= widthptr;
- thearch.cgen(n->left, &dst);
-}
-
-/*
- * generate:
- * res = s[lo, hi];
- * n->left is s
- * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
- * caller (cgen) guarantees res is an addable ONAME.
- *
- * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
- */
-void
-cgen_slice(Node *n, Node *res)
-{
- Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con;
- Prog *p1, *p2;
-
- cap = n->list->n;
- len = n->list->next->n;
- offs = N;
- if(n->list->next->next)
- offs = n->list->next->next->n;
-
- // evaluate base pointer first, because it is the only
- // possibly complex expression. once that is evaluated
- // and stored, updating the len and cap can be done
- // without making any calls, so without doing anything that
- // might cause preemption or garbage collection.
- // this makes the whole slice update atomic as far as the
- // garbage collector can see.
-
- base = temp(types[TUINTPTR]);
- tmplen = temp(types[TINT]);
- if(n->op != OSLICESTR)
- tmpcap = temp(types[TINT]);
- else
- tmpcap = tmplen;
-
- if(isnil(n->left)) {
- tempname(&src, n->left->type);
- thearch.cgen(n->left, &src);
- } else
- src = *n->left;
- if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
- src.xoffset += Array_array;
-
- if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
- if(!isptr[n->left->type->etype])
- fatal("slicearr is supposed to work on pointer: %+N\n", n);
- thearch.cgen(&src, base);
- cgen_checknil(base);
- } else {
- src.type = types[tptr];
- thearch.cgen(&src, base);
- }
-
- // committed to the update
- gvardef(res);
-
- // compute len and cap.
- // len = n-i, cap = m-i, and offs = i*width.
- // computing offs last lets the multiply overwrite i.
- thearch.cgen(len, tmplen);
- if(n->op != OSLICESTR)
- thearch.cgen(cap, tmpcap);
-
- // if new cap != 0 { base += add }
- // This avoids advancing base past the end of the underlying array/string,
- // so that it cannot point at the next object in memory.
- // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
- // In essence we are replacing x[i:j:k] where i == j == k
- // or x[i:j] where i == j == cap(x) with x[0:0:0].
- if(offs != N) {
- p1 = gjmp(P);
- p2 = gjmp(P);
- patch(p1, pc);
-
- nodconst(&con, tmpcap->type, 0);
- cmp = nod(OEQ, tmpcap, &con);
- typecheck(&cmp, Erv);
- thearch.bgen(cmp, 1, -1, p2);
-
- add = nod(OADD, base, offs);
- typecheck(&add, Erv);
- thearch.cgen(add, base);
-
- patch(p2, pc);
- }
-
- // dst.array = src.array [ + lo *width ]
- dst = *res;
- dst.xoffset += Array_array;
- dst.type = types[tptr];
- thearch.cgen(base, &dst);
-
- // dst.len = hi [ - lo ]
- dst = *res;
- dst.xoffset += Array_nel;
- dst.type = types[simtype[TUINT]];
- thearch.cgen(tmplen, &dst);
-
- if(n->op != OSLICESTR) {
- // dst.cap = cap [ - lo ]
- dst = *res;
- dst.xoffset += Array_cap;
- dst.type = types[simtype[TUINT]];
- thearch.cgen(tmpcap, &dst);
- }
-}
-
-/*
- * gather series of offsets
- * >=0 is direct addressed field
- * <0 is pointer to next field (+1)
- */
-int
-dotoffset(Node *n, int64 *oary, Node **nn)
-{
- int i;
-
- switch(n->op) {
- case ODOT:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i > 0) {
- if(oary[i-1] >= 0)
- oary[i-1] += n->xoffset;
- else
- oary[i-1] -= n->xoffset;
- break;
- }
- if(i < 10)
- oary[i++] = n->xoffset;
- break;
-
- case ODOTPTR:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i < 10)
- oary[i++] = -(n->xoffset+1);
- break;
-
- default:
- *nn = n;
- return 0;
- }
- if(i >= 10)
- *nn = N;
- return i;
-}
-
-/*
- * make a new off the books
- */
-void
-tempname(Node *nn, Type *t)
-{
- Node *n;
- Sym *s;
-
- if(curfn == N)
- fatal("no curfn for tempname");
-
- if(t == T) {
- yyerror("tempname called with nil type");
- t = types[TINT32];
- }
-
- // give each tmp a different name so that there
- // a chance to registerizer them
- snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
- statuniqgen++;
- s = lookup(namebuf);
- n = nod(ONAME, N, N);
- n->sym = s;
- s->def = n;
- n->type = t;
- n->class = PAUTO;
- n->addable = 1;
- n->ullman = 1;
- n->esc = EscNever;
- n->curfn = curfn;
- curfn->dcl = list(curfn->dcl, n);
-
- dowidth(t);
- n->xoffset = 0;
- *nn = *n;
-}
-
-Node*
-temp(Type *t)
-{
- Node *n;
-
- n = nod(OXXX, N, N);
- tempname(n, t);
- n->sym->def->used = 1;
- return n->orig;
-}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
deleted file mode 100644
index f90d619901..0000000000
--- a/src/cmd/gc/go.errors
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
- int yystate;
- int yychar;
- char *msg;
-} yymsg[] = {
- // Each line of the form % token list
- // is converted by bisonerrors into the yystate and yychar caused
- // by that token list.
-
- % loadsys package LIMPORT '(' LLITERAL import_package import_there ','
- "unexpected comma during import block",
-
- % loadsys package LIMPORT LNAME ';'
- "missing import path; require quoted string",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
- "missing { after if clause",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
- "missing { after switch clause",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
- "missing { after for clause",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
- "missing { after for clause",
-
- % loadsys package imports LFUNC LNAME '(' ')' ';' '{'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LTYPE LNAME ';'
- "unexpected semicolon or newline in type declaration",
-
- % loadsys package imports LCHAN '}'
- "unexpected } in channel type",
-
- % loadsys package imports LCHAN ')'
- "unexpected ) in channel type",
-
- % loadsys package imports LCHAN ','
- "unexpected comma in channel type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
- "unexpected semicolon or newline before else",
-
- % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
- "name list not allowed in interface type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
- "var declaration not allowed in for initializer",
-
- % loadsys package imports LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
- "argument to go/defer must be function call",
-
- % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
- "need trailing comma before newline in composite literal",
-
- % loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';'
- "need trailing comma before newline in composite literal",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
- "nested func not allowed",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
- "else must be followed by if or statement block"
-};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
deleted file mode 100644
index 92584f6c58..0000000000
--- a/src/cmd/gc/go.h
+++ /dev/null
@@ -1,1757 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <bio.h>
-#include <link.h>
-
-#undef OAPPEND
-
-// avoid <ctype.h>
-#undef isblank
-#define isblank goisblank
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef BUFSIZ
-
-// The parser's maximum stack size.
-// We have to use a #define macro here since yacc
-// or bison will check for its definition and use
-// a potentially smaller value if it is undefined.
-#define YYMAXDEPTH 500
-
-enum
-{
- NHUNK = 50000,
- BUFSIZ = 8192,
- NSYMB = 500,
- NHASH = 1024,
- STRINGSZ = 200,
- MAXALIGN = 7,
- UINF = 100,
-
- PRIME1 = 3,
-
- AUNK = 100,
-
- // These values are known by runtime.
- // The MEMx and NOEQx values must run in parallel. See algtype.
- AMEM = 0,
- AMEM0,
- AMEM8,
- AMEM16,
- AMEM32,
- AMEM64,
- AMEM128,
- ANOEQ,
- ANOEQ0,
- ANOEQ8,
- ANOEQ16,
- ANOEQ32,
- ANOEQ64,
- ANOEQ128,
- ASTRING,
- AINTER,
- ANILINTER,
- ASLICE,
- AFLOAT32,
- AFLOAT64,
- ACPLX64,
- ACPLX128,
-
- BADWIDTH = -1000000000,
-
- MaxStackVarSize = 10*1024*1024,
-};
-
-/*
- * note this is the representation
- * of the compilers string literals,
- * it is not the runtime representation
- */
-typedef struct Strlit Strlit;
-struct Strlit
-{
- int32 len;
- char s[1]; // variable
-};
-
-enum
-{
- Mpscale = 29, // safely smaller than bits in a long
- Mpprec = 16, // Mpscale*Mpprec is max number of bits
- Mpnorm = Mpprec - 1, // significant words in a normalized float
- Mpbase = 1L << Mpscale,
- Mpsign = Mpbase >> 1,
- Mpmask = Mpbase - 1,
- Mpdebug = 0,
-};
-
-typedef struct Mpint Mpint;
-struct Mpint
-{
- long a[Mpprec];
- uchar neg;
- uchar ovf;
-};
-
-typedef struct Mpflt Mpflt;
-struct Mpflt
-{
- Mpint val;
- short exp;
-};
-
-typedef struct Mpcplx Mpcplx;
-struct Mpcplx
-{
- Mpflt real;
- Mpflt imag;
-};
-
-typedef struct Val Val;
-struct Val
-{
- short ctype;
- union
- {
- short reg; // OREGISTER
- short bval; // bool value CTBOOL
- Mpint* xval; // int CTINT, rune CTRUNE
- Mpflt* fval; // float CTFLT
- Mpcplx* cval; // float CTCPLX
- Strlit* sval; // string CTSTR
- } u;
-};
-typedef struct Array Array;
-typedef struct Bvec Bvec;
-typedef struct Pkg Pkg;
-typedef struct Sym Sym;
-typedef struct Node Node;
-typedef struct NodeList NodeList;
-typedef struct Type Type;
-typedef struct Label Label;
-
-struct Array
-{
- int32 length; // number of elements
- int32 size; // element size
- int32 capacity; // size of data in elements
- char *data; // element storage
-};
-
-struct Type
-{
- uchar etype;
- uchar nointerface;
- uchar noalg;
- uchar chan;
- uchar trecur; // to detect loops
- uchar printed;
- uchar embedded; // TFIELD embedded type
- uchar siggen;
- uchar funarg; // on TSTRUCT and TFIELD
- uchar copyany;
- uchar local; // created in this file
- uchar deferwidth;
- uchar broke; // broken type definition.
- uchar isddd; // TFIELD is ... argument
- uchar align;
- uchar haspointers; // 0 unknown, 1 no, 2 yes
-
- Node* nod; // canonical OTYPE node
- Type* orig; // original type (type literal or predefined type)
- int lineno;
-
- // TFUNC
- int thistuple;
- int outtuple;
- int intuple;
- uchar outnamed;
-
- Type* method;
- Type* xmethod;
-
- Sym* sym;
- int32 vargen; // unique name for OTYPE/ONAME
-
- Node* nname;
- vlong argwid;
-
- // most nodes
- Type* type; // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
- vlong width; // offset in TFIELD, width in all others
-
- // TFIELD
- Type* down; // next struct field, also key type in TMAP
- Type* outer; // outer struct
- Strlit* note; // literal string annotation
-
- // TARRAY
- vlong bound; // negative is dynamic array
-
- // TMAP
- Type* bucket; // internal type representing a hash bucket
- Type* hmap; // internal type representing a Hmap (map header object)
- Type* hiter; // internal type representing hash iterator state
- Type* map; // link from the above 3 internal types back to the map type.
-
- int32 maplineno; // first use of TFORW as map key
- int32 embedlineno; // first use of TFORW as embedded type
-
- // for TFORW, where to copy the eventual value to
- NodeList *copyto;
-
- Node *lastfn; // for usefield
-};
-#define T ((Type*)0)
-
-typedef struct InitEntry InitEntry;
-typedef struct InitPlan InitPlan;
-
-struct InitEntry
-{
- vlong xoffset; // struct, array only
- Node *key; // map only
- Node *expr;
-};
-
-struct InitPlan
-{
- vlong lit; // bytes of initialized non-zero literals
- vlong zero; // bytes of zeros
- vlong expr; // bytes of run-time computed expressions
-
- InitEntry *e;
- int len;
- int cap;
-};
-
-enum
-{
- EscUnknown,
- EscHeap,
- EscScope,
- EscNone,
- EscReturn,
- EscNever,
- EscBits = 3,
- EscMask = (1<<EscBits) - 1,
- EscContentEscapes = 1<<EscBits, // value obtained by indirect of parameter escapes to some returned result
- EscReturnBits = EscBits+1,
-};
-
-struct Node
-{
- // Tree structure.
- // Generic recursive walks should follow these fields.
- Node* left;
- Node* right;
- Node* ntest;
- Node* nincr;
- NodeList* ninit;
- NodeList* nbody;
- NodeList* nelse;
- NodeList* list;
- NodeList* rlist;
-
- uchar op;
- uchar nointerface;
- uchar ullman; // sethi/ullman number
- uchar addable; // type of addressability - 0 is not addressable
- uchar trecur; // to detect loops
- uchar etype; // op for OASOP, etype for OTYPE, exclam for export
- uchar bounded; // bounds check unnecessary
- uchar class; // PPARAM, PAUTO, PEXTERN, etc
- uchar method; // OCALLMETH name
- uchar embedded; // ODCLFIELD embedded type
- uchar colas; // OAS resulting from :=
- uchar diag; // already printed error about this
- uchar noescape; // func arguments do not escape
- uchar nosplit; // func should not execute on separate stack
- uchar builtin; // built-in name, like len or close
- uchar nowritebarrier; // emit compiler error instead of write barrier
- uchar walkdef;
- uchar typecheck;
- uchar local;
- uchar dodata;
- uchar initorder;
- uchar used;
- uchar isddd;
- uchar readonly;
- uchar implicit;
- uchar addrtaken; // address taken, even if not moved to heap
- uchar assigned; // is the variable ever assigned to
- uchar captured; // is the variable captured by a closure
- uchar byval; // is the variable captured by value or by reference
- uchar dupok; // duplicate definitions ok (for func)
- uchar wrapper; // is method wrapper (for func)
- uchar reslice; // this is a reslice x = x[0:y] or x = append(x, ...)
- schar likely; // likeliness of if statement
- uchar hasbreak; // has break statement
- uchar needzero; // if it contains pointers, needs to be zeroed on function entry
- uchar needctxt; // function uses context register (has closure variables)
- uint esc; // EscXXX
- int funcdepth;
-
- // most nodes
- Type* type;
- Node* orig; // original form, for printing, and tracking copies of ONAMEs
-
- // func
- Node* nname;
- Node* shortname;
- NodeList* enter;
- NodeList* exit;
- NodeList* cvars; // closure params
- NodeList* dcl; // autodcl for this func/closure
- NodeList* inl; // copy of the body for use in inlining
- NodeList* inldcl; // copy of dcl for use in inlining
- int closgen;
- Node* outerfunc;
-
- // OLITERAL/OREGISTER
- Val val;
-
- // ONAME
- Node* ntype;
- Node* defn; // ONAME: initializing assignment; OLABEL: labeled statement
- Node* pack; // real package for import . names
- Node* curfn; // function for local variables
- Type* paramfld; // TFIELD for this PPARAM; also for ODOT, curfn
- int decldepth; // declaration loop depth, increased for every loop or label
-
- // ONAME func param with PHEAP
- Node* heapaddr; // temp holding heap address of param
- Node* outerexpr; // expression copied into closure for variable
- Node* stackparam; // OPARAM node referring to stack copy of param
- Node* alloc; // allocation call
-
- // ONAME closure param with PPARAMREF
- Node* outer; // outer PPARAMREF in nested closure
- Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
- int top; // top context (Ecall, Eproc, etc)
-
- // ONAME substitute while inlining
- Node* inlvar;
-
- // OPACK
- Pkg* pkg;
-
- // OARRAYLIT, OMAPLIT, OSTRUCTLIT.
- InitPlan* initplan;
-
- // Escape analysis.
- NodeList* escflowsrc; // flow(this, src)
- NodeList* escretval; // on OCALLxxx, list of dummy return values
- int escloopdepth; // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
-
- Sym* sym; // various
- int32 vargen; // unique name for OTYPE/ONAME
- int32 lineno;
- int32 endlineno;
- vlong xoffset;
- vlong stkdelta; // offset added by stack frame compaction phase.
- int32 ostk;
- int32 iota;
- uint32 walkgen;
- int32 esclevel;
- void* opt; // for optimization passes
-};
-#define N ((Node*)0)
-
-/*
- * Every node has a walkgen field.
- * If you want to do a traversal of a node graph that
- * might contain duplicates and want to avoid
- * visiting the same nodes twice, increment walkgen
- * before starting. Then before processing a node, do
- *
- * if(n->walkgen == walkgen)
- * return;
- * n->walkgen = walkgen;
- *
- * Such a walk cannot call another such walk recursively,
- * because of the use of the global walkgen.
- */
-EXTERN uint32 walkgen;
-
-struct NodeList
-{
- Node* n;
- NodeList* next;
- NodeList* end;
-};
-
-enum
-{
- SymExport = 1<<0, // to be exported
- SymPackage = 1<<1,
- SymExported = 1<<2, // already written out by export
- SymUniq = 1<<3,
- SymSiggen = 1<<4,
- SymAsm = 1<<5,
- SymAlgGen = 1<<6,
-};
-
-struct Sym
-{
- ushort lexical;
- uchar flags;
- uchar sym; // huffman encoding in object file
- Sym* link;
- int32 npkg; // number of imported packages with this name
- uint32 uniqgen;
- Pkg* importdef; // where imported definition was found
- char* linkname; // link name
-
- // saved and restored by dcopy
- Pkg* pkg;
- char* name; // variable name
- Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
- Label* label; // corresponding label (ephemeral)
- int32 block; // blocknumber to catch redeclaration
- int32 lastlineno; // last declaration for diagnostic
- Pkg* origpkg; // original package for . import
- LSym* lsym;
-};
-#define S ((Sym*)0)
-
-EXTERN Sym* dclstack;
-
-struct Pkg
-{
- char* name; // package name
- Strlit* path; // string literal used in import statement
- Sym* pathsym;
- char* prefix; // escaped path for use in symbol table
- Pkg* link;
- uchar imported; // export data of this package was parsed
- char exported; // import line written in export data
- char direct; // imported directly
- char safe; // whether the package is marked as safe
-};
-
-typedef struct Iter Iter;
-struct Iter
-{
- int done;
- Type* tfunc;
- Type* t;
- Node** an;
- Node* n;
-};
-
-// Node ops.
-enum
-{
- OXXX,
-
- // names
- ONAME, // var, const or func name
- ONONAME, // unnamed arg or return value: f(int, string) (int, error) { etc }
- OTYPE, // type name
- OPACK, // import
- OLITERAL, // literal
-
- // expressions
- OADD, // x + y
- OSUB, // x - y
- OOR, // x | y
- OXOR, // x ^ y
- OADDSTR, // s + "foo"
- OADDR, // &x
- OANDAND, // b0 && b1
- OAPPEND, // append
- OARRAYBYTESTR, // string(bytes)
- OARRAYBYTESTRTMP, // string(bytes) ephemeral
- OARRAYRUNESTR, // string(runes)
- OSTRARRAYBYTE, // []byte(s)
- OSTRARRAYBYTETMP, // []byte(s) ephemeral
- OSTRARRAYRUNE, // []rune(s)
- OAS, // x = y or x := y
- OAS2, // x, y, z = xx, yy, zz
- OAS2FUNC, // x, y = f()
- OAS2RECV, // x, ok = <-c
- OAS2MAPR, // x, ok = m["foo"]
- OAS2DOTTYPE, // x, ok = I.(int)
- OASOP, // x += y
- OCALL, // function call, method call or type conversion, possibly preceded by defer or go.
- OCALLFUNC, // f()
- OCALLMETH, // t.Method()
- OCALLINTER, // err.Error()
- OCALLPART, // t.Method (without ())
- OCAP, // cap
- OCLOSE, // close
- OCLOSURE, // f = func() { etc }
- OCMPIFACE, // err1 == err2
- OCMPSTR, // s1 == s2
- OCOMPLIT, // composite literal, typechecking may convert to a more specific OXXXLIT.
- OMAPLIT, // M{"foo":3, "bar":4}
- OSTRUCTLIT, // T{x:3, y:4}
- OARRAYLIT, // [2]int{3, 4}
- OPTRLIT, // &T{x:3, y:4}
- OCONV, // var i int; var u uint; i = int(u)
- OCONVIFACE, // I(t)
- OCONVNOP, // type Int int; var i int; var j Int; i = int(j)
- OCOPY, // copy
- ODCL, // var x int
- ODCLFUNC, // func f() or func (r) f()
- ODCLFIELD, // struct field, interface field, or func/method argument/return value.
- ODCLCONST, // const pi = 3.14
- ODCLTYPE, // type Int int
- ODELETE, // delete
- ODOT, // t.x
- ODOTPTR, // p.x that is implicitly (*p).x
- ODOTMETH, // t.Method
- ODOTINTER, // err.Error
- OXDOT, // t.x, typechecking may convert to a more specific ODOTXXX.
- ODOTTYPE, // e = err.(MyErr)
- ODOTTYPE2, // e, ok = err.(MyErr)
- OEQ, // x == y
- ONE, // x != y
- OLT, // x < y
- OLE, // x <= y
- OGE, // x >= y
- OGT, // x > y
- OIND, // *p
- OINDEX, // a[i]
- OINDEXMAP, // m[s]
- OKEY, // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
- OPARAM, // The on-stack copy of a parameter or return value that escapes.
- OLEN, // len
- OMAKE, // make, typechecking may convert to a more specific OMAKEXXX.
- OMAKECHAN, // make(chan int)
- OMAKEMAP, // make(map[string]int)
- OMAKESLICE, // make([]int, 0)
- OMUL, // x * y
- ODIV, // x / y
- OMOD, // x % y
- OLSH, // x << u
- ORSH, // x >> u
- OAND, // x & y
- OANDNOT, // x &^ y
- ONEW, // new
- ONOT, // !b
- OCOM, // ^x
- OPLUS, // +x
- OMINUS, // -y
- OOROR, // b1 || b2
- OPANIC, // panic
- OPRINT, // print
- OPRINTN, // println
- OPAREN, // (x)
- OSEND, // c <- x
- OSLICE, // v[1:2], typechecking may convert to a more specific OSLICEXXX.
- OSLICEARR, // a[1:2]
- OSLICESTR, // s[1:2]
- OSLICE3, // v[1:2:3], typechecking may convert to OSLICE3ARR.
- OSLICE3ARR, // a[1:2:3]
- ORECOVER, // recover
- ORECV, // <-c
- ORUNESTR, // string(i)
- OSELRECV, // case x = <-c:
- OSELRECV2, // case x, ok = <-c:
- OIOTA, // iota
- OREAL, // real
- OIMAG, // imag
- OCOMPLEX, // complex
-
- // statements
- OBLOCK, // block of code
- OBREAK, // break
- OCASE, // case, after being verified by swt.c's casebody.
- OXCASE, // case, before verification.
- OCONTINUE, // continue
- ODEFER, // defer
- OEMPTY, // no-op
- OFALL, // fallthrough, after being verified by swt.c's casebody.
- OXFALL, // fallthrough, before verification.
- OFOR, // for
- OGOTO, // goto
- OIF, // if
- OLABEL, // label:
- OPROC, // go
- ORANGE, // range
- ORETURN, // return
- OSELECT, // select
- OSWITCH, // switch x
- OTYPESW, // switch err.(type)
-
- // types
- OTCHAN, // chan int
- OTMAP, // map[string]int
- OTSTRUCT, // struct{}
- OTINTER, // interface{}
- OTFUNC, // func()
- OTARRAY, // []int, [8]int, [N]int or [...]int
-
- // misc
- ODDD, // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
- ODDDARG, // func f(args ...int), introduced by escape analysis.
- OINLCALL, // intermediary representation of an inlined call.
- OEFACE, // itable and data words of an empty-interface value.
- OITAB, // itable word of an interface value.
- OSPTR, // base pointer of a slice or string.
- OCLOSUREVAR, // variable reference at beginning of closure function
- OCFUNC, // reference to c function pointer (not go func value)
- OCHECKNIL, // emit code to ensure pointer/interface not nil
- OVARKILL, // variable is dead
-
- // thearch-specific registers
- OREGISTER, // a register, such as AX.
- OINDREG, // offset plus indirect of a register, such as 8(SP).
-
- // 386/amd64-specific opcodes
- OCMP, // compare: ACMP.
- ODEC, // decrement: ADEC.
- OINC, // increment: AINC.
- OEXTEND, // extend: ACWD/ACDQ/ACQO.
- OHMUL, // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
- OLROT, // left rotate: AROL.
- ORROTC, // right rotate-carry: ARCR.
- ORETJMP, // return to other function
-
- OEND,
-};
-
-enum
-{
- Txxx, // 0
-
- TINT8, TUINT8, // 1
- TINT16, TUINT16,
- TINT32, TUINT32,
- TINT64, TUINT64,
- TINT, TUINT, TUINTPTR,
-
- TCOMPLEX64, // 12
- TCOMPLEX128,
-
- TFLOAT32, // 14
- TFLOAT64,
-
- TBOOL, // 16
-
- TPTR32, TPTR64, // 17
-
- TFUNC, // 19
- TARRAY,
- T_old_DARRAY,
- TSTRUCT, // 22
- TCHAN,
- TMAP,
- TINTER, // 25
- TFORW,
- TFIELD,
- TANY,
- TSTRING,
- TUNSAFEPTR,
-
- // pseudo-types for literals
- TIDEAL, // 31
- TNIL,
- TBLANK,
-
- // pseudo-type for frame layout
- TFUNCARGS,
- TCHANARGS,
- TINTERMETH,
-
- NTYPE,
-};
-
-enum
-{
- CTxxx,
-
- CTINT,
- CTRUNE,
- CTFLT,
- CTCPLX,
- CTSTR,
- CTBOOL,
- CTNIL,
-};
-
-enum
-{
- /* types of channel */
- /* must match ../../pkg/nreflect/type.go:/Chandir */
- Cxxx,
- Crecv = 1<<0,
- Csend = 1<<1,
- Cboth = Crecv | Csend,
-};
-
-// declaration context
-enum
-{
- Pxxx,
-
- PEXTERN, // global variable
- PAUTO, // local variables
- PPARAM, // input arguments
- PPARAMOUT, // output results
- PPARAMREF, // closure variable reference
- PFUNC, // global function
-
- PDISCARD, // discard during parse of duplicate import
-
- PHEAP = 1<<7, // an extra bit to identify an escaped variable
-};
-
-enum
-{
- Etop = 1<<1, // evaluated at statement level
- Erv = 1<<2, // evaluated in value context
- Etype = 1<<3,
- Ecall = 1<<4, // call-only expressions are ok
- Efnstruct = 1<<5, // multivalue function returns are ok
- Eiota = 1<<6, // iota is ok
- Easgn = 1<<7, // assigning to expression
- Eindir = 1<<8, // indirecting through expression
- Eaddr = 1<<9, // taking address of expression
- Eproc = 1<<10, // inside a go statement
- Ecomplit = 1<<11, // type in composite literal
-};
-
-enum {
- BITS = 3,
- NVAR = (BITS*64)
-};
-
-typedef struct Bits Bits;
-struct Bits
-{
- uint64 b[BITS];
-};
-
-EXTERN Bits zbits;
-
-struct Bvec
-{
- int32 n; // number of bits
- uint32 b[];
-};
-
-typedef struct Var Var;
-struct Var
-{
- vlong offset;
- Node* node;
- Var* nextinnode;
- int width;
- int id;
- char name;
- char etype;
- char addr;
-};
-
-EXTERN Var var[NVAR];
-
-typedef struct Typedef Typedef;
-struct Typedef
-{
- char* name;
- int etype;
- int sameas;
-};
-
-typedef struct Sig Sig;
-struct Sig
-{
- char* name;
- Pkg* pkg;
- Sym* isym;
- Sym* tsym;
- Type* type;
- Type* mtype;
- int32 offset;
- Sig* link;
-};
-
-typedef struct Io Io;
-struct Io
-{
- char* infile;
- Biobuf* bin;
- int32 ilineno;
- int nlsemi;
- int eofnl;
- int last;
- int peekc;
- int peekc1; // second peekc for ...
- char* cp; // used for content when bin==nil
- int importsafe;
-};
-
-typedef struct Dlist Dlist;
-struct Dlist
-{
- Type* field;
-};
-
-typedef struct Idir Idir;
-struct Idir
-{
- Idir* link;
- char* dir;
-};
-
-/*
- * argument passing to/from
- * smagic and umagic
- */
-typedef struct Magic Magic;
-struct Magic
-{
- int w; // input for both - width
- int s; // output for both - shift
- int bad; // output for both - unexpected failure
-
- // magic multiplier for signed literal divisors
- int64 sd; // input - literal divisor
- int64 sm; // output - multiplier
-
- // magic multiplier for unsigned literal divisors
- uint64 ud; // input - literal divisor
- uint64 um; // output - multiplier
- int ua; // output - adder
-};
-
-struct Label
-{
- uchar used;
- Sym* sym;
- Node* def;
- NodeList* use;
- Label* link;
-
- // for use during gen
- Prog* gotopc; // pointer to unresolved gotos
- Prog* labelpc; // pointer to code
- Prog* breakpc; // pointer to code
- Prog* continpc; // pointer to code
-};
-#define L ((Label*)0)
-
-/*
- * note this is the runtime representation
- * of the compilers arrays.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * uchar cap[4]; // allocated number of elements
- * } Array;
- */
-EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
-EXTERN int Array_nel; // runtime offsetof(Array,nel) - same for String
-EXTERN int Array_cap; // runtime offsetof(Array,cap)
-EXTERN int sizeof_Array; // runtime sizeof(Array)
-
-
-/*
- * note this is the runtime representation
- * of the compilers strings.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * } String;
- */
-EXTERN int sizeof_String; // runtime sizeof(String)
-
-EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
-
-EXTERN Io curio;
-EXTERN Io pushedio;
-EXTERN int32 lexlineno;
-EXTERN int32 lineno;
-EXTERN int32 prevlineno;
-
-EXTERN Fmt pragcgobuf;
-
-EXTERN char* infile;
-EXTERN char* outfile;
-EXTERN Biobuf* bout;
-EXTERN int nerrors;
-EXTERN int nsavederrors;
-EXTERN int nsyntaxerrors;
-EXTERN int decldepth;
-EXTERN int safemode;
-EXTERN int nolocalimports;
-EXTERN char namebuf[NSYMB];
-EXTERN char lexbuf[NSYMB];
-EXTERN char litbuf[NSYMB];
-EXTERN int debug[256];
-EXTERN char* debugstr;
-EXTERN int debug_checknil;
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* importmyname; // my name for package
-EXTERN Pkg* localpkg; // package being compiled
-EXTERN Pkg* importpkg; // package being imported
-EXTERN Pkg* structpkg; // package that declared struct, during import
-EXTERN Pkg* builtinpkg; // fake package for builtins
-EXTERN Pkg* gostringpkg; // fake pkg for Go strings
-EXTERN Pkg* itabpkg; // fake pkg for itab cache
-EXTERN Pkg* runtimepkg; // package runtime
-EXTERN Pkg* racepkg; // package runtime/race
-EXTERN Pkg* stringpkg; // fake package for C strings
-EXTERN Pkg* typepkg; // fake package for runtime type info (headers)
-EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data)
-EXTERN Pkg* weaktypepkg; // weak references to runtime type info
-EXTERN Pkg* unsafepkg; // package unsafe
-EXTERN Pkg* trackpkg; // fake package for field tracking
-EXTERN Pkg* rawpkg; // fake package for raw symbol names
-EXTERN Pkg* phash[128];
-EXTERN int tptr; // either TPTR32 or TPTR64
-extern char* runtimeimport;
-extern char* unsafeimport;
-EXTERN char* myimportpath;
-EXTERN Idir* idirs;
-EXTERN char* localimport;
-EXTERN char* asmhdr;
-
-EXTERN Type* types[NTYPE];
-EXTERN Type* idealstring;
-EXTERN Type* idealbool;
-EXTERN Type* bytetype;
-EXTERN Type* runetype;
-EXTERN Type* errortype;
-EXTERN uchar simtype[NTYPE];
-EXTERN uchar isptr[NTYPE];
-EXTERN uchar isforw[NTYPE];
-EXTERN uchar isint[NTYPE];
-EXTERN uchar isfloat[NTYPE];
-EXTERN uchar iscomplex[NTYPE];
-EXTERN uchar issigned[NTYPE];
-EXTERN uchar issimple[NTYPE];
-
-EXTERN uchar okforeq[NTYPE];
-EXTERN uchar okforadd[NTYPE];
-EXTERN uchar okforand[NTYPE];
-EXTERN uchar okfornone[NTYPE];
-EXTERN uchar okforcmp[NTYPE];
-EXTERN uchar okforbool[NTYPE];
-EXTERN uchar okforcap[NTYPE];
-EXTERN uchar okforlen[NTYPE];
-EXTERN uchar okforarith[NTYPE];
-EXTERN uchar okforconst[NTYPE];
-EXTERN uchar* okfor[OEND];
-EXTERN uchar iscmp[OEND];
-
-EXTERN Mpint* minintval[NTYPE];
-EXTERN Mpint* maxintval[NTYPE];
-EXTERN Mpflt* minfltval[NTYPE];
-EXTERN Mpflt* maxfltval[NTYPE];
-
-EXTERN NodeList* xtop;
-EXTERN NodeList* externdcl;
-EXTERN NodeList* exportlist;
-EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies
-EXTERN NodeList* funcsyms;
-EXTERN int dclcontext; // PEXTERN/PAUTO
-EXTERN int incannedimport;
-EXTERN int statuniqgen; // name generator for static temps
-EXTERN int loophack;
-
-EXTERN int32 iota;
-EXTERN NodeList* lastconst;
-EXTERN Node* lasttype;
-EXTERN vlong maxarg;
-EXTERN vlong stksize; // stack size for current frame
-EXTERN vlong stkptrsize; // prefix of stack containing pointers
-EXTERN int32 blockgen; // max block number
-EXTERN int32 block; // current block number
-EXTERN int hasdefer; // flag that curfn has defer statetment
-
-EXTERN Node* curfn;
-
-EXTERN int widthptr;
-EXTERN int widthint;
-EXTERN int widthreg;
-
-EXTERN Node* typesw;
-EXTERN Node* nblank;
-
-EXTERN int use_sse;
-
-EXTERN char* hunk;
-EXTERN int32 nhunk;
-EXTERN int32 thunk;
-
-EXTERN int funcdepth;
-EXTERN int typecheckok;
-EXTERN int compiling_runtime;
-EXTERN int compiling_wrappers;
-EXTERN int inl_nonlocal;
-EXTERN int use_writebarrier;
-EXTERN int pure_go;
-EXTERN char* flag_installsuffix;
-EXTERN int flag_race;
-EXTERN int flag_largemodel;
-EXTERN int noescape;
-EXTERN int nosplit;
-EXTERN int nowritebarrier;
-EXTERN int debuglive;
-EXTERN Link* ctxt;
-
-EXTERN int nointerface;
-EXTERN int writearchive;
-
-EXTERN Biobuf bstdout;
-
-EXTERN int nacl;
-
-/*
- * y.tab.c
- */
-int yyparse(void);
-
-/*
- * align.c
- */
-int argsize(Type *t);
-void checkwidth(Type *t);
-void defercheckwidth(void);
-void dowidth(Type *t);
-void resumecheckwidth(void);
-vlong rnd(vlong o, vlong r);
-void typeinit(void);
-
-/*
- * array.c
- */
-Array* arraynew(int32 capacity, int32 size);
-void arrayfree(Array *array);
-int32 arraylength(Array *array);
-void* arrayget(Array *array, int32 index);
-void arrayset(Array *array, int32 index, void *element);
-void arrayadd(Array *array, void *element);
-void arraysort(Array* array, int (*cmp)(const void*, const void*));
-
-/*
- * bits.c
- */
-int Qconv(Fmt *fp);
-Bits band(Bits a, Bits b);
-int bany(Bits *a);
-int beq(Bits a, Bits b);
-int bitno(uint64 b);
-Bits blsh(uint n);
-Bits bnot(Bits a);
-int bnum(Bits a);
-Bits bor(Bits a, Bits b);
-int btest(Bits *a, uint n);
-void biset(Bits *a, uint n);
-void biclr(Bits *a, uint n);
-
-/*
- * bv.c
- */
-Bvec* bvalloc(int32 n);
-void bvandnot(Bvec *dst, Bvec *src1, Bvec *src2);
-int bvcmp(Bvec *bv1, Bvec *bv2);
-void bvcopy(Bvec *dst, Bvec *src);
-Bvec* bvconcat(Bvec *src1, Bvec *src2);
-int bvget(Bvec *bv, int32 i);
-int32 bvnext(Bvec *bv, int32 i);
-int bvisempty(Bvec *bv);
-void bvnot(Bvec *bv);
-void bvor(Bvec *dst, Bvec *src1, Bvec *src2);
-void bvand(Bvec *dst, Bvec *src1, Bvec *src2);
-void bvprint(Bvec *bv);
-void bvreset(Bvec *bv, int32 i);
-void bvresetall(Bvec *bv);
-void bvset(Bvec *bv, int32 i);
-
-/*
- * closure.c
- */
-Node* closurebody(NodeList *body);
-void closurehdr(Node *ntype);
-void typecheckclosure(Node *func, int top);
-void capturevars(Node *func);
-void transformclosure(Node *func);
-Node* walkclosure(Node *func, NodeList **init);
-void typecheckpartialcall(Node*, Node*);
-Node* walkpartialcall(Node*, NodeList**);
-
-/*
- * const.c
- */
-int cmpslit(Node *l, Node *r);
-int consttype(Node *n);
-void convconst(Node *con, Type *t, Val *val);
-void convlit(Node **np, Type *t);
-void convlit1(Node **np, Type *t, int explicit);
-void defaultlit(Node **np, Type *t);
-void defaultlit2(Node **lp, Node **rp, int force);
-void evconst(Node *n);
-int isconst(Node *n, int ct);
-int isgoconst(Node *n);
-Node* nodcplxlit(Val r, Val i);
-Node* nodlit(Val v);
-long nonnegconst(Node *n);
-int doesoverflow(Val v, Type *t);
-void overflow(Val v, Type *t);
-int smallintconst(Node *n);
-Val toint(Val v);
-Mpflt* truncfltlit(Mpflt *oldv, Type *t);
-
-/*
- * cplx.c
- */
-void complexadd(int op, Node *nl, Node *nr, Node *res);
-void complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to);
-void complexgen(Node *n, Node *res);
-void complexminus(Node *nl, Node *res);
-void complexmove(Node *f, Node *t);
-void complexmul(Node *nl, Node *nr, Node *res);
-int complexop(Node *n, Node *res);
-void nodfconst(Node *n, Type *t, Mpflt* fval);
-
-/*
- * dcl.c
- */
-void addmethod(Sym *sf, Type *t, int local, int nointerface);
-void addvar(Node *n, Type *t, int ctxt);
-NodeList* checkarglist(NodeList *all, int input);
-Node* colas(NodeList *left, NodeList *right, int32 lno);
-void colasdefn(NodeList *left, Node *defn);
-NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
-Node* dclname(Sym *s);
-void declare(Node *n, int ctxt);
-void dumpdcl(char *st);
-Node* embedded(Sym *s, Pkg *pkg);
-Node* fakethis(void);
-void funcbody(Node *n);
-void funccompile(Node *n);
-void funchdr(Node *n);
-Type* functype(Node *this, NodeList *in, NodeList *out);
-void ifacedcl(Node *n);
-int isifacemethod(Type *f);
-void markdcl(void);
-Node* methodname(Node *n, Type *t);
-Node* methodname1(Node *n, Node *t);
-Sym* methodsym(Sym *nsym, Type *t0, int iface);
-Node* newname(Sym *s);
-Node* oldname(Sym *s);
-void popdcl(void);
-void poptodcl(void);
-void redeclare(Sym *s, char *where);
-void testdclstack(void);
-Type* tointerface(NodeList *l);
-Type* tostruct(NodeList *l);
-Node* typedcl0(Sym *s);
-Node* typedcl1(Node *n, Node *t, int local);
-Node* typenod(Type *t);
-NodeList* variter(NodeList *vl, Node *t, NodeList *el);
-Sym* funcsym(Sym*);
-
-/*
- * esc.c
- */
-void escapes(NodeList*);
-
-/*
- * export.c
- */
-void autoexport(Node *n, int ctxt);
-void dumpexport(void);
-void dumpasmhdr(void);
-int exportname(char *s);
-void exportsym(Node *n);
-void importconst(Sym *s, Type *t, Node *n);
-void importimport(Sym *s, Strlit *z);
-Sym* importsym(Sym *s, int op);
-void importtype(Type *pt, Type *t);
-void importvar(Sym *s, Type *t);
-Type* pkgtype(Sym *s);
-
-/*
- * fmt.c
- */
-void fmtinstallgo(void);
-void dump(char *s, Node *n);
-void dumplist(char *s, NodeList *l);
-
-/*
- * gen.c
- */
-void addrescapes(Node *n);
-void cgen_as(Node *nl, Node *nr);
-void cgen_callmeth(Node *n, int proc);
-void cgen_eface(Node* n, Node* res);
-void cgen_slice(Node* n, Node* res);
-void clearlabels(void);
-void clearslim(Node*);
-void checklabels(void);
-int dotoffset(Node *n, int64 *oary, Node **nn);
-void gen(Node *n);
-void genlist(NodeList *l);
-Node* sysfunc(char *name);
-void tempname(Node *n, Type *t);
-Node* temp(Type*);
-
-/*
- * init.c
- */
-void fninit(NodeList *n);
-Sym* renameinit(void);
-
-/*
- * inl.c
- */
-void caninl(Node *fn);
-void inlcalls(Node *fn);
-void typecheckinl(Node *fn);
-
-/*
- * lex.c
- */
-void cannedimports(char *file, char *cp);
-void importfile(Val *f, int line);
-char* lexname(int lex);
-char* expstring(void);
-void mkpackage(char* pkgname);
-void unimportfile(void);
-int32 yylex(void);
-extern int yylast;
-extern int yyprev;
-
-/*
- * mparith1.c
- */
-int Bconv(Fmt *fp);
-int Fconv(Fmt *fp);
-void mpaddcfix(Mpint *a, vlong c);
-void mpaddcflt(Mpflt *a, double c);
-void mpatofix(Mpint *a, char *as);
-void mpatoflt(Mpflt *a, char *as);
-int mpcmpfixc(Mpint *b, vlong c);
-int mpcmpfixfix(Mpint *a, Mpint *b);
-int mpcmpfixflt(Mpint *a, Mpflt *b);
-int mpcmpfltc(Mpflt *b, double c);
-int mpcmpfltfix(Mpflt *a, Mpint *b);
-int mpcmpfltflt(Mpflt *a, Mpflt *b);
-void mpcomfix(Mpint *a);
-void mpdivfixfix(Mpint *a, Mpint *b);
-void mpmodfixfix(Mpint *a, Mpint *b);
-void mpmovefixfix(Mpint *a, Mpint *b);
-void mpmovefixflt(Mpflt *a, Mpint *b);
-int mpmovefltfix(Mpint *a, Mpflt *b);
-void mpmovefltflt(Mpflt *a, Mpflt *b);
-void mpmulcfix(Mpint *a, vlong c);
-void mpmulcflt(Mpflt *a, double c);
-void mpsubfixfix(Mpint *a, Mpint *b);
-void mpsubfltflt(Mpflt *a, Mpflt *b);
-
-/*
- * mparith2.c
- */
-void mpaddfixfix(Mpint *a, Mpint *b, int);
-void mpandfixfix(Mpint *a, Mpint *b);
-void mpandnotfixfix(Mpint *a, Mpint *b);
-void mpdivfract(Mpint *a, Mpint *b);
-void mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
-vlong mpgetfix(Mpint *a);
-void mplshfixfix(Mpint *a, Mpint *b);
-void mpmovecfix(Mpint *a, vlong c);
-void mpmulfixfix(Mpint *a, Mpint *b);
-void mpmulfract(Mpint *a, Mpint *b);
-void mpnegfix(Mpint *a);
-void mporfixfix(Mpint *a, Mpint *b);
-void mprshfixfix(Mpint *a, Mpint *b);
-void mpshiftfix(Mpint *a, int s);
-int mptestfix(Mpint *a);
-void mpxorfixfix(Mpint *a, Mpint *b);
-
-/*
- * mparith3.c
- */
-void mpaddfltflt(Mpflt *a, Mpflt *b);
-void mpdivfltflt(Mpflt *a, Mpflt *b);
-double mpgetflt(Mpflt *a);
-double mpgetflt32(Mpflt *a);
-void mpmovecflt(Mpflt *a, double c);
-void mpmulfltflt(Mpflt *a, Mpflt *b);
-void mpnegflt(Mpflt *a);
-void mpnorm(Mpflt *a);
-void mpsetexp(Mpflt *a, int exp);
-int mptestflt(Mpflt *a);
-int sigfig(Mpflt *a);
-
-/*
- * obj.c
- */
-void Bputname(Biobuf *b, LSym *s);
-int duint16(Sym *s, int off, uint16 v);
-int duint32(Sym *s, int off, uint32 v);
-int duint64(Sym *s, int off, uint64 v);
-int duint8(Sym *s, int off, uint8 v);
-int duintptr(Sym *s, int off, uint64 v);
-void dumpobj(void);
-Sym* stringsym(char*, int);
-void slicebytes(Node*, char*, int);
-LSym* linksym(Sym*);
-
-/*
- * order.c
- */
-void order(Node *fn);
-void orderstmtinplace(Node **stmt);
-
-/*
- * range.c
- */
-void typecheckrange(Node *n);
-void walkrange(Node *n);
-
-/*
- * reflect.c
- */
-void dumptypestructs(void);
-Type* methodfunc(Type *f, Type*);
-Node* typename(Type *t);
-Sym* typesym(Type *t);
-Sym* typenamesym(Type *t);
-Sym* tracksym(Type *t);
-Sym* typesymprefix(char *prefix, Type *t);
-int haspointers(Type *t);
-Type* hmap(Type *t);
-Type* hiter(Type* t);
-Type* mapbucket(Type *t);
-
-/*
- * select.c
- */
-void typecheckselect(Node *sel);
-void walkselect(Node *sel);
-
-/*
- * sinit.c
- */
-void anylit(int, Node *n, Node *var, NodeList **init);
-int gen_as_init(Node *n);
-NodeList* initfix(NodeList *l);
-int oaslit(Node *n, NodeList **init);
-int stataddr(Node *nam, Node *n);
-
-/*
- * subr.c
- */
-Node* adddot(Node *n);
-int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
-void addinit(Node**, NodeList*);
-Type* aindex(Node *b, Type *t);
-int algtype(Type *t);
-int algtype1(Type *t, Type **bad);
-void argtype(Node *on, Type *t);
-Node* assignconv(Node *n, Type *t, char *context);
-int assignop(Type *src, Type *dst, char **why);
-void badtype(int o, Type *tl, Type *tr);
-int brcom(int a);
-int brrev(int a);
-NodeList* concat(NodeList *a, NodeList *b);
-int convertop(Type *src, Type *dst, char **why);
-Node* copyexpr(Node*, Type*, NodeList**);
-int count(NodeList *l);
-int cplxsubtype(int et);
-int eqtype(Type *t1, Type *t2);
-int eqtypenoname(Type *t1, Type *t2);
-void errorexit(void);
-void expandmeth(Type *t);
-void fatal(char *fmt, ...);
-void flusherrors(void);
-void frame(int context);
-Type* funcfirst(Iter *s, Type *t);
-Type* funcnext(Iter *s);
-void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
-void genhash(Sym *sym, Type *t);
-void geneq(Sym *sym, Type *t);
-Type** getinarg(Type *t);
-Type* getinargx(Type *t);
-Type** getoutarg(Type *t);
-Type* getoutargx(Type *t);
-Type** getthis(Type *t);
-Type* getthisx(Type *t);
-int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
-void importdot(Pkg *opkg, Node *pack);
-int is64(Type *t);
-int isbadimport(Strlit *s);
-int isblank(Node *n);
-int isblanksym(Sym *s);
-int isdirectiface(Type*);
-int isfixedarray(Type *t);
-int isideal(Type *t);
-int isinter(Type *t);
-int isnil(Node *n);
-int isnilinter(Type *t);
-int isptrto(Type *t, int et);
-int isslice(Type *t);
-int istype(Type *t, int et);
-int iszero(Node *n);
-void linehist(char *file, int32 off, int relative);
-NodeList* list(NodeList *l, Node *n);
-NodeList* list1(Node *n);
-void listsort(NodeList**, int(*f)(Node*, Node*));
-Node* liststmt(NodeList *l);
-NodeList* listtreecopy(NodeList *l);
-Sym* lookup(char *name);
-void* mal(int32 n);
-Type* maptype(Type *key, Type *val);
-Type* methtype(Type *t, int mustname);
-Pkg* mkpkg(Strlit *path);
-Sym* ngotype(Node *n);
-int noconv(Type *t1, Type *t2);
-Node* nod(int op, Node *nleft, Node *nright);
-Node* nodbool(int b);
-void nodconst(Node *n, Type *t, int64 v);
-Node* nodintconst(int64 v);
-Node* nodfltconst(Mpflt *v);
-Node* nodnil(void);
-int parserline(void);
-Sym* pkglookup(char *name, Pkg *pkg);
-int powtwo(Node *n);
-Type* ptrto(Type *t);
-void* remal(void *p, int32 on, int32 n);
-Sym* restrictlookup(char *name, Pkg *pkg);
-Node* safeexpr(Node *n, NodeList **init);
-void saveerrors(void);
-Node* cheapexpr(Node *n, NodeList **init);
-Node* localexpr(Node *n, Type *t, NodeList **init);
-void saveorignode(Node *n);
-int32 setlineno(Node *n);
-void setmaxarg(Type *t, int32 extra);
-Type* shallow(Type *t);
-int simsimtype(Type *t);
-void smagic(Magic *m);
-Type* sortinter(Type *t);
-uint32 stringhash(char *p);
-Strlit* newstrlit(char *s);
-int structcount(Type *t);
-Type* structfirst(Iter *s, Type **nn);
-Type* structnext(Iter *s);
-Node* syslook(char *name, int copy);
-Type* tounsigned(Type *t);
-Node* treecopy(Node *n);
-Type* typ(int et);
-uint32 typehash(Type *t);
-void ullmancalc(Node *n);
-void umagic(Magic *m);
-void warn(char *fmt, ...);
-void warnl(int line, char *fmt, ...);
-void yyerror(char *fmt, ...);
-void yyerrorl(int line, char *fmt, ...);
-void adderrorname(Node*);
-
-/*
- * swt.c
- */
-void typecheckswitch(Node *n);
-void walkswitch(Node *sw);
-
-/*
- * typecheck.c
- */
-int islvalue(Node *n);
-int samesafeexpr(Node *l, Node *r);
-Node* typecheck(Node **np, int top);
-void typechecklist(NodeList *l, int top);
-Node* typecheckdef(Node *n);
-void copytype(Node *n, Type *t);
-void checkreturn(Node*);
-void checkassign(Node *stmt, Node*);
-void queuemethod(Node *n);
-
-/*
- * unsafe.c
- */
-int isunsafebuiltin(Node *n);
-Node* unsafenmagic(Node *n);
-
-/*
- * walk.c
- */
-Node* callnew(Type *t);
-Node* chanfn(char *name, int n, Type *t);
-Node* mkcall(char *name, Type *t, NodeList **init, ...);
-Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
-int vmatch1(Node *l, Node *r);
-void walk(Node *fn);
-void walkexpr(Node **np, NodeList **init);
-void walkexprlist(NodeList *l, NodeList **init);
-void walkexprlistsafe(NodeList *l, NodeList **init);
-void walkexprlistcheap(NodeList *l, NodeList **init);
-void walkstmt(Node **np);
-void walkstmtlist(NodeList *l);
-Node* conv(Node*, Type*);
-int candiscard(Node*);
-int needwritebarrier(Node*, Node*);
-Node* outervalue(Node*);
-void usefield(Node*);
-
-/*
- * thearch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
- */
-#define P ((Prog*)0)
-
-EXTERN Prog* continpc;
-EXTERN Prog* breakpc;
-EXTERN Prog* pc;
-EXTERN Prog* firstpc;
-
-EXTERN Node* nodfp;
-EXTERN int disable_checknil;
-EXTERN vlong zerosize;
-
-void checknil(Node*, NodeList**);
-void cgen_checknil(Node*);
-void compile(Node*);
-int duintxx(Sym *s, int off, uint64 v, int wid);
-void gvardef(Node*);
-void gvarkill(Node*);
-void movelarge(NodeList*);
-void liveness(Node*, Prog*, Sym*, Sym*);
-void twobitwalktype1(Type*, vlong*, Bvec*);
-
-#pragma varargck type "B" Mpint*
-#pragma varargck type "E" int
-#pragma varargck type "E" uint
-#pragma varargck type "F" Mpflt*
-#pragma varargck type "H" NodeList*
-#pragma varargck type "J" Node*
-#pragma varargck type "lL" int32
-#pragma varargck type "L" int32
-#pragma varargck type "N" Node*
-#pragma varargck type "lN" Node*
-#pragma varargck type "O" int
-#pragma varargck type "O" uint
-#pragma varargck type "Q" Bits
-#pragma varargck type "S" Sym*
-#pragma varargck type "lS" LSym*
-#pragma varargck type "T" Type*
-#pragma varargck type "lT" Type*
-#pragma varargck type "V" Val*
-#pragma varargck type "Z" Strlit*
-
-/*
- * racewalk.c
- */
-void racewalk(Node *fn);
-
-/*
- * flow.c
- */
-typedef struct Flow Flow;
-typedef struct Graph Graph;
-
-struct Flow {
- Prog* prog; // actual instruction
- Flow* p1; // predecessors of this instruction: p1,
- Flow* p2; // and then p2 linked though p2link.
- Flow* p2link;
- Flow* s1; // successors of this instruction (at most two: s1 and s2).
- Flow* s2;
- Flow* link; // next instruction in function code
-
- int32 active; // usable by client
-
- int32 id; // sequence number in flow graph
- int32 rpo; // reverse post ordering
- uint16 loop; // x5 for every loop
- uchar refset; // diagnostic generated
-
- void* data; // for use by client
-};
-
-struct Graph
-{
- Flow* start;
- int num;
-
- // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
- // and each non-dead Flow node f has g->rpo[f->rpo] == f.
- Flow** rpo;
-};
-
-void fixjmp(Prog*);
-Graph* flowstart(Prog*, int);
-void flowrpo(Graph*);
-void flowend(Graph*);
-void mergetemp(Prog*);
-void nilopt(Prog*);
-int noreturn(Prog*);
-Flow* uniqp(Flow*);
-Flow* uniqs(Flow*);
-
-/*
- * interface to back end
- */
-
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
- uint32 flags; // the bits below
- uint64 reguse; // registers implicitly used by this instruction
- uint64 regset; // registers implicitly set by this instruction
- uint64 regindex; // registers used by addressing mode
-};
-
-enum
-{
- // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
- Pseudo = 1<<1,
-
- // There's nothing to say about the instruction,
- // but it's still okay to see.
- OK = 1<<2,
-
- // Size of right-side write, or right-side read if no write.
- SizeB = 1<<3,
- SizeW = 1<<4,
- SizeL = 1<<5,
- SizeQ = 1<<6,
- SizeF = 1<<7, // float aka float32
- SizeD = 1<<8, // double aka float64
-
- // Left side (Prog.from): address taken, read, write.
- LeftAddr = 1<<9,
- LeftRead = 1<<10,
- LeftWrite = 1<<11,
-
- // Register in middle (Prog.reg); only ever read. (arm, ppc64)
- RegRead = 1<<12,
- CanRegRead = 1<<13,
-
- // Right side (Prog.to): address taken, read, write.
- RightAddr = 1<<14,
- RightRead = 1<<15,
- RightWrite = 1<<16,
-
- // Instruction kinds
- Move = 1<<17, // straight move
- Conv = 1<<18, // size conversion
- Cjmp = 1<<19, // conditional jump
- Break = 1<<20, // breaks control flow (no fallthrough)
- Call = 1<<21, // function call
- Jump = 1<<22, // jump
- Skip = 1<<23, // data instruction
-
- // Set, use, or kill of carry bit.
- // Kill means we never look at the carry bit after this kind of instruction.
- SetCarry = 1<<24,
- UseCarry = 1<<25,
- KillCarry = 1<<26,
-
- // Special cases for register use. (amd64, 386)
- ShiftCX = 1<<27, // possible shift by CX
- ImulAXDX = 1<<28, // possible multiply into DX:AX
-
- // Instruction updates whichever of from/to is type D_OREG. (ppc64)
- PostInc = 1<<29,
-};
-
-typedef struct Arch Arch;
-
-struct Arch
-{
- int thechar;
- char *thestring;
- LinkArch *thelinkarch;
- Typedef *typedefs;
-
- int REGSP;
- int REGCTXT;
- vlong MAXWIDTH;
-
- int (*anyregalloc)(void);
- void (*betypeinit)(void);
- void (*bgen)(Node*, int, int, Prog*);
- void (*cgen)(Node*, Node*);
- void (*cgen_call)(Node*, int);
- void (*cgen_callinter)(Node*, Node*, int);
- void (*cgen_ret)(Node*);
- void (*clearfat)(Node*);
- void (*defframe)(Prog*);
- void (*excise)(Flow*);
- void (*expandchecks)(Prog*);
- void (*gclean)(void);
- void (*ginit)(void);
- Prog* (*gins)(int, Node*, Node*);
- void (*ginscall)(Node*, int);
- void (*igen)(Node*, Node*, Node*);
- void (*linkarchinit)(void);
- void (*peep)(Prog*);
- void (*proginfo)(ProgInfo*, Prog*);
- void (*regalloc)(Node*, Type*, Node*);
- void (*regfree)(Node*);
- int (*regtyp)(Addr*);
- int (*sameaddr)(Addr*, Addr*);
- int (*smallindir)(Addr*, Addr*);
- int (*stackaddr)(Addr*);
- uint64 (*excludedregs)(void);
- uint64 (*RtoB)(int);
- uint64 (*FtoB)(int);
- int (*BtoR)(uint64);
- int (*BtoF)(uint64);
- int (*optoas)(int, Type*);
- uint64 (*doregbits)(int);
- char **(*regnames)(int*);
-};
-
-void afunclit(Addr*, Node*);
-void clearp(Prog*);
-int dgostringptr(Sym*, int, char*);
-int dgostrlitptr(Sym*, int, Strlit*);
-int dsname(Sym*, int, char*, int);
-int dsymptr(Sym*, int, Sym*, int);
-void dumpdata(void);
-void fixautoused(Prog*);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void ggloblnod(Node*);
-void ggloblsym(Sym*, int32, int8);
-Prog* gjmp(Prog*);
-void gtrack(Sym*);
-void gused(Node*);
-int isfat(Type*);
-void markautoused(Prog*);
-void naddr(Node*, Addr*, int);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void patch(Prog*, Prog*);
-Prog* unpatch(Prog*);
-void datagostring(Strlit *sval, Addr *a);
-int ismem(Node*);
-int samereg(Node*, Node*);
-void regopt(Prog*);
-int Tconv(Fmt*);
-int Oconv(Fmt*);
-Prog* gbranch(int as, Type *t, int likely);
-void nodindreg(Node *n, Type *t, int r);
-void nodreg(Node *n, Type *t, int r);
-Prog* prog(int as);
-void datastring(char*, int, Addr*);
-
-EXTERN int32 pcloc;
-
-EXTERN Arch thearch;
-
-EXTERN Node *newproc;
-EXTERN Node *deferproc;
-EXTERN Node *deferreturn;
-EXTERN Node *panicindex;
-EXTERN Node *panicslice;
-EXTERN Node *throwreturn;
-
-int gcmain(int, char**);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
deleted file mode 100644
index dc8b530562..0000000000
--- a/src/cmd/gc/go.y
+++ /dev/null
@@ -1,2225 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * Go language grammar.
- *
- * The Go semicolon rules are:
- *
- * 1. all statements and declarations are terminated by semicolons.
- * 2. semicolons can be omitted before a closing ) or }.
- * 3. semicolons are inserted by the lexer before a newline
- * following a specific list of tokens.
- *
- * Rules #1 and #2 are accomplished by writing the lists as
- * semicolon-separated lists with an optional trailing semicolon.
- * Rule #3 is implemented in yylex.
- */
-
-%{
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-%}
-%union {
- Node* node;
- NodeList* list;
- Type* type;
- Sym* sym;
- struct Val val;
- int i;
-}
-
-// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'
-
-%token <val> LLITERAL
-%token <i> LASOP LCOLAS
-%token <sym> LBREAK LCASE LCHAN LCONST LCONTINUE LDDD
-%token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
-%token <sym> LIF LIMPORT LINTERFACE LMAP LNAME
-%token <sym> LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
-%token <sym> LTYPE LVAR
-
-%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
-%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
-
-%type <i> lbrace import_here
-%type <sym> sym packname
-%type <val> oliteral
-
-%type <node> stmt ntype
-%type <node> arg_type
-%type <node> case caseblock
-%type <node> compound_stmt dotname embed expr complitexpr bare_complitexpr
-%type <node> expr_or_type
-%type <node> fndcl hidden_fndcl fnliteral
-%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
-%type <node> interfacedcl keyval labelname name
-%type <node> name_or_type non_expr_type
-%type <node> new_name dcl_name oexpr typedclname
-%type <node> onew_name
-%type <node> osimple_stmt pexpr pexpr_no_paren
-%type <node> pseudocall range_stmt select_stmt
-%type <node> simple_stmt
-%type <node> switch_stmt uexpr
-%type <node> xfndcl typedcl start_complit
-
-%type <list> xdcl fnbody fnres loop_body dcl_name_list
-%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type <list> oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list
-%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
-%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
-
-%type <node> convtype comptype dotdotdot
-%type <node> indcl interfacetype structtype ptrtype
-%type <node> recvchantype non_recvchantype othertype fnret_type fntype
-
-%type <sym> hidden_importsym hidden_pkg_importsym
-
-%type <node> hidden_constant hidden_literal hidden_funarg
-%type <node> hidden_interfacedcl hidden_structdcl
-
-%type <list> hidden_funres
-%type <list> ohidden_funres
-%type <list> hidden_funarg_list ohidden_funarg_list
-%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
-%type <list> hidden_structdcl_list ohidden_structdcl_list
-
-%type <type> hidden_type hidden_type_misc hidden_pkgtype
-%type <type> hidden_type_func
-%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
-
-%left LCOMM /* outside the usual hierarchy; here for good error messages */
-
-%left LOROR
-%left LANDAND
-%left LEQ LNE LLE LGE LLT LGT
-%left '+' '-' '|' '^'
-%left '*' '/' '%' '&' LLSH LRSH LANDNOT
-
-/*
- * manual override of shift/reduce conflicts.
- * the general form is that we assign a precedence
- * to the token being shifted and then introduce
- * NotToken with lower precedence or PreferToToken with higher
- * and annotate the reducing rule accordingly.
- */
-%left NotPackage
-%left LPACKAGE
-
-%left NotParen
-%left '('
-
-%left ')'
-%left PreferToRightParen
-
-%error-verbose
-
-%%
-file:
- loadsys
- package
- imports
- xdcl_list
- {
- xtop = concat(xtop, $4);
- }
-
-package:
- %prec NotPackage
- {
- prevlineno = lineno;
- yyerror("package statement must be first");
- errorexit();
- }
-| LPACKAGE sym ';'
- {
- mkpackage($2->name);
- }
-
-/*
- * this loads the definitions for the low-level runtime functions,
- * so that the compiler can generate calls to them,
- * but does not make the name "runtime" visible as a package.
- */
-loadsys:
- {
- importpkg = runtimepkg;
-
- if(debug['A'])
- cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
- else
- cannedimports("runtime.builtin", runtimeimport);
- curio.importsafe = 1;
- }
- import_package
- import_there
- {
- importpkg = nil;
- }
-
-imports:
-| imports import ';'
-
-import:
- LIMPORT import_stmt
-| LIMPORT '(' import_stmt_list osemi ')'
-| LIMPORT '(' ')'
-
-import_stmt:
- import_here import_package import_there
- {
- Pkg *ipkg;
- Sym *my;
- Node *pack;
-
- ipkg = importpkg;
- my = importmyname;
- importpkg = nil;
- importmyname = S;
-
- if(my == nil)
- my = lookup(ipkg->name);
-
- pack = nod(OPACK, N, N);
- pack->sym = my;
- pack->pkg = ipkg;
- pack->lineno = $1;
-
- if(my->name[0] == '.') {
- importdot(ipkg, pack);
- break;
- }
- if(strcmp(my->name, "init") == 0) {
- yyerror("cannot import package as init - init must be a func");
- break;
- }
- if(my->name[0] == '_' && my->name[1] == '\0')
- break;
- if(my->def) {
- lineno = $1;
- redeclare(my, "as imported package name");
- }
- my->def = pack;
- my->lastlineno = $1;
- my->block = 1; // at top level
- }
-| import_here import_there
- {
- // When an invalid import path is passed to importfile,
- // it calls yyerror and then sets up a fake import with
- // no package statement. This allows us to test more
- // than one invalid import statement in a single file.
- if(nerrors == 0)
- fatal("phase error in import");
- }
-
-import_stmt_list:
- import_stmt
-| import_stmt_list ';' import_stmt
-
-import_here:
- LLITERAL
- {
- // import with original name
- $$ = parserline();
- importmyname = S;
- importfile(&$1, $$);
- }
-| sym LLITERAL
- {
- // import with given name
- $$ = parserline();
- importmyname = $1;
- importfile(&$2, $$);
- }
-| '.' LLITERAL
- {
- // import into my name space
- $$ = parserline();
- importmyname = lookup(".");
- importfile(&$2, $$);
- }
-
-import_package:
- LPACKAGE LNAME import_safety ';'
- {
- if(importpkg->name == nil) {
- importpkg->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(importpkg->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path);
- importpkg->direct = 1;
- importpkg->safe = curio.importsafe;
-
- if(safemode && !curio.importsafe)
- yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
- }
-
-import_safety:
-| LNAME
- {
- if(strcmp($1->name, "safe") == 0)
- curio.importsafe = 1;
- }
-
-import_there:
- {
- defercheckwidth();
- }
- hidden_import_list '$' '$'
- {
- resumecheckwidth();
- unimportfile();
- }
-
-/*
- * declarations
- */
-xdcl:
- {
- yyerror("empty top-level declaration");
- $$ = nil;
- }
-| common_dcl
-| xfndcl
- {
- $$ = list1($1);
- }
-| non_dcl_stmt
- {
- yyerror("non-declaration statement outside function body");
- $$ = nil;
- }
-| error
- {
- $$ = nil;
- }
-
-common_dcl:
- LVAR vardcl
- {
- $$ = $2;
- }
-| LVAR '(' vardcl_list osemi ')'
- {
- $$ = $3;
- }
-| LVAR '(' ')'
- {
- $$ = nil;
- }
-| lconst constdcl
- {
- $$ = $2;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl osemi ')'
- {
- $$ = $3;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl ';' constdcl_list osemi ')'
- {
- $$ = concat($3, $5);
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' ')'
- {
- $$ = nil;
- iota = -100000;
- }
-| LTYPE typedcl
- {
- $$ = list1($2);
- }
-| LTYPE '(' typedcl_list osemi ')'
- {
- $$ = $3;
- }
-| LTYPE '(' ')'
- {
- $$ = nil;
- }
-
-lconst:
- LCONST
- {
- iota = 0;
- }
-
-vardcl:
- dcl_name_list ntype
- {
- $$ = variter($1, $2, nil);
- }
-| dcl_name_list ntype '=' expr_list
- {
- $$ = variter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = variter($1, nil, $3);
- }
-
-constdcl:
- dcl_name_list ntype '=' expr_list
- {
- $$ = constiter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = constiter($1, N, $3);
- }
-
-constdcl1:
- constdcl
-| dcl_name_list ntype
- {
- $$ = constiter($1, $2, nil);
- }
-| dcl_name_list
- {
- $$ = constiter($1, N, nil);
- }
-
-typedclname:
- sym
- {
- // different from dclname because the name
- // becomes visible right here, not at the end
- // of the declaration.
- $$ = typedcl0($1);
- }
-
-typedcl:
- typedclname ntype
- {
- $$ = typedcl1($1, $2, 1);
- }
-
-simple_stmt:
- expr
- {
- $$ = $1;
-
- // These nodes do not carry line numbers.
- // Since a bare name used as an expression is an error,
- // introduce a wrapper node to give the correct line.
- switch($$->op) {
- case ONAME:
- case ONONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- $$ = nod(OPAREN, $$, N);
- $$->implicit = 1;
- break;
- }
- }
-| expr LASOP expr
- {
- $$ = nod(OASOP, $1, $3);
- $$->etype = $2; // rathole to pass opcode
- }
-| expr_list '=' expr_list
- {
- if($1->next == nil && $3->next == nil) {
- // simple
- $$ = nod(OAS, $1->n, $3->n);
- break;
- }
- // multiple
- $$ = nod(OAS2, N, N);
- $$->list = $1;
- $$->rlist = $3;
- }
-| expr_list LCOLAS expr_list
- {
- if($3->n->op == OTYPESW) {
- $$ = nod(OTYPESW, N, $3->n->right);
- if($3->next != nil)
- yyerror("expr.(type) must be alone in list");
- if($1->next != nil)
- yyerror("argument count mismatch: %d = %d", count($1), 1);
- else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n))
- yyerror("invalid variable name %N in type switch", $1->n);
- else
- $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname.
- break;
- }
- $$ = colas($1, $3, $2);
- }
-| expr LINC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->implicit = 1;
- $$->etype = OADD;
- }
-| expr LDEC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->implicit = 1;
- $$->etype = OSUB;
- }
-
-case:
- LCASE expr_or_type_list ':'
- {
- Node *n, *nn;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = $2;
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- nn = newname(n->sym);
- declare(nn, dclcontext);
- $$->nname = nn;
-
- // keep track of the instances for reporting unused
- nn->defn = typesw->right;
- }
- }
-| LCASE expr_or_type_list '=' expr ':'
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- if($2->next == nil)
- n = nod(OAS, $2->n, $4);
- else {
- n = nod(OAS2, N, N);
- n->list = $2;
- n->rlist = list1($4);
- }
- $$->list = list1(n);
- }
-| LCASE expr_or_type_list LCOLAS expr ':'
- {
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = list1(colas($2, list1($4), $3));
- }
-| LDEFAULT ':'
- {
- Node *n, *nn;
-
- markdcl();
- $$ = nod(OXCASE, N, N);
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- nn = newname(n->sym);
- declare(nn, dclcontext);
- $$->nname = nn;
-
- // keep track of the instances for reporting unused
- nn->defn = typesw->right;
- }
- }
-
-compound_stmt:
- '{'
- {
- markdcl();
- }
- stmt_list '}'
- {
- if($3 == nil)
- $$ = nod(OEMPTY, N, N);
- else
- $$ = liststmt($3);
- popdcl();
- }
-
-caseblock:
- case
- {
- // If the last token read by the lexer was consumed
- // as part of the case, clear it (parser has cleared yychar).
- // If the last token read by the lexer was the lookahead
- // leave it alone (parser has it cached in yychar).
- // This is so that the stmt_list action doesn't look at
- // the case tokens if the stmt_list is empty.
- yylast = yychar;
- $1->xoffset = block;
- }
- stmt_list
- {
- int last;
-
- // This is the only place in the language where a statement
- // list is not allowed to drop the final semicolon, because
- // it's the only place where a statement list is not followed
- // by a closing brace. Handle the error for pedantry.
-
- // Find the final token of the statement list.
- // yylast is lookahead; yyprev is last of stmt_list
- last = yyprev;
-
- if(last > 0 && last != ';' && yychar != '}')
- yyerror("missing statement after label");
- $$ = $1;
- $$->nbody = $3;
- popdcl();
- }
-
-caseblock_list:
- {
- $$ = nil;
- }
-| caseblock_list caseblock
- {
- $$ = list($1, $2);
- }
-
-loop_body:
- LBODY
- {
- markdcl();
- }
- stmt_list '}'
- {
- $$ = $3;
- popdcl();
- }
-
-range_stmt:
- expr_list '=' LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->etype = 0; // := flag
- }
-| expr_list LCOLAS LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->colas = 1;
- colasdefn($1, $$);
- }
-| LRANGE expr
- {
- $$ = nod(ORANGE, N, $2);
- $$->etype = 0; // := flag
- }
-
-for_header:
- osimple_stmt ';' osimple_stmt ';' osimple_stmt
- {
- // init ; test ; incr
- if($5 != N && $5->colas != 0)
- yyerror("cannot declare in the for-increment");
- $$ = nod(OFOR, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- $$->nincr = $5;
- }
-| osimple_stmt
- {
- // normal test
- $$ = nod(OFOR, N, N);
- $$->ntest = $1;
- }
-| range_stmt
-
-for_body:
- for_header loop_body
- {
- $$ = $1;
- $$->nbody = concat($$->nbody, $2);
- }
-
-for_stmt:
- LFOR
- {
- markdcl();
- }
- for_body
- {
- $$ = $3;
- popdcl();
- }
-
-if_header:
- osimple_stmt
- {
- // test
- $$ = nod(OIF, N, N);
- $$->ntest = $1;
- }
-| osimple_stmt ';' osimple_stmt
- {
- // init ; test
- $$ = nod(OIF, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- }
-
-/* IF cond body (ELSE IF cond body)* (ELSE block)? */
-if_stmt:
- LIF
- {
- markdcl();
- }
- if_header
- {
- if($3->ntest == N)
- yyerror("missing condition in if statement");
- }
- loop_body
- {
- $3->nbody = $5;
- }
- elseif_list else
- {
- Node *n;
- NodeList *nn;
-
- $$ = $3;
- n = $3;
- popdcl();
- for(nn = concat($7, $8); nn; nn = nn->next) {
- if(nn->n->op == OIF)
- popdcl();
- n->nelse = list1(nn->n);
- n = nn->n;
- }
- }
-
-elseif:
- LELSE LIF
- {
- markdcl();
- }
- if_header loop_body
- {
- if($4->ntest == N)
- yyerror("missing condition in if statement");
- $4->nbody = $5;
- $$ = list1($4);
- }
-
-elseif_list:
- {
- $$ = nil;
- }
-| elseif_list elseif
- {
- $$ = concat($1, $2);
- }
-
-else:
- {
- $$ = nil;
- }
-| LELSE compound_stmt
- {
- NodeList *node;
-
- node = mal(sizeof *node);
- node->n = $2;
- node->end = node;
- $$ = node;
- }
-
-switch_stmt:
- LSWITCH
- {
- markdcl();
- }
- if_header
- {
- Node *n;
- n = $3->ntest;
- if(n != N && n->op != OTYPESW)
- n = N;
- typesw = nod(OXXX, typesw, n);
- }
- LBODY caseblock_list '}'
- {
- $$ = $3;
- $$->op = OSWITCH;
- $$->list = $6;
- typesw = typesw->left;
- popdcl();
- }
-
-select_stmt:
- LSELECT
- {
- typesw = nod(OXXX, typesw, N);
- }
- LBODY caseblock_list '}'
- {
- $$ = nod(OSELECT, N, N);
- $$->lineno = typesw->lineno;
- $$->list = $4;
- typesw = typesw->left;
- }
-
-/*
- * expressions
- */
-expr:
- uexpr
-| expr LOROR expr
- {
- $$ = nod(OOROR, $1, $3);
- }
-| expr LANDAND expr
- {
- $$ = nod(OANDAND, $1, $3);
- }
-| expr LEQ expr
- {
- $$ = nod(OEQ, $1, $3);
- }
-| expr LNE expr
- {
- $$ = nod(ONE, $1, $3);
- }
-| expr LLT expr
- {
- $$ = nod(OLT, $1, $3);
- }
-| expr LLE expr
- {
- $$ = nod(OLE, $1, $3);
- }
-| expr LGE expr
- {
- $$ = nod(OGE, $1, $3);
- }
-| expr LGT expr
- {
- $$ = nod(OGT, $1, $3);
- }
-| expr '+' expr
- {
- $$ = nod(OADD, $1, $3);
- }
-| expr '-' expr
- {
- $$ = nod(OSUB, $1, $3);
- }
-| expr '|' expr
- {
- $$ = nod(OOR, $1, $3);
- }
-| expr '^' expr
- {
- $$ = nod(OXOR, $1, $3);
- }
-| expr '*' expr
- {
- $$ = nod(OMUL, $1, $3);
- }
-| expr '/' expr
- {
- $$ = nod(ODIV, $1, $3);
- }
-| expr '%' expr
- {
- $$ = nod(OMOD, $1, $3);
- }
-| expr '&' expr
- {
- $$ = nod(OAND, $1, $3);
- }
-| expr LANDNOT expr
- {
- $$ = nod(OANDNOT, $1, $3);
- }
-| expr LLSH expr
- {
- $$ = nod(OLSH, $1, $3);
- }
-| expr LRSH expr
- {
- $$ = nod(ORSH, $1, $3);
- }
- /* not an expression anymore, but left in so we can give a good error */
-| expr LCOMM expr
- {
- $$ = nod(OSEND, $1, $3);
- }
-
-uexpr:
- pexpr
-| '*' uexpr
- {
- $$ = nod(OIND, $2, N);
- }
-| '&' uexpr
- {
- if($2->op == OCOMPLIT) {
- // Special case for &T{...}: turn into (*T){...}.
- $$ = $2;
- $$->right = nod(OIND, $$->right, N);
- $$->right->implicit = 1;
- } else {
- $$ = nod(OADDR, $2, N);
- }
- }
-| '+' uexpr
- {
- $$ = nod(OPLUS, $2, N);
- }
-| '-' uexpr
- {
- $$ = nod(OMINUS, $2, N);
- }
-| '!' uexpr
- {
- $$ = nod(ONOT, $2, N);
- }
-| '~' uexpr
- {
- yyerror("the bitwise complement operator is ^");
- $$ = nod(OCOM, $2, N);
- }
-| '^' uexpr
- {
- $$ = nod(OCOM, $2, N);
- }
-| LCOMM uexpr
- {
- $$ = nod(ORECV, $2, N);
- }
-
-/*
- * call-like statements that
- * can be preceded by 'defer' and 'go'
- */
-pseudocall:
- pexpr '(' ')'
- {
- $$ = nod(OCALL, $1, N);
- }
-| pexpr '(' expr_or_type_list ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- }
-| pexpr '(' expr_or_type_list LDDD ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- $$->isddd = 1;
- }
-
-pexpr_no_paren:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| name
-| pexpr '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-| pexpr '.' '(' expr_or_type ')'
- {
- $$ = nod(ODOTTYPE, $1, $4);
- }
-| pexpr '.' '(' LTYPE ')'
- {
- $$ = nod(OTYPESW, N, $1);
- }
-| pexpr '[' expr ']'
- {
- $$ = nod(OINDEX, $1, $3);
- }
-| pexpr '[' oexpr ':' oexpr ']'
- {
- $$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
- }
-| pexpr '[' oexpr ':' oexpr ':' oexpr ']'
- {
- if($5 == N)
- yyerror("middle index required in 3-index slice");
- if($7 == N)
- yyerror("final index required in 3-index slice");
- $$ = nod(OSLICE3, $1, nod(OKEY, $3, nod(OKEY, $5, $7)));
- }
-| pseudocall
-| convtype '(' expr ocomma ')'
- {
- // conversion
- $$ = nod(OCALL, $1, N);
- $$->list = list1($3);
- }
-| comptype lbrace start_complit braced_keyval_list '}'
- {
- $$ = $3;
- $$->right = $1;
- $$->list = $4;
- fixlbrace($2);
- }
-| pexpr_no_paren '{' start_complit braced_keyval_list '}'
- {
- $$ = $3;
- $$->right = $1;
- $$->list = $4;
- }
-| '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
- {
- yyerror("cannot parenthesize type in composite literal");
- $$ = $5;
- $$->right = $2;
- $$->list = $6;
- }
-| fnliteral
-
-start_complit:
- {
- // composite expression.
- // make node early so we get the right line number.
- $$ = nod(OCOMPLIT, N, N);
- }
-
-keyval:
- expr ':' complitexpr
- {
- $$ = nod(OKEY, $1, $3);
- }
-
-bare_complitexpr:
- expr
- {
- // These nodes do not carry line numbers.
- // Since a composite literal commonly spans several lines,
- // the line number on errors may be misleading.
- // Introduce a wrapper node to give the correct line.
- $$ = $1;
- switch($$->op) {
- case ONAME:
- case ONONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- $$ = nod(OPAREN, $$, N);
- $$->implicit = 1;
- }
- }
-| '{' start_complit braced_keyval_list '}'
- {
- $$ = $2;
- $$->list = $3;
- }
-
-complitexpr:
- expr
-| '{' start_complit braced_keyval_list '}'
- {
- $$ = $2;
- $$->list = $3;
- }
-
-pexpr:
- pexpr_no_paren
-| '(' expr_or_type ')'
- {
- $$ = $2;
-
- // Need to know on lhs of := whether there are ( ).
- // Don't bother with the OPAREN in other cases:
- // it's just a waste of memory and time.
- switch($$->op) {
- case ONAME:
- case ONONAME:
- case OPACK:
- case OTYPE:
- case OLITERAL:
- case OTYPESW:
- $$ = nod(OPAREN, $$, N);
- }
- }
-
-expr_or_type:
- expr
-| non_expr_type %prec PreferToRightParen
-
-name_or_type:
- ntype
-
-lbrace:
- LBODY
- {
- $$ = LBODY;
- }
-| '{'
- {
- $$ = '{';
- }
-
-/*
- * names and types
- * newname is used before declared
- * oldname is used after declared
- */
-new_name:
- sym
- {
- if($1 == S)
- $$ = N;
- else
- $$ = newname($1);
- }
-
-dcl_name:
- sym
- {
- $$ = dclname($1);
- }
-
-onew_name:
- {
- $$ = N;
- }
-| new_name
-
-sym:
- LNAME
- {
- $$ = $1;
- // during imports, unqualified non-exported identifiers are from builtinpkg
- if(importpkg != nil && !exportname($1->name))
- $$ = pkglookup($1->name, builtinpkg);
- }
-| hidden_importsym
-| '?'
- {
- $$ = S;
- }
-
-hidden_importsym:
- '@' LLITERAL '.' LNAME
- {
- Pkg *p;
-
- if($2.u.sval->len == 0)
- p = importpkg;
- else {
- if(isbadimport($2.u.sval))
- errorexit();
- p = mkpkg($2.u.sval);
- }
- $$ = pkglookup($4->name, p);
- }
-| '@' LLITERAL '.' '?'
- {
- Pkg *p;
-
- if($2.u.sval->len == 0)
- p = importpkg;
- else {
- if(isbadimport($2.u.sval))
- errorexit();
- p = mkpkg($2.u.sval);
- }
- $$ = pkglookup("?", p);
- }
-
-name:
- sym %prec NotParen
- {
- $$ = oldname($1);
- if($$->pack != N)
- $$->pack->used = 1;
- }
-
-labelname:
- new_name
-
-/*
- * to avoid parsing conflicts, type is split into
- * channel types
- * function types
- * parenthesized types
- * any other type
- * the type system makes additional restrictions,
- * but those are not implemented in the grammar.
- */
-dotdotdot:
- LDDD
- {
- yyerror("final argument in variadic function missing type");
- $$ = nod(ODDD, typenod(typ(TINTER)), N);
- }
-| LDDD ntype
- {
- $$ = nod(ODDD, $2, N);
- }
-
-ntype:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = $2;
- }
-
-non_expr_type:
- recvchantype
-| fntype
-| othertype
-| '*' non_expr_type
- {
- $$ = nod(OIND, $2, N);
- }
-
-non_recvchantype:
- fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = $2;
- }
-
-convtype:
- fntype
-| othertype
-
-comptype:
- othertype
-
-fnret_type:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-
-dotname:
- name
-| name '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-
-othertype:
- '[' oexpr ']' ntype
- {
- $$ = nod(OTARRAY, $2, $4);
- }
-| '[' LDDD ']' ntype
- {
- // array literal of nelem
- $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
- }
-| LCHAN non_recvchantype
- {
- $$ = nod(OTCHAN, $2, N);
- $$->etype = Cboth;
- }
-| LCHAN LCOMM ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Csend;
- }
-| LMAP '[' ntype ']' ntype
- {
- $$ = nod(OTMAP, $3, $5);
- }
-| structtype
-| interfacetype
-
-ptrtype:
- '*' ntype
- {
- $$ = nod(OIND, $2, N);
- }
-
-recvchantype:
- LCOMM LCHAN ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Crecv;
- }
-
-structtype:
- LSTRUCT lbrace structdcl_list osemi '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LSTRUCT lbrace '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- fixlbrace($2);
- }
-
-interfacetype:
- LINTERFACE lbrace interfacedcl_list osemi '}'
- {
- $$ = nod(OTINTER, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LINTERFACE lbrace '}'
- {
- $$ = nod(OTINTER, N, N);
- fixlbrace($2);
- }
-
-/*
- * function stuff
- * all in one place to show how crappy it all is
- */
-xfndcl:
- LFUNC fndcl fnbody
- {
- $$ = $2;
- if($$ == N)
- break;
- if(noescape && $3 != nil)
- yyerror("can only use //go:noescape with external func implementations");
- $$->nbody = $3;
- $$->endlineno = lineno;
- $$->noescape = noescape;
- $$->nosplit = nosplit;
- $$->nowritebarrier = nowritebarrier;
- funcbody($$);
- }
-
-fndcl:
- sym '(' oarg_type_list_ocomma ')' fnres
- {
- Node *t;
-
- $$ = N;
- $3 = checkarglist($3, 1);
-
- if(strcmp($1->name, "init") == 0) {
- $1 = renameinit();
- if($3 != nil || $5 != nil)
- yyerror("func init must have no arguments and no return values");
- }
- if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
- if($3 != nil || $5 != nil)
- yyerror("func main must have no arguments and no return values");
- }
-
- t = nod(OTFUNC, N, N);
- t->list = $3;
- t->rlist = $5;
-
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = newname($1);
- $$->nname->defn = $$;
- $$->nname->ntype = t; // TODO: check if nname already has an ntype
- declare($$->nname, PFUNC);
-
- funchdr($$);
- }
-| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
- {
- Node *rcvr, *t;
-
- $$ = N;
- $2 = checkarglist($2, 0);
- $6 = checkarglist($6, 1);
-
- if($2 == nil) {
- yyerror("method has no receiver");
- break;
- }
- if($2->next != nil) {
- yyerror("method has multiple receivers");
- break;
- }
- rcvr = $2->n;
- if(rcvr->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- break;
- }
-
- t = nod(OTFUNC, rcvr, N);
- t->list = $6;
- t->rlist = $8;
-
- $$ = nod(ODCLFUNC, N, N);
- $$->shortname = newname($4);
- $$->nname = methodname1($$->shortname, rcvr->right);
- $$->nname->defn = $$;
- $$->nname->ntype = t;
- $$->nname->nointerface = nointerface;
- declare($$->nname, PFUNC);
-
- funchdr($$);
- }
-
-hidden_fndcl:
- hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
- {
- Sym *s;
- Type *t;
-
- $$ = N;
-
- s = $1;
- t = functype(N, $3, $5);
-
- importsym(s, ONAME);
- if(s->def != N && s->def->op == ONAME) {
- if(eqtype(t, s->def->type)) {
- dclcontext = PDISCARD; // since we skip funchdr below
- break;
- }
- yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
- }
-
- $$ = newname(s);
- $$->type = t;
- declare($$, PFUNC);
-
- funchdr($$);
- }
-| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = methodname1(newname($4), $2->n->right);
- $$->type = functype($2->n, $6, $8);
-
- checkwidth($$->type);
- addmethod($4, $$->type, 0, nointerface);
- nointerface = 0;
- funchdr($$);
-
- // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
- // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
- // out by typecheck's lookdot as this $$->ttype. So by providing
- // this back link here we avoid special casing there.
- $$->type->nname = $$;
- }
-
-fntype:
- LFUNC '(' oarg_type_list_ocomma ')' fnres
- {
- $3 = checkarglist($3, 1);
- $$ = nod(OTFUNC, N, N);
- $$->list = $3;
- $$->rlist = $5;
- }
-
-fnbody:
- {
- $$ = nil;
- }
-| '{' stmt_list '}'
- {
- $$ = $2;
- if($$ == nil)
- $$ = list1(nod(OEMPTY, N, N));
- }
-
-fnres:
- %prec NotParen
- {
- $$ = nil;
- }
-| fnret_type
- {
- $$ = list1(nod(ODCLFIELD, N, $1));
- }
-| '(' oarg_type_list_ocomma ')'
- {
- $2 = checkarglist($2, 0);
- $$ = $2;
- }
-
-fnlitdcl:
- fntype
- {
- closurehdr($1);
- }
-
-fnliteral:
- fnlitdcl lbrace stmt_list '}'
- {
- $$ = closurebody($3);
- fixlbrace($2);
- }
-| fnlitdcl error
- {
- $$ = closurebody(nil);
- }
-
-/*
- * lists of things
- * note that they are left recursive
- * to conserve yacc stack. they need to
- * be reversed to interpret correctly
- */
-xdcl_list:
- {
- $$ = nil;
- }
-| xdcl_list xdcl ';'
- {
- $$ = concat($1, $2);
- if(nsyntaxerrors == 0)
- testdclstack();
- nointerface = 0;
- noescape = 0;
- nosplit = 0;
- nowritebarrier = 0;
- }
-
-vardcl_list:
- vardcl
-| vardcl_list ';' vardcl
- {
- $$ = concat($1, $3);
- }
-
-constdcl_list:
- constdcl1
-| constdcl_list ';' constdcl1
- {
- $$ = concat($1, $3);
- }
-
-typedcl_list:
- typedcl
- {
- $$ = list1($1);
- }
-| typedcl_list ';' typedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl_list:
- structdcl
-| structdcl_list ';' structdcl
- {
- $$ = concat($1, $3);
- }
-
-interfacedcl_list:
- interfacedcl
- {
- $$ = list1($1);
- }
-| interfacedcl_list ';' interfacedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl:
- new_name_list ntype oliteral
- {
- NodeList *l;
-
- Node *n;
- l = $1;
- if(l == nil) {
- // ? symbol, during import (list1(N) == nil)
- n = $2;
- if(n->op == OIND)
- n = n->left;
- n = embedded(n->sym, importpkg);
- n->right = $2;
- n->val = $3;
- $$ = list1(n);
- break;
- }
-
- for(l=$1; l; l=l->next) {
- l->n = nod(ODCLFIELD, l->n, $2);
- l->n->val = $3;
- }
- }
-| embed oliteral
- {
- $1->val = $2;
- $$ = list1($1);
- }
-| '(' embed ')' oliteral
- {
- $2->val = $4;
- $$ = list1($2);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' embed oliteral
- {
- $2->right = nod(OIND, $2->right, N);
- $2->val = $3;
- $$ = list1($2);
- }
-| '(' '*' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' '(' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-
-packname:
- LNAME
- {
- Node *n;
-
- $$ = $1;
- n = oldname($1);
- if(n->pack != N)
- n->pack->used = 1;
- }
-| LNAME '.' sym
- {
- Pkg *pkg;
-
- if($1->def == N || $1->def->op != OPACK) {
- yyerror("%S is not a package", $1);
- pkg = localpkg;
- } else {
- $1->def->used = 1;
- pkg = $1->def->pkg;
- }
- $$ = restrictlookup($3->name, pkg);
- }
-
-embed:
- packname
- {
- $$ = embedded($1, localpkg);
- }
-
-interfacedcl:
- new_name indcl
- {
- $$ = nod(ODCLFIELD, $1, $2);
- ifacedcl($$);
- }
-| packname
- {
- $$ = nod(ODCLFIELD, N, oldname($1));
- }
-| '(' packname ')'
- {
- $$ = nod(ODCLFIELD, N, oldname($2));
- yyerror("cannot parenthesize embedded type");
- }
-
-indcl:
- '(' oarg_type_list_ocomma ')' fnres
- {
- // without func keyword
- $2 = checkarglist($2, 1);
- $$ = nod(OTFUNC, fakethis(), N);
- $$->list = $2;
- $$->rlist = $4;
- }
-
-/*
- * function arguments.
- */
-arg_type:
- name_or_type
-| sym name_or_type
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| sym dotdotdot
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| dotdotdot
-
-arg_type_list:
- arg_type
- {
- $$ = list1($1);
- }
-| arg_type_list ',' arg_type
- {
- $$ = list($1, $3);
- }
-
-oarg_type_list_ocomma:
- {
- $$ = nil;
- }
-| arg_type_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * statement
- */
-stmt:
- {
- $$ = N;
- }
-| compound_stmt
-| common_dcl
- {
- $$ = liststmt($1);
- }
-| non_dcl_stmt
-| error
- {
- $$ = N;
- }
-
-non_dcl_stmt:
- simple_stmt
-| for_stmt
-| switch_stmt
-| select_stmt
-| if_stmt
-| labelname ':'
- {
- $1 = nod(OLABEL, $1, N);
- $1->sym = dclstack; // context, for goto restrictions
- }
- stmt
- {
- NodeList *l;
-
- $1->defn = $4;
- l = list1($1);
- if($4)
- l = list(l, $4);
- $$ = liststmt(l);
- }
-| LFALL
- {
- // will be converted to OFALL
- $$ = nod(OXFALL, N, N);
- $$->xoffset = block;
- }
-| LBREAK onew_name
- {
- $$ = nod(OBREAK, $2, N);
- }
-| LCONTINUE onew_name
- {
- $$ = nod(OCONTINUE, $2, N);
- }
-| LGO pseudocall
- {
- $$ = nod(OPROC, $2, N);
- }
-| LDEFER pseudocall
- {
- $$ = nod(ODEFER, $2, N);
- }
-| LGOTO new_name
- {
- $$ = nod(OGOTO, $2, N);
- $$->sym = dclstack; // context, for goto restrictions
- }
-| LRETURN oexpr_list
- {
- $$ = nod(ORETURN, N, N);
- $$->list = $2;
- if($$->list == nil && curfn != N) {
- NodeList *l;
-
- for(l=curfn->dcl; l; l=l->next) {
- if(l->n->class == PPARAM)
- continue;
- if(l->n->class != PPARAMOUT)
- break;
- if(l->n->sym->def != l->n)
- yyerror("%s is shadowed during return", l->n->sym->name);
- }
- }
- }
-
-stmt_list:
- stmt
- {
- $$ = nil;
- if($1 != N)
- $$ = list1($1);
- }
-| stmt_list ';' stmt
- {
- $$ = $1;
- if($3 != N)
- $$ = list($$, $3);
- }
-
-new_name_list:
- new_name
- {
- $$ = list1($1);
- }
-| new_name_list ',' new_name
- {
- $$ = list($1, $3);
- }
-
-dcl_name_list:
- dcl_name
- {
- $$ = list1($1);
- }
-| dcl_name_list ',' dcl_name
- {
- $$ = list($1, $3);
- }
-
-expr_list:
- expr
- {
- $$ = list1($1);
- }
-| expr_list ',' expr
- {
- $$ = list($1, $3);
- }
-
-expr_or_type_list:
- expr_or_type
- {
- $$ = list1($1);
- }
-| expr_or_type_list ',' expr_or_type
- {
- $$ = list($1, $3);
- }
-
-/*
- * list of combo of keyval and val
- */
-keyval_list:
- keyval
- {
- $$ = list1($1);
- }
-| bare_complitexpr
- {
- $$ = list1($1);
- }
-| keyval_list ',' keyval
- {
- $$ = list($1, $3);
- }
-| keyval_list ',' bare_complitexpr
- {
- $$ = list($1, $3);
- }
-
-braced_keyval_list:
- {
- $$ = nil;
- }
-| keyval_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * optional things
- */
-osemi:
-| ';'
-
-ocomma:
-| ','
-
-oexpr:
- {
- $$ = N;
- }
-| expr
-
-oexpr_list:
- {
- $$ = nil;
- }
-| expr_list
-
-osimple_stmt:
- {
- $$ = N;
- }
-| simple_stmt
-
-ohidden_funarg_list:
- {
- $$ = nil;
- }
-| hidden_funarg_list
-
-ohidden_structdcl_list:
- {
- $$ = nil;
- }
-| hidden_structdcl_list
-
-ohidden_interfacedcl_list:
- {
- $$ = nil;
- }
-| hidden_interfacedcl_list
-
-oliteral:
- {
- $$.ctype = CTxxx;
- }
-| LLITERAL
-
-/*
- * import syntax from package header
- */
-hidden_import:
- LIMPORT LNAME LLITERAL ';'
- {
- importimport($2, $3.u.sval);
- }
-| LVAR hidden_pkg_importsym hidden_type ';'
- {
- importvar($2, $3);
- }
-| LCONST hidden_pkg_importsym '=' hidden_constant ';'
- {
- importconst($2, types[TIDEAL], $4);
- }
-| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
- {
- importconst($2, $3, $5);
- }
-| LTYPE hidden_pkgtype hidden_type ';'
- {
- importtype($2, $3);
- }
-| LFUNC hidden_fndcl fnbody ';'
- {
- if($2 == N) {
- dclcontext = PEXTERN; // since we skip the funcbody below
- break;
- }
-
- $2->inl = $3;
-
- funcbody($2);
- importlist = list(importlist, $2);
-
- if(debug['E']) {
- print("import [%Z] func %lN \n", importpkg->path, $2);
- if(debug['m'] > 2 && $2->inl)
- print("inl body:%+H\n", $2->inl);
- }
- }
-
-hidden_pkg_importsym:
- hidden_importsym
- {
- $$ = $1;
- structpkg = $$->pkg;
- }
-
-hidden_pkgtype:
- hidden_pkg_importsym
- {
- $$ = pkgtype($1);
- importsym($1, OTYPE);
- }
-
-/*
- * importing types
- */
-
-hidden_type:
- hidden_type_misc
-| hidden_type_recv_chan
-| hidden_type_func
-
-hidden_type_non_recv_chan:
- hidden_type_misc
-| hidden_type_func
-
-hidden_type_misc:
- hidden_importsym
- {
- $$ = pkgtype($1);
- }
-| LNAME
- {
- // predefined name like uint8
- $1 = pkglookup($1->name, builtinpkg);
- if($1->def == N || $1->def->op != OTYPE) {
- yyerror("%s is not a type", $1->name);
- $$ = T;
- } else
- $$ = $1->def->type;
- }
-| '[' ']' hidden_type
- {
- $$ = aindex(N, $3);
- }
-| '[' LLITERAL ']' hidden_type
- {
- $$ = aindex(nodlit($2), $4);
- }
-| LMAP '[' hidden_type ']' hidden_type
- {
- $$ = maptype($3, $5);
- }
-| LSTRUCT '{' ohidden_structdcl_list '}'
- {
- $$ = tostruct($3);
- }
-| LINTERFACE '{' ohidden_interfacedcl_list '}'
- {
- $$ = tointerface($3);
- }
-| '*' hidden_type
- {
- $$ = ptrto($2);
- }
-| LCHAN hidden_type_non_recv_chan
- {
- $$ = typ(TCHAN);
- $$->type = $2;
- $$->chan = Cboth;
- }
-| LCHAN '(' hidden_type_recv_chan ')'
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Cboth;
- }
-| LCHAN LCOMM hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Csend;
- }
-
-hidden_type_recv_chan:
- LCOMM LCHAN hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Crecv;
- }
-
-hidden_type_func:
- LFUNC '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = functype(nil, $3, $5);
- }
-
-hidden_funarg:
- sym hidden_type oliteral
- {
- $$ = nod(ODCLFIELD, N, typenod($2));
- if($1)
- $$->left = newname($1);
- $$->val = $3;
- }
-| sym LDDD hidden_type oliteral
- {
- Type *t;
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = $3;
-
- $$ = nod(ODCLFIELD, N, typenod(t));
- if($1)
- $$->left = newname($1);
- $$->isddd = 1;
- $$->val = $4;
- }
-
-hidden_structdcl:
- sym hidden_type oliteral
- {
- Sym *s;
- Pkg *p;
-
- if($1 != S && strcmp($1->name, "?") != 0) {
- $$ = nod(ODCLFIELD, newname($1), typenod($2));
- $$->val = $3;
- } else {
- s = $2->sym;
- if(s == S && isptr[$2->etype])
- s = $2->type->sym;
- p = importpkg;
- if($1 != S)
- p = $1->pkg;
- $$ = embedded(s, p);
- $$->right = typenod($2);
- $$->val = $3;
- }
- }
-
-hidden_interfacedcl:
- sym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- }
-| hidden_type
- {
- $$ = nod(ODCLFIELD, N, typenod($1));
- }
-
-ohidden_funres:
- {
- $$ = nil;
- }
-| hidden_funres
-
-hidden_funres:
- '(' ohidden_funarg_list ')'
- {
- $$ = $2;
- }
-| hidden_type
- {
- $$ = list1(nod(ODCLFIELD, N, typenod($1)));
- }
-
-/*
- * importing constants
- */
-
-hidden_literal:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| '-' LLITERAL
- {
- $$ = nodlit($2);
- switch($$->val.ctype){
- case CTINT:
- case CTRUNE:
- mpnegfix($$->val.u.xval);
- break;
- case CTFLT:
- mpnegflt($$->val.u.fval);
- break;
- case CTCPLX:
- mpnegflt(&$$->val.u.cval->real);
- mpnegflt(&$$->val.u.cval->imag);
- break;
- default:
- yyerror("bad negated constant");
- }
- }
-| sym
- {
- $$ = oldname(pkglookup($1->name, builtinpkg));
- if($$->op != OLITERAL)
- yyerror("bad constant %S", $$->sym);
- }
-
-hidden_constant:
- hidden_literal
-| '(' hidden_literal '+' hidden_literal ')'
- {
- if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) {
- $$ = $2;
- mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0);
- break;
- }
- $4->val.u.cval->real = $4->val.u.cval->imag;
- mpmovecflt(&$4->val.u.cval->imag, 0.0);
- $$ = nodcplxlit($2->val, $4->val);
- }
-
-hidden_import_list:
-| hidden_import_list hidden_import
-
-hidden_funarg_list:
- hidden_funarg
- {
- $$ = list1($1);
- }
-| hidden_funarg_list ',' hidden_funarg
- {
- $$ = list($1, $3);
- }
-
-hidden_structdcl_list:
- hidden_structdcl
- {
- $$ = list1($1);
- }
-| hidden_structdcl_list ';' hidden_structdcl
- {
- $$ = list($1, $3);
- }
-
-hidden_interfacedcl_list:
- hidden_interfacedcl
- {
- $$ = list1($1);
- }
-| hidden_interfacedcl_list ';' hidden_interfacedcl
- {
- $$ = list($1, $3);
- }
-
-%%
-
-static void
-fixlbrace(int lbr)
-{
- // If the opening brace was an LBODY,
- // set up for another one now that we're done.
- // See comment in lex.c about loophack.
- if(lbr == LBODY)
- loophack = 1;
-}
-
diff --git a/src/cmd/gc/gsubr.c b/src/cmd/gc/gsubr.c
deleted file mode 100644
index 5175ae34f5..0000000000
--- a/src/cmd/gc/gsubr.c
+++ /dev/null
@@ -1,654 +0,0 @@
-// 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 "go.h"
-#include "../../runtime/funcdata.h"
-#include "../ld/textflag.h"
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = thearch.gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = thearch.gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = thearch.gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-void
-clearp(Prog *p)
-{
- nopout(p);
- 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;
- } 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 = TYPE_BRANCH;
- p->to.u.branch = P;
- if(as != AJMP && likely != 0 && thearch.thechar != '9') {
- p->from.type = TYPE_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 != TYPE_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 != TYPE_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)
-{
- thearch.gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-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 == TYPE_ADDR && a->name == NAME_EXTERN) {
- a->type = TYPE_MEM;
- a->sym = linksym(n->sym);
- }
-}
-
-/*
- * 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;
-}
-
-/*
- * 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:
- return 1;
- case OADDR:
- return thearch.thechar == '6' || thearch.thechar == '9'; // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
- }
- return 0;
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog *p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
- if (p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a == N || b == N)
- return 0;
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
-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) {
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = thearch.REGSP;
- if(thearch.thechar == '5')
- n->xoffset += 4;
- if(thearch.thechar == '9')
- n->xoffset += 8;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
-
- case 2: // offset output arg
-fatal("shouldn't be used");
- n->op = OINDREG;
- n->val.u.reg = thearch.REGSP;
- n->xoffset += types[tptr]->width;
- break;
- }
- n->typecheck = 1;
- return n;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- *a = zprog.from;
- if(n == N)
- return;
-
- if(n->type != T && n->type->etype != TIDEAL) {
- // TODO(rsc): This is undone by the selective clearing of width below,
- // to match architectures that were not as aggressive in setting width
- // during naddr. Those widths must be cleared to avoid triggering
- // failures in gins when it detects real but heretofore latent (and one
- // hopes innocuous) type mismatches.
- // The type mismatches should be fixed and the clearing below removed.
- dowidth(n->type);
- a->width = n->type->width;
- }
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
- a->width = 0;
- break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- 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);
- if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
- a->width = 0;
- 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 = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = thearch.REGCTXT;
- a->sym = nil;
- a->offset = n->xoffset;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case ONAME:
- a->etype = 0;
- if(n->type != T)
- a->etype = simtype[n->type->etype];
- 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 = TYPE_MEM;
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->name = NAME_EXTERN;
- a->type = TYPE_ADDR;
- a->width = widthptr;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- if(thearch.thechar == '8')
- a->width = 0;
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_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 = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- a->etype = tptr;
- if(thearch.thechar != '5' && thearch.thechar != '9') // TODO(rsc): Do this even for arm, ppc64.
- a->width = widthptr;
- if(a->type != TYPE_MEM)
- fatal("naddr: OADDR %D (from %O)", a, n->left->op);
- a->type = TYPE_ADDR;
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // itab(nil)
- a->etype = tptr;
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_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);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = simtype[TUINT];
- if(thearch.thechar == '9')
- a->etype = simtype[TINT];
- a->offset += Array_nel;
- if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
- a->width = widthint;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = simtype[TUINT];
- if(thearch.thechar == '9')
- a->etype = simtype[TINT];
- a->offset += Array_cap;
- if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
- a->width = widthint;
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
- }
-}
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
deleted file mode 100644
index f1484ea1a6..0000000000
--- a/src/cmd/gc/init.c
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * a function named init is a special case.
- * it is called by the initialization before
- * main is run. to make it unique within a
- * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init.1".
- */
-Sym*
-renameinit(void)
-{
- static int initgen;
-
- snprint(namebuf, sizeof(namebuf), "init.%d", ++initgen);
- return lookup(namebuf);
-}
-
-/*
- * hand-craft the following initialization code
- * var initdone· uint8 (1)
- * func init() (2)
- * if initdone· != 0 { (3)
- * if initdone· == 2 (4)
- * return
- * throw(); (5)
- * }
- * initdone· = 1; (6)
- * // over all matching imported symbols
- * <pkg>.init() (7)
- * { <init stmts> } (8)
- * init.<n>() // if any (9)
- * initdone· = 2; (10)
- * return (11)
- * }
- */
-static int
-anyinit(NodeList *n)
-{
- uint32 h;
- Sym *s;
- NodeList *l;
-
- // are there any interesting init statements
- for(l=n; l; l=l->next) {
- switch(l->n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- case OEMPTY:
- break;
- case OAS:
- if(isblank(l->n->left) && candiscard(l->n->right))
- break;
- // fall through
- default:
- return 1;
- }
- }
-
- // is this main
- if(strcmp(localpkg->name, "main") == 0)
- return 1;
-
- // is there an explicit init function
- s = lookup("init.1");
- if(s->def != N)
- return 1;
-
- // are there any imported init functions
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- return 1;
- }
-
- // then none
- return 0;
-}
-
-void
-fninit(NodeList *n)
-{
- int i;
- Node *gatevar;
- Node *a, *b, *fn;
- NodeList *r;
- uint32 h;
- Sym *s, *initsym;
-
- if(debug['A']) {
- // sys.go or unsafe.go during compiler build
- return;
- }
-
- n = initfix(n);
- if(!anyinit(n))
- return;
-
- r = nil;
-
- // (1)
- snprint(namebuf, sizeof(namebuf), "initdone·");
- gatevar = newname(lookup(namebuf));
- addvar(gatevar, types[TUINT8], PEXTERN);
-
- // (2)
- maxarg = 0;
- snprint(namebuf, sizeof(namebuf), "init");
-
- fn = nod(ODCLFUNC, N, N);
- initsym = lookup(namebuf);
- fn->nname = newname(initsym);
- fn->nname->defn = fn;
- fn->nname->ntype = nod(OTFUNC, N, N);
- declare(fn->nname, PFUNC);
- funchdr(fn);
-
- // (3)
- a = nod(OIF, N, N);
- a->ntest = nod(ONE, gatevar, nodintconst(0));
- r = list(r, a);
-
- // (4)
- b = nod(OIF, N, N);
- b->ntest = nod(OEQ, gatevar, nodintconst(2));
- b->nbody = list1(nod(ORETURN, N, N));
- a->nbody = list1(b);
-
- // (5)
- b = syslook("throwinit", 0);
- b = nod(OCALL, b, N);
- a->nbody = list(a->nbody, b);
-
- // (6)
- a = nod(OAS, gatevar, nodintconst(1));
- r = list(r, a);
-
- // (7)
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- if(s == initsym)
- continue;
-
- // could check that it is fn of no args/returns
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (8)
- r = concat(r, n);
-
- // (9)
- // could check that it is fn of no args/returns
- for(i=1;; i++) {
- snprint(namebuf, sizeof(namebuf), "init.%d", i);
- s = lookup(namebuf);
- if(s->def == N)
- break;
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (10)
- a = nod(OAS, gatevar, nodintconst(2));
- r = list(r, a);
-
- // (11)
- a = nod(ORETURN, N, N);
- r = list(r, a);
- exportsym(fn->nname);
-
- fn->nbody = r;
- funcbody(fn);
-
- curfn = fn;
- typecheck(&fn, Etop);
- typechecklist(r, Etop);
- curfn = nil;
- funccompile(fn);
-}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
deleted file mode 100644
index 45e15bb9b7..0000000000
--- a/src/cmd/gc/inl.c
+++ /dev/null
@@ -1,986 +0,0 @@
-// 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.
-//
-// The inlining facility makes 2 passes: first caninl determines which
-// functions are suitable for inlining, and for those that are it
-// saves a copy of the body. Then inlcalls walks each function body to
-// expand calls to inlinable functions.
-//
-// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
-// making 1 the default and -l disable. -ll and more is useful to flush out bugs.
-// These additional levels (beyond -l) may be buggy and are not supported.
-// 0: disabled
-// 1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
-// 2: early typechecking of all imported bodies
-// 3: allow variadic functions
-// 4: allow non-leaf functions , (breaks runtime.Caller)
-// 5: transitive inlining
-//
-// At some point this may get another default and become switch-offable with -N.
-//
-// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying
-// which calls get inlined or not, more is for debugging, and may go away at any point.
-//
-// TODO:
-// - inline functions with ... args
-// - handle T.meth(f()) with func f() (t T, arg, arg, )
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// Used by caninl.
-static Node* inlcopy(Node *n);
-static NodeList* inlcopylist(NodeList *ll);
-static int ishairy(Node *n, int *budget);
-static int ishairylist(NodeList *ll, int *budget);
-
-// Used by inlcalls
-static void inlnodelist(NodeList *l);
-static void inlnode(Node **np);
-static void mkinlcall(Node **np, Node *fn, int isddd);
-static Node* inlvar(Node *n);
-static Node* retvar(Type *n, int i);
-static Node* argvar(Type *n, int i);
-static Node* newlabel(void);
-static Node* inlsubst(Node *n);
-static NodeList* inlsubstlist(NodeList *l);
-
-static void setlno(Node*, int);
-
-// Used during inlsubst[list]
-static Node *inlfn; // function currently being inlined
-static Node *inlretlabel; // target of the goto substituted in place of a return
-static NodeList *inlretvars; // temp out variables
-
-// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
-// the ->sym can be re-used in the local package, so peel it off the receiver's type.
-static Pkg*
-fnpkg(Node *fn)
-{
- Type *rcvr;
-
- if(fn->type->thistuple) {
- // method
- rcvr = getthisx(fn->type)->type->type;
- if(isptr[rcvr->etype])
- rcvr = rcvr->type;
- if(!rcvr->sym)
- fatal("receiver with no sym: [%S] %lN (%T)", fn->sym, fn, rcvr);
- return rcvr->sym->pkg;
- }
- // non-method
- return fn->sym->pkg;
-}
-
-// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
-// because they're a copy of an already checked body.
-void
-typecheckinl(Node *fn)
-{
- Node *savefn;
- Pkg *pkg;
- int save_safemode, lno;
-
- lno = setlineno(fn);
-
- // typecheckinl is only for imported functions;
- // their bodies may refer to unsafe as long as the package
- // was marked safe during import (which was checked then).
- // the ->inl of a local function has been typechecked before caninl copied it.
- pkg = fnpkg(fn);
- if (pkg == localpkg || pkg == nil)
- return; // typecheckinl on local function
-
- if (debug['m']>2)
- print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl);
-
- save_safemode = safemode;
- safemode = 0;
-
- savefn = curfn;
- curfn = fn;
- typechecklist(fn->inl, Etop);
- curfn = savefn;
-
- safemode = save_safemode;
-
- lineno = lno;
-}
-
-// Caninl determines whether fn is inlineable.
-// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
-// fn and ->nbody will already have been typechecked.
-void
-caninl(Node *fn)
-{
- Node *savefn;
- Type *t;
- int budget;
-
- if(fn->op != ODCLFUNC)
- fatal("caninl %N", fn);
- if(!fn->nname)
- fatal("caninl no nname %+N", fn);
-
- // If fn has no body (is defined outside of Go), cannot inline it.
- if(fn->nbody == nil)
- return;
-
- if(fn->typecheck == 0)
- fatal("caninl on non-typechecked function %N", fn);
-
- // can't handle ... args yet
- if(debug['l'] < 3)
- for(t=fn->type->type->down->down->type; t; t=t->down)
- if(t->isddd)
- return;
-
- budget = 40; // allowed hairyness
- if(ishairylist(fn->nbody, &budget))
- return;
-
- savefn = curfn;
- curfn = fn;
-
- fn->nname->inl = fn->nbody;
- fn->nbody = inlcopylist(fn->nname->inl);
- fn->nname->inldcl = inlcopylist(fn->nname->defn->dcl);
-
- // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
- // this is so export can find the body of a method
- fn->type->nname = fn->nname;
-
- if(debug['m'] > 1)
- print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl);
- else if(debug['m'])
- print("%L: can inline %N\n", fn->lineno, fn->nname);
-
- curfn = savefn;
-}
-
-// Look for anything we want to punt on.
-static int
-ishairylist(NodeList *ll, int* budget)
-{
- for(;ll;ll=ll->next)
- if(ishairy(ll->n, budget))
- return 1;
- return 0;
-}
-
-static int
-ishairy(Node *n, int *budget)
-{
- if(!n)
- return 0;
-
- // Things that are too hairy, irrespective of the budget
- switch(n->op) {
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- case OPANIC:
- case ORECOVER:
- if(debug['l'] < 4)
- return 1;
- break;
-
- case OCLOSURE:
- case OCALLPART:
- case ORANGE:
- case OFOR:
- case OSELECT:
- case OSWITCH:
- case OPROC:
- case ODEFER:
- case ODCLTYPE: // can't print yet
- case ODCLCONST: // can't print yet
- case ORETJMP:
- return 1;
-
- break;
- }
-
- (*budget)--;
-
- return *budget < 0 ||
- ishairy(n->left, budget) ||
- ishairy(n->right, budget) ||
- ishairylist(n->list, budget) ||
- ishairylist(n->rlist, budget) ||
- ishairylist(n->ninit, budget) ||
- ishairy(n->ntest, budget) ||
- ishairy(n->nincr, budget) ||
- ishairylist(n->nbody, budget) ||
- ishairylist(n->nelse, budget);
-}
-
-// Inlcopy and inlcopylist recursively copy the body of a function.
-// Any name-like node of non-local class is marked for re-export by adding it to
-// the exportlist.
-static NodeList*
-inlcopylist(NodeList *ll)
-{
- NodeList *l;
-
- l = nil;
- for(; ll; ll=ll->next)
- l = list(l, inlcopy(ll->n));
- return l;
-}
-
-static Node*
-inlcopy(Node *n)
-{
- Node *m;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OLITERAL:
- return n;
- }
-
- m = nod(OXXX, N, N);
- *m = *n;
- m->inl = nil;
- m->left = inlcopy(n->left);
- m->right = inlcopy(n->right);
- m->list = inlcopylist(n->list);
- m->rlist = inlcopylist(n->rlist);
- m->ninit = inlcopylist(n->ninit);
- m->ntest = inlcopy(n->ntest);
- m->nincr = inlcopy(n->nincr);
- m->nbody = inlcopylist(n->nbody);
- m->nelse = inlcopylist(n->nelse);
-
- return m;
-}
-
-
-// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
-// calls made to inlineable functions. This is the external entry point.
-void
-inlcalls(Node *fn)
-{
- Node *savefn;
-
- savefn = curfn;
- curfn = fn;
- inlnode(&fn);
- if(fn != curfn)
- fatal("inlnode replaced curfn");
- curfn = savefn;
-}
-
-// Turn an OINLCALL into a statement.
-static void
-inlconv2stmt(Node *n)
-{
- n->op = OBLOCK;
- // n->ninit stays
- n->list = n->nbody;
- n->nbody = nil;
- n->rlist = nil;
-}
-
-// Turn an OINLCALL into a single valued expression.
-static void
-inlconv2expr(Node **np)
-{
- Node *n, *r;
- n = *np;
- r = n->rlist->n;
- addinit(&r, concat(n->ninit, n->nbody));
- *np = r;
-}
-
-// Turn the rlist (with the return values) of the OINLCALL in
-// n into an expression list lumping the ninit and body
-// containing the inlined statements on the first list element so
-// order will be preserved Used in return, oas2func and call
-// statements.
-static NodeList*
-inlconv2list(Node *n)
-{
- NodeList *l;
-
- if(n->op != OINLCALL || n->rlist == nil)
- fatal("inlconv2list %+N\n", n);
-
- l = n->rlist;
- addinit(&l->n, concat(n->ninit, n->nbody));
- return l;
-}
-
-static void
-inlnodelist(NodeList *l)
-{
- for(; l; l=l->next)
- inlnode(&l->n);
-}
-
-// inlnode recurses over the tree to find inlineable calls, which will
-// be turned into OINLCALLs by mkinlcall. When the recursion comes
-// back up will examine left, right, list, rlist, ninit, ntest, nincr,
-// nbody and nelse and use one of the 4 inlconv/glue functions above
-// to turn the OINLCALL into an expression, a statement, or patch it
-// in to this nodes list or rlist as appropriate.
-// NOTE it makes no sense to pass the glue functions down the
-// recursion to the level where the OINLCALL gets created because they
-// have to edit /this/ n, so you'd have to push that one down as well,
-// but then you may as well do it here. so this is cleaner and
-// shorter and less complicated.
-static void
-inlnode(Node **np)
-{
- Node *n;
- NodeList *l;
- int lno;
-
- if(*np == nil)
- return;
-
- n = *np;
-
- switch(n->op) {
- case ODEFER:
- case OPROC:
- // inhibit inlining of their argument
- switch(n->left->op) {
- case OCALLFUNC:
- case OCALLMETH:
- n->left->etype = n->op;
- }
-
- case OCLOSURE:
- // TODO do them here (or earlier),
- // so escape analysis can avoid more heapmoves.
- return;
- }
-
- lno = setlineno(n);
-
- inlnodelist(n->ninit);
- for(l=n->ninit; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2stmt(l->n);
-
- inlnode(&n->left);
- if(n->left && n->left->op == OINLCALL)
- inlconv2expr(&n->left);
-
- inlnode(&n->right);
- if(n->right && n->right->op == OINLCALL)
- inlconv2expr(&n->right);
-
- inlnodelist(n->list);
- switch(n->op) {
- case OBLOCK:
- for(l=n->list; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2stmt(l->n);
- break;
-
- case ORETURN:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- case OAPPEND:
- case OCOMPLEX:
- // if we just replaced arg in f(arg()) or return arg with an inlined call
- // and arg returns multiple values, glue as list
- if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
- n->list = inlconv2list(n->list->n);
- break;
- }
-
- // fallthrough
- default:
- for(l=n->list; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2expr(&l->n);
- }
-
- inlnodelist(n->rlist);
- switch(n->op) {
- case OAS2FUNC:
- if(n->rlist->n->op == OINLCALL) {
- n->rlist = inlconv2list(n->rlist->n);
- n->op = OAS2;
- n->typecheck = 0;
- typecheck(np, Etop);
- break;
- }
-
- // fallthrough
- default:
- for(l=n->rlist; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2expr(&l->n);
-
- }
-
- inlnode(&n->ntest);
- if(n->ntest && n->ntest->op == OINLCALL)
- inlconv2expr(&n->ntest);
-
- inlnode(&n->nincr);
- if(n->nincr && n->nincr->op == OINLCALL)
- inlconv2stmt(n->nincr);
-
- inlnodelist(n->nbody);
- for(l=n->nbody; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2stmt(l->n);
-
- inlnodelist(n->nelse);
- for(l=n->nelse; l; l=l->next)
- if(l->n->op == OINLCALL)
- inlconv2stmt(l->n);
-
- // with all the branches out of the way, it is now time to
- // transmogrify this node itself unless inhibited by the
- // switch at the top of this function.
- switch(n->op) {
- case OCALLFUNC:
- case OCALLMETH:
- if (n->etype == OPROC || n->etype == ODEFER)
- return;
- }
-
- switch(n->op) {
- case OCALLFUNC:
- if(debug['m']>3)
- print("%L:call to func %+N\n", n->lineno, n->left);
- if(n->left->inl) // normal case
- mkinlcall(np, n->left, n->isddd);
- else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right && n->left->right->op == ONAME) // methods called as functions
- if(n->left->sym->def)
- mkinlcall(np, n->left->sym->def, n->isddd);
- break;
-
- case OCALLMETH:
- if(debug['m']>3)
- print("%L:call to meth %lN\n", n->lineno, n->left->right);
- // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
- if(n->left->type == T)
- fatal("no function type for [%p] %+N\n", n->left, n->left);
-
- if(n->left->type->nname == N)
- fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type);
-
- mkinlcall(np, n->left->type->nname, n->isddd);
-
- break;
- }
-
- lineno = lno;
-}
-
-static void mkinlcall1(Node **np, Node *fn, int isddd);
-
-static void
-mkinlcall(Node **np, Node *fn, int isddd)
-{
- int save_safemode;
- Pkg *pkg;
-
- save_safemode = safemode;
-
- // imported functions may refer to unsafe as long as the
- // package was marked safe during import (already checked).
- pkg = fnpkg(fn);
- if(pkg != localpkg && pkg != nil)
- safemode = 0;
- mkinlcall1(np, fn, isddd);
- safemode = save_safemode;
-}
-
-static Node*
-tinlvar(Type *t)
-{
- if(t->nname && !isblank(t->nname)) {
- if(!t->nname->inlvar)
- fatal("missing inlvar for %N\n", t->nname);
- return t->nname->inlvar;
- }
- typecheck(&nblank, Erv | Easgn);
- return nblank;
-}
-
-static int inlgen;
-
-// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
-// On return ninit has the parameter assignments, the nbody is the
-// inlined function body and list, rlist contain the input, output
-// parameters.
-static void
-mkinlcall1(Node **np, Node *fn, int isddd)
-{
- int i;
- int chkargcount;
- Node *n, *call, *saveinlfn, *as, *m;
- NodeList *dcl, *ll, *ninit, *body;
- Type *t;
- // For variadic fn.
- int variadic, varargcount, multiret;
- Node *vararg;
- NodeList *varargs;
- Type *varargtype, *vararrtype;
-
- if (fn->inl == nil)
- return;
-
- if (fn == curfn || fn->defn == curfn)
- return;
-
- if(debug['l']<2)
- typecheckinl(fn);
-
- n = *np;
-
- // Bingo, we have a function node, and it has an inlineable body
- if(debug['m']>1)
- print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl);
- else if(debug['m'])
- print("%L: inlining call to %N\n", n->lineno, fn);
-
- if(debug['m']>2)
- print("%L: Before inlining: %+N\n", n->lineno, n);
-
- saveinlfn = inlfn;
- inlfn = fn;
-
- ninit = n->ninit;
-
-//dumplist("ninit pre", ninit);
-
- if(fn->defn) // local function
- dcl = fn->inldcl;
- else // imported function
- dcl = fn->dcl;
-
- inlretvars = nil;
- i = 0;
- // Make temp names to use instead of the originals
- for(ll = dcl; ll; ll=ll->next) {
- if(ll->n->class == PPARAMOUT) // return values handled below.
- continue;
- if(ll->n->op == ONAME) {
- ll->n->inlvar = inlvar(ll->n);
- // Typecheck because inlvar is not necessarily a function parameter.
- typecheck(&ll->n->inlvar, Erv);
- if ((ll->n->class&~PHEAP) != PAUTO)
- ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs
- }
- }
-
- // temporaries for return values.
- for(t = getoutargx(fn->type)->type; t; t = t->down) {
- if(t != T && t->nname != N && !isblank(t->nname)) {
- m = inlvar(t->nname);
- typecheck(&m, Erv);
- t->nname->inlvar = m;
- } else {
- // anonymous return values, synthesize names for use in assignment that replaces return
- m = retvar(t, i++);
- }
- ninit = list(ninit, nod(ODCL, m, N));
- inlretvars = list(inlretvars, m);
- }
-
- // assign receiver.
- if(fn->type->thistuple && n->left->op == ODOTMETH) {
- // method call with a receiver.
- t = getthisx(fn->type)->type;
- if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
- fatal("missing inlvar for %N\n", t->nname);
- if(!n->left->left)
- fatal("method call without receiver: %+N", n);
- if(t == T)
- fatal("method call unknown receiver type: %+N", n);
- as = nod(OAS, tinlvar(t), n->left->left);
- if(as != N) {
- typecheck(&as, Etop);
- ninit = list(ninit, as);
- }
- }
-
- // check if inlined function is variadic.
- variadic = 0;
- varargtype = T;
- varargcount = 0;
- for(t=fn->type->type->down->down->type; t; t=t->down) {
- if(t->isddd) {
- variadic = 1;
- varargtype = t->type;
- }
- }
- // but if argument is dotted too forget about variadicity.
- if(variadic && isddd)
- variadic = 0;
-
- // check if argument is actually a returned tuple from call.
- multiret = 0;
- if(n->list && !n->list->next) {
- switch(n->list->n->op) {
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- if(n->list->n->left->type->outtuple > 1)
- multiret = n->list->n->left->type->outtuple-1;
- }
- }
-
- if(variadic) {
- varargcount = count(n->list) + multiret;
- if(n->left->op != ODOTMETH)
- varargcount -= fn->type->thistuple;
- varargcount -= fn->type->intuple - 1;
- }
-
- // assign arguments to the parameters' temp names
- as = nod(OAS2, N, N);
- as->rlist = n->list;
- ll = n->list;
-
- // TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call?
- if(fn->type->thistuple && n->left->op != ODOTMETH) {
- // non-method call to method
- if(!n->list)
- fatal("non-method call to method without first arg: %+N", n);
- // append receiver inlvar to LHS.
- t = getthisx(fn->type)->type;
- if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
- fatal("missing inlvar for %N\n", t->nname);
- if(t == T)
- fatal("method call unknown receiver type: %+N", n);
- as->list = list(as->list, tinlvar(t));
- ll = ll->next; // track argument count.
- }
-
- // append ordinary arguments to LHS.
- chkargcount = n->list && n->list->next;
- vararg = N; // the slice argument to a variadic call
- varargs = nil; // the list of LHS names to put in vararg.
- if(!chkargcount) {
- // 0 or 1 expression on RHS.
- for(t = getinargx(fn->type)->type; t; t=t->down) {
- if(variadic && t->isddd) {
- vararg = tinlvar(t);
- for(i=0; i<varargcount && ll; i++) {
- m = argvar(varargtype, i);
- varargs = list(varargs, m);
- as->list = list(as->list, m);
- }
- break;
- }
- as->list = list(as->list, tinlvar(t));
- }
- } else {
- // match arguments except final variadic (unless the call is dotted itself)
- for(t = getinargx(fn->type)->type; t;) {
- if(!ll)
- break;
- if(variadic && t->isddd)
- break;
- as->list = list(as->list, tinlvar(t));
- t=t->down;
- ll=ll->next;
- }
- // match varargcount arguments with variadic parameters.
- if(variadic && t && t->isddd) {
- vararg = tinlvar(t);
- for(i=0; i<varargcount && ll; i++) {
- m = argvar(varargtype, i);
- varargs = list(varargs, m);
- as->list = list(as->list, m);
- ll=ll->next;
- }
- if(i==varargcount)
- t=t->down;
- }
- if(ll || t)
- fatal("arg count mismatch: %#T vs %,H\n", getinargx(fn->type), n->list);
- }
-
- if (as->rlist) {
- typecheck(&as, Etop);
- ninit = list(ninit, as);
- }
-
- // turn the variadic args into a slice.
- if(variadic) {
- as = nod(OAS, vararg, N);
- if(!varargcount) {
- as->right = nodnil();
- as->right->type = varargtype;
- } else {
- vararrtype = typ(TARRAY);
- vararrtype->type = varargtype->type;
- vararrtype->bound = varargcount;
-
- as->right = nod(OCOMPLIT, N, typenod(varargtype));
- as->right->list = varargs;
- as->right = nod(OSLICE, as->right, nod(OKEY, N, N));
- }
- typecheck(&as, Etop);
- ninit = list(ninit, as);
- }
-
- // zero the outparams
- for(ll = inlretvars; ll; ll=ll->next) {
- as = nod(OAS, ll->n, N);
- typecheck(&as, Etop);
- ninit = list(ninit, as);
- }
-
- inlretlabel = newlabel();
- inlgen++;
- body = inlsubstlist(fn->inl);
-
- body = list(body, nod(OGOTO, inlretlabel, N)); // avoid 'not used' when function doesnt have return
- body = list(body, nod(OLABEL, inlretlabel, N));
-
- typechecklist(body, Etop);
-//dumplist("ninit post", ninit);
-
- call = nod(OINLCALL, N, N);
- call->ninit = ninit;
- call->nbody = body;
- call->rlist = inlretvars;
- call->type = n->type;
- call->typecheck = 1;
-
- setlno(call, n->lineno);
-//dumplist("call body", body);
-
- *np = call;
-
- inlfn = saveinlfn;
-
- // transitive inlining
- // TODO do this pre-expansion on fn->inl directly. requires
- // either supporting exporting statemetns with complex ninits
- // or saving inl and making inlinl
- if(debug['l'] >= 5) {
- body = fn->inl;
- fn->inl = nil; // prevent infinite recursion
- inlnodelist(call->nbody);
- for(ll=call->nbody; ll; ll=ll->next)
- if(ll->n->op == OINLCALL)
- inlconv2stmt(ll->n);
- fn->inl = body;
- }
-
- if(debug['m']>2)
- print("%L: After inlining %+N\n\n", n->lineno, *np);
-
-}
-
-// Every time we expand a function we generate a new set of tmpnames,
-// PAUTO's in the calling functions, and link them off of the
-// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
-static Node*
-inlvar(Node *var)
-{
- Node *n;
-
- if(debug['m']>3)
- print("inlvar %+N\n", var);
-
- n = newname(var->sym);
- n->type = var->type;
- n->class = PAUTO;
- n->used = 1;
- n->curfn = curfn; // the calling function, not the called one
- n->addrtaken = var->addrtaken;
-
- // Esc pass wont run if we're inlining into a iface wrapper.
- // Luckily, we can steal the results from the target func.
- // If inlining a function defined in another package after
- // escape analysis is done, treat all local vars as escaping.
- // See issue 9537.
- if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME))
- addrescapes(n);
-
- curfn->dcl = list(curfn->dcl, n);
- return n;
-}
-
-// Synthesize a variable to store the inlined function's results in.
-static Node*
-retvar(Type *t, int i)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "~r%d", i);
- n = newname(lookup(namebuf));
- n->type = t->type;
- n->class = PAUTO;
- n->used = 1;
- n->curfn = curfn; // the calling function, not the called one
- curfn->dcl = list(curfn->dcl, n);
- return n;
-}
-
-// Synthesize a variable to store the inlined function's arguments
-// when they come from a multiple return call.
-static Node*
-argvar(Type *t, int i)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "~arg%d", i);
- n = newname(lookup(namebuf));
- n->type = t->type;
- n->class = PAUTO;
- n->used = 1;
- n->curfn = curfn; // the calling function, not the called one
- curfn->dcl = list(curfn->dcl, n);
- return n;
-}
-
-static Node*
-newlabel(void)
-{
- Node *n;
- static int label;
-
- label++;
- snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label);
- n = newname(lookup(namebuf));
- n->etype = 1; // flag 'safe' for escape analysis (no backjumps)
- return n;
-}
-
-// inlsubst and inlsubstlist recursively copy the body of the saved
-// pristine ->inl body of the function while substituting references
-// to input/output parameters with ones to the tmpnames, and
-// substituting returns with assignments to the output.
-static NodeList*
-inlsubstlist(NodeList *ll)
-{
- NodeList *l;
-
- l = nil;
- for(; ll; ll=ll->next)
- l = list(l, inlsubst(ll->n));
- return l;
-}
-
-static Node*
-inlsubst(Node *n)
-{
- char *p;
- Node *m, *as;
- NodeList *ll;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- case ONAME:
- if(n->inlvar) { // These will be set during inlnode
- if (debug['m']>2)
- print ("substituting name %+N -> %+N\n", n, n->inlvar);
- return n->inlvar;
- }
- if (debug['m']>2)
- print ("not substituting name %+N\n", n);
- return n;
-
- case OLITERAL:
- case OTYPE:
- return n;
-
- case ORETURN:
- // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
-
-// dump("Return before substitution", n);
- m = nod(OGOTO, inlretlabel, N);
- m->ninit = inlsubstlist(n->ninit);
-
- if(inlretvars && n->list) {
- as = nod(OAS2, N, N);
- // shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
- for(ll=inlretvars; ll; ll=ll->next)
- as->list = list(as->list, ll->n);
- as->rlist = inlsubstlist(n->list);
- typecheck(&as, Etop);
- m->ninit = list(m->ninit, as);
- }
-
- typechecklist(m->ninit, Etop);
- typecheck(&m, Etop);
-// dump("Return after substitution", m);
- return m;
-
- case OGOTO:
- case OLABEL:
- m = nod(OXXX, N, N);
- *m = *n;
- m->ninit = nil;
- p = smprint("%s·%d", n->left->sym->name, inlgen);
- m->left = newname(lookup(p));
- free(p);
- return m;
- }
-
-
- m = nod(OXXX, N, N);
- *m = *n;
- m->ninit = nil;
-
- if(n->op == OCLOSURE)
- fatal("cannot inline function containing closure: %+N", n);
-
- m->left = inlsubst(n->left);
- m->right = inlsubst(n->right);
- m->list = inlsubstlist(n->list);
- m->rlist = inlsubstlist(n->rlist);
- m->ninit = concat(m->ninit, inlsubstlist(n->ninit));
- m->ntest = inlsubst(n->ntest);
- m->nincr = inlsubst(n->nincr);
- m->nbody = inlsubstlist(n->nbody);
- m->nelse = inlsubstlist(n->nelse);
-
- return m;
-}
-
-// Plaster over linenumbers
-static void
-setlnolist(NodeList *ll, int lno)
-{
- for(;ll;ll=ll->next)
- setlno(ll->n, lno);
-}
-
-static void
-setlno(Node *n, int lno)
-{
- if(!n)
- return;
-
- // don't clobber names, unless they're freshly synthesized
- if(n->op != ONAME || n->lineno == 0)
- n->lineno = lno;
-
- setlno(n->left, lno);
- setlno(n->right, lno);
- setlnolist(n->list, lno);
- setlnolist(n->rlist, lno);
- setlnolist(n->ninit, lno);
- setlno(n->ntest, lno);
- setlno(n->nincr, lno);
- setlnolist(n->nbody, lno);
- setlnolist(n->nelse, lno);
-}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
deleted file mode 100644
index a4b832aa0b..0000000000
--- a/src/cmd/gc/lex.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "y.tab.h"
-#include <ar.h>
-
-#ifndef PLAN9
-#include <signal.h>
-#endif
-
-#undef getc
-#undef ungetc
-#define getc ccgetc
-#define ungetc ccungetc
-
-extern int yychar;
-int yyprev;
-int yylast;
-
-static int imported_unsafe;
-
-static void lexinit(void);
-static void lexinit1(void);
-static void lexfini(void);
-static void yytinit(void);
-static int getc(void);
-static void ungetc(int);
-static int32 getr(void);
-static int escchar(int, int*, vlong*);
-static void addidir(char*);
-static int getlinepragma(void);
-static char *goos, *goarch, *goroot;
-
-#define BOM 0xFEFF
-
-// Debug arguments.
-// These can be specified with the -d flag, as in "-d nil"
-// to set the debug_checknil variable. In general the list passed
-// to -d can be comma-separated.
-static struct {
- char *name;
- int *val;
-} debugtab[] = {
- {"nil", &debug_checknil},
-};
-
-// Our own isdigit, isspace, isalpha, isalnum that take care
-// of EOF and other out of range arguments.
-static int
-yy_isdigit(int c)
-{
- return c >= 0 && c <= 0xFF && isdigit(c);
-}
-
-static int
-yy_isspace(int c)
-{
- return c == ' ' || c == '\t' || c == '\n' || c == '\r';
-}
-
-static int
-yy_isalpha(int c)
-{
- return c >= 0 && c <= 0xFF && isalpha(c);
-}
-
-static int
-yy_isalnum(int c)
-{
- return c >= 0 && c <= 0xFF && isalnum(c);
-}
-
-// Disallow use of isdigit etc.
-#undef isdigit
-#undef isspace
-#undef isalpha
-#undef isalnum
-#define isdigit use_yy_isdigit_instead_of_isdigit
-#define isspace use_yy_isspace_instead_of_isspace
-#define isalpha use_yy_isalpha_instead_of_isalpha
-#define isalnum use_yy_isalnum_instead_of_isalnum
-
-#define DBG if(!debug['x']){}else print
-/*c2go void DBG(char*, ...); */
-
-enum
-{
- EOF = -1,
-};
-
-void
-usage(void)
-{
- print("usage: %cg [options] file.go...\n", thearch.thechar);
- flagprint(1);
- exits("usage");
-}
-
-void
-fault(int s)
-{
- USED(s);
-
- // If we've already complained about things
- // in the program, don't bother complaining
- // about the seg fault too; let the user clean up
- // the code and try again.
- if(nsavederrors + nerrors > 0)
- errorexit();
- fatal("fault");
-}
-
-#ifdef PLAN9
-void
-catcher(void *v, char *s)
-{
- USED(v);
-
- if(strncmp(s, "sys: trap: fault read", 21) == 0) {
- if(nsavederrors + nerrors > 0)
- errorexit();
- fatal("fault");
- }
- noted(NDFLT);
-}
-#endif
-
-void
-doversion(void)
-{
- char *p, *sep;
-
- p = expstring();
- if(strcmp(p, "X:none") == 0)
- p = "";
- sep = "";
- if(*p)
- sep = " ";
- print("%cg version %s%s%s\n", thearch.thechar, getgoversion(), sep, p);
- exits(0);
-}
-
-int
-gcmain(int argc, char *argv[])
-{
- int i;
- NodeList *l;
- char *p;
-
-#ifdef SIGBUS
- signal(SIGBUS, fault);
- signal(SIGSEGV, fault);
-#endif
-
-#ifdef PLAN9
- notify(catcher);
- // Tell the FPU to handle all exceptions.
- setfcr(FPPDBL|FPRNR);
-#endif
- // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
- // but not other values.
- p = getgoarch();
- if(strncmp(p, thearch.thestring, strlen(thearch.thestring)) != 0)
- sysfatal("cannot use %cg with GOARCH=%s", thearch.thechar, p);
- goarch = p;
-
- thearch.linkarchinit();
- ctxt = linknew(thearch.thelinkarch);
- ctxt->diag = yyerror;
- ctxt->bso = &bstdout;
- Binit(&bstdout, 1, OWRITE);
-
- localpkg = mkpkg(newstrlit(""));
- localpkg->prefix = "\"\"";
-
- // pseudo-package, for scoping
- builtinpkg = mkpkg(newstrlit("go.builtin"));
- builtinpkg->prefix = "go.builtin"; // not go%2ebuiltin
-
- // pseudo-package, accessed by import "unsafe"
- unsafepkg = mkpkg(newstrlit("unsafe"));
- unsafepkg->name = "unsafe";
-
- // real package, referred to by generated runtime calls
- runtimepkg = mkpkg(newstrlit("runtime"));
- runtimepkg->name = "runtime";
-
- // pseudo-packages used in symbol tables
- gostringpkg = mkpkg(newstrlit("go.string"));
- gostringpkg->name = "go.string";
- gostringpkg->prefix = "go.string"; // not go%2estring
-
- itabpkg = mkpkg(newstrlit("go.itab"));
- itabpkg->name = "go.itab";
- itabpkg->prefix = "go.itab"; // not go%2eitab
-
- weaktypepkg = mkpkg(newstrlit("go.weak.type"));
- weaktypepkg->name = "go.weak.type";
- weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype
-
- typelinkpkg = mkpkg(newstrlit("go.typelink"));
- typelinkpkg->name = "go.typelink";
- typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
-
- trackpkg = mkpkg(newstrlit("go.track"));
- trackpkg->name = "go.track";
- trackpkg->prefix = "go.track"; // not go%2etrack
-
- typepkg = mkpkg(newstrlit("type"));
- typepkg->name = "type";
-
- goroot = getgoroot();
- goos = getgoos();
-
- nacl = strcmp(goos, "nacl") == 0;
- if(nacl)
- flag_largemodel = 1;
-
- fmtstrinit(&pragcgobuf);
- quotefmtinstall();
-
- outfile = nil;
- flagcount("+", "compiling runtime", &compiling_runtime);
- flagcount("%", "debug non-static initializers", &debug['%']);
- flagcount("A", "for bootstrapping, allow 'any' type", &debug['A']);
- flagcount("B", "disable bounds checking", &debug['B']);
- flagstr("D", "path: set relative path for local imports", &localimport);
- flagcount("E", "debug symbol export", &debug['E']);
- flagfn1("I", "dir: add dir to import search path", addidir);
- flagcount("K", "debug missing line numbers", &debug['K']);
- flagcount("L", "use full (long) path in error messages", &debug['L']);
- flagcount("M", "debug move generation", &debug['M']);
- flagcount("N", "disable optimizations", &debug['N']);
- flagcount("P", "debug peephole optimizer", &debug['P']);
- flagcount("R", "debug register optimizer", &debug['R']);
- flagcount("S", "print assembly listing", &debug['S']);
- flagfn0("V", "print compiler version", doversion);
- flagcount("W", "debug parse tree after type checking", &debug['W']);
- flagstr("asmhdr", "file: write assembly header to named file", &asmhdr);
- flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
- flagstr("d", "list: print debug information about items in list", &debugstr);
- flagcount("e", "no limit on number of errors reported", &debug['e']);
- flagcount("f", "debug stack frames", &debug['f']);
- flagcount("g", "debug code generation", &debug['g']);
- flagcount("h", "halt on error", &debug['h']);
- flagcount("i", "debug line number stack", &debug['i']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagcount("j", "debug runtime-initialized variables", &debug['j']);
- flagcount("l", "disable inlining", &debug['l']);
- flagcount("live", "debug liveness analysis", &debuglive);
- flagcount("m", "print optimization decisions", &debug['m']);
- flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports);
- flagstr("o", "obj: set output file", &outfile);
- flagstr("p", "path: set expected package import path", &myimportpath);
- flagcount("pack", "write package file instead of object file", &writearchive);
- flagcount("r", "debug generated wrappers", &debug['r']);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
- flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
- flagcount("u", "reject unsafe code", &safemode);
- flagcount("v", "increase debug verbosity", &debug['v']);
- flagcount("w", "debug type checking", &debug['w']);
- use_writebarrier = 1;
- flagcount("wb", "enable write barrier", &use_writebarrier);
- flagcount("x", "debug lexer", &debug['x']);
- flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
- if(thearch.thechar == '6')
- flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
-
- flagparse(&argc, &argv, usage);
- ctxt->debugasm = debug['S'];
- ctxt->debugvlog = debug['v'];
-
- if(argc < 1)
- usage();
-
- if(flag_race) {
- racepkg = mkpkg(newstrlit("runtime/race"));
- racepkg->name = "race";
- }
-
- // parse -d argument
- if(debugstr) {
- char *f[100];
- int i, j, nf;
-
- nf = getfields(debugstr, f, nelem(f), 1, ",");
- for(i=0; i<nf; i++) {
- for(j=0; j<nelem(debugtab); j++) {
- if(strcmp(debugtab[j].name, f[i]) == 0) {
- if(debugtab[j].val != nil)
- *debugtab[j].val = 1;
- break;
- }
- }
- if(j >= nelem(debugtab))
- sysfatal("unknown debug information -d '%s'\n", f[i]);
- }
- }
-
- // enable inlining. for now:
- // default: inlining on. (debug['l'] == 1)
- // -l: inlining off (debug['l'] == 0)
- // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
- if(debug['l'] <= 1)
- debug['l'] = 1 - debug['l'];
-
- if(thearch.thechar == '8') {
- p = getgo386();
- if(strcmp(p, "387") == 0)
- use_sse = 0;
- else if(strcmp(p, "sse2") == 0)
- use_sse = 1;
- else
- sysfatal("unsupported setting GO386=%s", p);
- }
-
- fmtinstallgo();
- thearch.betypeinit();
- if(widthptr == 0)
- fatal("betypeinit failed");
-
- lexinit();
- typeinit();
- lexinit1();
- yytinit();
-
- blockgen = 1;
- dclcontext = PEXTERN;
- nerrors = 0;
- lexlineno = 1;
-
- for(i=0; i<argc; i++) {
- infile = argv[i];
- linehist(infile, 0, 0);
-
- curio.infile = infile;
- curio.bin = Bopen(infile, OREAD);
- if(curio.bin == nil) {
- print("open %s: %r\n", infile);
- errorexit();
- }
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.nlsemi = 0;
- curio.eofnl = 0;
- curio.last = 0;
-
- // Skip initial BOM if present.
- if(Bgetrune(curio.bin) != BOM)
- Bungetrune(curio.bin);
-
- block = 1;
- iota = -1000000;
-
- imported_unsafe = 0;
-
- yyparse();
- if(nsyntaxerrors != 0)
- errorexit();
-
- linehist(nil, 0, 0);
- if(curio.bin != nil)
- Bterm(curio.bin);
- }
- testdclstack();
- mkpackage(localpkg->name); // final import not used checks
- lexfini();
-
- typecheckok = 1;
- if(debug['f'])
- frame(1);
-
- // Process top-level declarations in phases.
-
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- defercheckwidth();
- for(l=xtop; l; l=l->next)
- if(l->n->op != ODCL && l->n->op != OAS)
- typecheck(&l->n, Etop);
-
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCL || l->n->op == OAS)
- typecheck(&l->n, Etop);
- resumecheckwidth();
-
- // Phase 3: Type check function bodies.
- for(l=xtop; l; l=l->next) {
- if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
- curfn = l->n;
- decldepth = 1;
- saveerrors();
- typechecklist(l->n->nbody, Etop);
- checkreturn(l->n);
- if(nerrors != 0)
- l->n->nbody = nil; // type errors; do not compile
- }
- }
-
- // Phase 4: Decide how to capture closed variables.
- // This needs to run before escape analysis,
- // because variables captured by value do not escape.
- for(l=xtop; l; l=l->next) {
- if(l->n->op == ODCLFUNC && l->n->closure) {
- curfn = l->n;
- capturevars(l->n);
- }
- }
-
- curfn = nil;
-
- if(nsavederrors+nerrors)
- errorexit();
-
- // Phase 5: Inlining
- if(debug['l'] > 1) {
- // Typecheck imported function bodies if debug['l'] > 1,
- // otherwise lazily when used or re-exported.
- for(l=importlist; l; l=l->next)
- if (l->n->inl) {
- saveerrors();
- typecheckinl(l->n);
- }
-
- if(nsavederrors+nerrors)
- errorexit();
- }
-
- if(debug['l']) {
- // Find functions that can be inlined and clone them before walk expands them.
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- caninl(l->n);
-
- // Expand inlineable calls in all functions
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- inlcalls(l->n);
- }
-
- // Phase 6: Escape analysis.
- // Required for moving heap allocations onto stack,
- // which in turn is required by the closure implementation,
- // which stores the addresses of stack variables into the closure.
- // If the closure does not escape, it needs to be on the stack
- // or else the stack copier will not update it.
- escapes(xtop);
-
- // Escape analysis moved escaped values off stack.
- // Move large values off stack too.
- movelarge(xtop);
-
- // Phase 7: Transform closure bodies to properly reference captured variables.
- // This needs to happen before walk, because closures must be transformed
- // before walk reaches a call of a closure.
- for(l=xtop; l; l=l->next) {
- if(l->n->op == ODCLFUNC && l->n->closure) {
- curfn = l->n;
- transformclosure(l->n);
- }
- }
- curfn = N;
-
- // Phase 8: Compile top level functions.
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- funccompile(l->n);
-
- if(nsavederrors+nerrors == 0)
- fninit(xtop);
-
- // Phase 9: Check external declarations.
- for(l=externdcl; l; l=l->next)
- if(l->n->op == ONAME)
- typecheck(&l->n, Erv);
-
- if(nerrors+nsavederrors)
- errorexit();
-
- dumpobj();
-
- if(asmhdr)
- dumpasmhdr();
-
- if(nerrors+nsavederrors)
- errorexit();
-
- flusherrors();
- exits(0);
- return 0;
-}
-
-void
-saveerrors(void)
-{
- nsavederrors += nerrors;
- nerrors = 0;
-}
-
-static int
-arsize(Biobuf *b, char *name)
-{
- struct ar_hdr a;
-
- if(Bread(b, a.name, sizeof(a.name)) != sizeof(a.name) ||
- Bread(b, a.date, sizeof(a.date)) != sizeof(a.date) ||
- Bread(b, a.uid, sizeof(a.uid)) != sizeof(a.uid) ||
- Bread(b, a.gid, sizeof(a.gid)) != sizeof(a.gid) ||
- Bread(b, a.mode, sizeof(a.mode)) != sizeof(a.mode) ||
- Bread(b, a.size, sizeof(a.size)) != sizeof(a.size) ||
- Bread(b, a.fmag, sizeof(a.fmag)) != sizeof(a.fmag))
- return -1;
-
- if(strncmp(a.name, name, strlen(name)) != 0)
- return -1;
-
- return atoi(a.size);
-}
-
-static int
-skiptopkgdef(Biobuf *b)
-{
- char *p;
- int sz;
-
- /* archive header */
- if((p = Brdline(b, '\n')) == nil)
- return 0;
- if(Blinelen(b) != 8)
- return 0;
- if(memcmp(p, "!<arch>\n", 8) != 0)
- return 0;
- /* symbol table may be first; skip it */
- sz = arsize(b, "__.GOSYMDEF");
- if(sz >= 0)
- Bseek(b, sz, 1);
- else
- Bseek(b, 8, 0);
- /* package export block is next */
- sz = arsize(b, "__.PKGDEF");
- if(sz <= 0)
- return 0;
- return 1;
-}
-
-static void
-addidir(char* dir)
-{
- Idir** pp;
-
- if(dir == nil)
- return;
-
- for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
- ;
- *pp = mal(sizeof(Idir));
- (*pp)->link = nil;
- (*pp)->dir = dir;
-}
-
-// is this path a local name? begins with ./ or ../ or /
-static int
-islocalname(Strlit *name)
-{
- if(name->len >= 1 && name->s[0] == '/')
- return 1;
- if(ctxt->windows && name->len >= 3 &&
- yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
- return 1;
- if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
- return 1;
- if(name->len == 1 && strncmp(name->s, ".", 1) == 0)
- return 1;
- if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
- return 1;
- if(name->len == 2 && strncmp(name->s, "..", 2) == 0)
- return 1;
- return 0;
-}
-
-static int
-findpkg(Strlit *name)
-{
- Idir *p;
- char *q, *suffix, *suffixsep;
-
- if(islocalname(name)) {
- if(safemode || nolocalimports)
- return 0;
- // try .a before .6. important for building libraries:
- // if there is an array.6 in the array.a library,
- // want to find all of array.a, not just array.6.
- snprint(namebuf, sizeof(namebuf), "%Z.a", name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thearch.thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- return 0;
- }
-
- // local imports should be canonicalized already.
- // don't want to see "encoding/../encoding/base64"
- // as different from "encoding/base64".
- q = mal(name->len+1);
- memmove(q, name->s, name->len);
- q[name->len] = '\0';
- cleanname(q);
- if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
- yyerror("non-canonical import path %Z (should be %s)", name, q);
- return 0;
- }
-
- for(p = idirs; p != nil; p = p->link) {
- snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thearch.thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- if(goroot != nil) {
- suffix = "";
- suffixsep = "";
- if(flag_installsuffix != nil) {
- suffixsep = "_";
- suffix = flag_installsuffix;
- } else if(flag_race) {
- suffixsep = "_";
- suffix = "race";
- }
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thearch.thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- return 0;
-}
-
-static void
-fakeimport(void)
-{
- importpkg = mkpkg(newstrlit("fake"));
- cannedimports("fake.6", "$$\n");
-}
-
-void
-importfile(Val *f, int line)
-{
- Biobuf *imp;
- char *file, *p, *q, *tag;
- int32 c;
- int n;
- Strlit *path;
- char *cleanbuf, *prefix;
-
- USED(line);
-
- if(f->ctype != CTSTR) {
- yyerror("import statement not a string");
- fakeimport();
- return;
- }
-
- if(f->u.sval->len == 0) {
- yyerror("import path is empty");
- fakeimport();
- return;
- }
-
- if(isbadimport(f->u.sval)) {
- fakeimport();
- return;
- }
-
- // The package name main is no longer reserved,
- // but we reserve the import path "main" to identify
- // the main package, just as we reserve the import
- // path "math" to identify the standard math package.
- if(strcmp(f->u.sval->s, "main") == 0) {
- yyerror("cannot import \"main\"");
- errorexit();
- }
-
- if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) {
- yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval);
- errorexit();
- }
-
- if(strcmp(f->u.sval->s, "unsafe") == 0) {
- if(safemode) {
- yyerror("cannot import package unsafe");
- errorexit();
- }
- importpkg = mkpkg(f->u.sval);
- cannedimports("unsafe.6", unsafeimport);
- imported_unsafe = 1;
- return;
- }
-
- path = f->u.sval;
- if(islocalname(path)) {
- if(path->s[0] == '/') {
- yyerror("import path cannot be absolute path");
- fakeimport();
- return;
- }
- prefix = ctxt->pathname;
- if(localimport != nil)
- prefix = localimport;
- cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
- strcpy(cleanbuf, prefix);
- strcat(cleanbuf, "/");
- strcat(cleanbuf, path->s);
- cleanname(cleanbuf);
- path = newstrlit(cleanbuf);
-
- if(isbadimport(path)) {
- fakeimport();
- return;
- }
- }
-
- if(!findpkg(path)) {
- yyerror("can't find import: \"%Z\"", f->u.sval);
- errorexit();
- }
- importpkg = mkpkg(path);
-
- // If we already saw that package, feed a dummy statement
- // to the lexer to avoid parsing export data twice.
- if(importpkg->imported) {
- file = strdup(namebuf);
- tag = "";
- if(importpkg->safe) {
- tag = "safe";
- }
- p = smprint("package %s %s\n$$\n", importpkg->name, tag);
- cannedimports(file, p);
- return;
- }
- importpkg->imported = 1;
-
- imp = Bopen(namebuf, OREAD);
- if(imp == nil) {
- yyerror("can't open import: \"%Z\": %r", f->u.sval);
- errorexit();
- }
- file = strdup(namebuf);
-
- n = strlen(namebuf);
- if(n > 2 && namebuf[n-2] == '.' && namebuf[n-1] == 'a') {
- if(!skiptopkgdef(imp)) {
- yyerror("import %s: not a package file", file);
- errorexit();
- }
- }
-
- // check object header
- p = Brdstr(imp, '\n', 1);
- if(strcmp(p, "empty archive") != 0) {
- if(strncmp(p, "go object ", 10) != 0) {
- yyerror("import %s: not a go object file", file);
- errorexit();
- }
- q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
- if(strcmp(p+10, q) != 0) {
- yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
- errorexit();
- }
- free(q);
- }
-
- // assume files move (get installed)
- // so don't record the full path.
- linehist(file + n - path->len - 2, -1, 1); // acts as #pragma lib
-
- /*
- * position the input right
- * after $$ and return
- */
- pushedio = curio;
- curio.bin = imp;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.nlsemi = 0;
- typecheckok = 1;
-
- for(;;) {
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- return;
- }
- yyerror("no import in \"%Z\"", f->u.sval);
- unimportfile();
-}
-
-void
-unimportfile(void)
-{
- if(curio.bin != nil) {
- Bterm(curio.bin);
- curio.bin = nil;
- } else
- lexlineno--; // re correct sys.6 line number
-
- curio = pushedio;
- pushedio.bin = nil;
- incannedimport = 0;
- typecheckok = 0;
-}
-
-void
-cannedimports(char *file, char *cp)
-{
- lexlineno++; // if sys.6 is included on line 1,
-
- pushedio = curio;
- curio.bin = nil;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.cp = cp;
- curio.nlsemi = 0;
- curio.importsafe = 0;
-
- typecheckok = 1;
- incannedimport = 1;
-}
-
-static int
-isfrog(int c)
-{
- // complain about possibly invisible control characters
- if(c < ' ') {
- return !yy_isspace(c); // exclude good white space
- }
- if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
- return 1;
- return 0;
-}
-
-typedef struct Loophack Loophack;
-struct Loophack {
- int v;
- Loophack *next;
-};
-
-static int32
-_yylex(void)
-{
- int c, c1, clen, escflag, ncp;
- vlong v;
- char *cp, *ep;
- Rune rune;
- Sym *s;
- static Loophack *lstk;
- Loophack *h;
-
- prevlineno = lineno;
-
-l0:
- c = getc();
- if(yy_isspace(c)) {
- if(c == '\n' && curio.nlsemi) {
- ungetc(c);
- DBG("lex: implicit semi\n");
- return ';';
- }
- goto l0;
- }
-
- lineno = lexlineno; /* start of token */
-
- if(c >= Runeself) {
- /* all multibyte runes are alpha */
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isalpha(c)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isdigit(c))
- goto tnum;
-
- switch(c) {
- case EOF:
- lineno = prevlineno;
- ungetc(EOF);
- return -1;
-
- case '_':
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
-
- case '.':
- c1 = getc();
- if(yy_isdigit(c1)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- *cp++ = c;
- c = c1;
- goto casedot;
- }
- if(c1 == '.') {
- c1 = getc();
- if(c1 == '.') {
- c = LDDD;
- goto lx;
- }
- ungetc(c1);
- c1 = '.';
- }
- break;
-
- case '"':
- /* "..." */
- strcpy(lexbuf, "\"<string>\"");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- if(escchar('"', &escflag, &v))
- break;
- if(v < Runeself || escflag) {
- cp[clen++] = v;
- } else {
- rune = v;
- c = runelen(rune);
- runetochar(cp+clen, &rune);
- clen += c;
- }
- }
- goto strlit;
-
- case '`':
- /* `...` */
- strcpy(lexbuf, "`<string>`");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- c = getr();
- if(c == '\r')
- continue;
- if(c == EOF) {
- yyerror("eof in string");
- break;
- }
- if(c == '`')
- break;
- rune = c;
- clen += runetochar(cp+clen, &rune);
- }
- goto strlit;
-
- case '\'':
- /* '.' */
- if(escchar('\'', &escflag, &v)) {
- yyerror("empty character literal or unescaped ' in character literal");
- v = '\'';
- }
- if(!escchar('\'', &escflag, &v)) {
- yyerror("missing '");
- ungetc(v);
- }
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpmovecfix(yylval.val.u.xval, v);
- yylval.val.ctype = CTRUNE;
- DBG("lex: codepoint literal\n");
- strcpy(litbuf, "string literal");
- return LLITERAL;
-
- case '/':
- c1 = getc();
- if(c1 == '*') {
- int nl;
-
- nl = 0;
- for(;;) {
- c = getr();
- if(c == '\n')
- nl = 1;
- while(c == '*') {
- c = getr();
- if(c == '/') {
- if(nl)
- ungetc('\n');
- goto l0;
- }
- if(c == '\n')
- nl = 1;
- }
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '/') {
- c = getlinepragma();
- for(;;) {
- if(c == '\n' || c == EOF) {
- ungetc(c);
- goto l0;
- }
- c = getr();
- }
- }
- if(c1 == '=') {
- c = ODIV;
- goto asop;
- }
- break;
-
- case ':':
- c1 = getc();
- if(c1 == '=') {
- c = LCOLAS;
- yylval.i = lexlineno;
- goto lx;
- }
- break;
-
- case '*':
- c1 = getc();
- if(c1 == '=') {
- c = OMUL;
- goto asop;
- }
- break;
-
- case '%':
- c1 = getc();
- if(c1 == '=') {
- c = OMOD;
- goto asop;
- }
- break;
-
- case '+':
- c1 = getc();
- if(c1 == '+') {
- c = LINC;
- goto lx;
- }
- if(c1 == '=') {
- c = OADD;
- goto asop;
- }
- break;
-
- case '-':
- c1 = getc();
- if(c1 == '-') {
- c = LDEC;
- goto lx;
- }
- if(c1 == '=') {
- c = OSUB;
- goto asop;
- }
- break;
-
- case '>':
- c1 = getc();
- if(c1 == '>') {
- c = LRSH;
- c1 = getc();
- if(c1 == '=') {
- c = ORSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LGE;
- goto lx;
- }
- c = LGT;
- break;
-
- case '<':
- c1 = getc();
- if(c1 == '<') {
- c = LLSH;
- c1 = getc();
- if(c1 == '=') {
- c = OLSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LLE;
- goto lx;
- }
- if(c1 == '-') {
- c = LCOMM;
- goto lx;
- }
- c = LLT;
- break;
-
- case '=':
- c1 = getc();
- if(c1 == '=') {
- c = LEQ;
- goto lx;
- }
- break;
-
- case '!':
- c1 = getc();
- if(c1 == '=') {
- c = LNE;
- goto lx;
- }
- break;
-
- case '&':
- c1 = getc();
- if(c1 == '&') {
- c = LANDAND;
- goto lx;
- }
- if(c1 == '^') {
- c = LANDNOT;
- c1 = getc();
- if(c1 == '=') {
- c = OANDNOT;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = OAND;
- goto asop;
- }
- break;
-
- case '|':
- c1 = getc();
- if(c1 == '|') {
- c = LOROR;
- goto lx;
- }
- if(c1 == '=') {
- c = OOR;
- goto asop;
- }
- break;
-
- case '^':
- c1 = getc();
- if(c1 == '=') {
- c = OXOR;
- goto asop;
- }
- break;
-
- /*
- * clumsy dance:
- * to implement rule that disallows
- * if T{1}[0] { ... }
- * but allows
- * if (T{1}[0]) { ... }
- * the block bodies for if/for/switch/select
- * begin with an LBODY token, not '{'.
- *
- * when we see the keyword, the next
- * non-parenthesized '{' becomes an LBODY.
- * loophack is normally 0.
- * a keyword makes it go up to 1.
- * parens push loophack onto a stack and go back to 0.
- * a '{' with loophack == 1 becomes LBODY and disables loophack.
- *
- * i said it was clumsy.
- */
- case '(':
- case '[':
- if(loophack || lstk != nil) {
- h = malloc(sizeof *h);
- if(h == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- h->v = loophack;
- h->next = lstk;
- lstk = h;
- loophack = 0;
- }
- goto lx;
- case ')':
- case ']':
- if(lstk != nil) {
- h = lstk;
- loophack = h->v;
- lstk = h->next;
- free(h);
- }
- goto lx;
- case '{':
- if(loophack == 1) {
- DBG("%L lex: LBODY\n", lexlineno);
- loophack = 0;
- return LBODY;
- }
- goto lx;
-
- default:
- goto lx;
- }
- ungetc(c1);
-
-lx:
- if(c > 0xff)
- DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
- else
- DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
- if(isfrog(c)) {
- yyerror("illegal character 0x%ux", c);
- goto l0;
- }
- if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
- yyerror("%s: unexpected %c", "syntax error", c);
- goto l0;
- }
- return c;
-
-asop:
- yylval.i = c; // rathole to hold which asop
- DBG("lex: TOKEN ASOP %c\n", c);
- return LASOP;
-
-talph:
- /*
- * cp is set to lexbuf and some
- * prefix has been stored
- */
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(c >= Runeself) {
- ungetc(c);
- rune = getr();
- // 0xb7 · is used for internal names
- if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
- yyerror("invalid identifier character U+%04x", rune);
- cp += runetochar(cp, &rune);
- } else if(!yy_isalnum(c) && c != '_')
- break;
- else
- *cp++ = c;
- c = getc();
- }
- *cp = 0;
- ungetc(c);
-
- s = lookup(lexbuf);
- switch(s->lexical) {
- case LIGNORE:
- goto l0;
-
- case LFOR:
- case LIF:
- case LSWITCH:
- case LSELECT:
- loophack = 1; // see comment about loophack above
- break;
- }
-
- DBG("lex: %S %s\n", s, lexname(s->lexical));
- yylval.sym = s;
- return s->lexical;
-
-tnum:
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- if(c != '0') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- goto dc;
- }
- }
- *cp++ = c;
- c = getc();
- if(c == 'x' || c == 'X') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- if(c >= 'a' && c <= 'f')
- continue;
- if(c >= 'A' && c <= 'F')
- continue;
- if(cp == lexbuf+2)
- yyerror("malformed hex constant");
- if(c == 'p')
- goto caseep;
- goto ncu;
- }
- }
-
- if(c == 'p') // 0p begins floating point zero
- goto caseep;
-
- c1 = 0;
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(!yy_isdigit(c))
- break;
- if(c < '0' || c > '7')
- c1 = 1; // not octal
- *cp++ = c;
- c = getc();
- }
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto caseep;
- if(c == 'i')
- goto casei;
- if(c1)
- yyerror("malformed octal constant");
- goto ncu;
-
-dc:
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E' || c == 'p' || c == 'P')
- goto caseep;
- if(c == 'i')
- goto casei;
-
-ncu:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpatofix(yylval.val.u.xval, lexbuf);
- if(yylval.val.u.xval->ovf) {
- yyerror("overflow in constant");
- mpmovecfix(yylval.val.u.xval, 0);
- }
- yylval.val.ctype = CTINT;
- DBG("lex: integer literal\n");
- strcpy(litbuf, "literal ");
- strcat(litbuf, lexbuf);
- return LLITERAL;
-
-casedot:
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(!yy_isdigit(c))
- break;
- }
- if(c == 'i')
- goto casei;
- if(c != 'e' && c != 'E')
- goto caseout;
-
-caseep:
- *cp++ = c;
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casei:
- // imaginary constant
- *cp = 0;
- yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- mpatoflt(&yylval.val.u.cval->imag, lexbuf);
- if(yylval.val.u.cval->imag.val.ovf) {
- yyerror("overflow in imaginary constant");
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- }
- yylval.val.ctype = CTCPLX;
- DBG("lex: imaginary literal\n");
- strcpy(litbuf, "literal ");
- strcat(litbuf, lexbuf);
- return LLITERAL;
-
-caseout:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
- mpatoflt(yylval.val.u.fval, lexbuf);
- if(yylval.val.u.fval->val.ovf) {
- yyerror("overflow in float constant");
- mpmovecflt(yylval.val.u.fval, 0.0);
- }
- yylval.val.ctype = CTFLT;
- DBG("lex: floating literal\n");
- strcpy(litbuf, "literal ");
- strcat(litbuf, lexbuf);
- return LLITERAL;
-
-strlit:
- *(int32*)cp = clen-sizeof(int32); // length
- do {
- cp[clen++] = 0;
- } while(clen & MAXALIGN);
- yylval.val.u.sval = (Strlit*)cp;
- yylval.val.ctype = CTSTR;
- DBG("lex: string literal\n");
- strcpy(litbuf, "string literal");
- return LLITERAL;
-}
-
-static void pragcgo(char*);
-
-static int
-more(char **pp)
-{
- char *p;
-
- p = *pp;
- while(yy_isspace(*p))
- p++;
- *pp = p;
- return *p != '\0';
-}
-
-/*
- * read and interpret syntax that looks like
- * //line parse.y:15
- * as a discontinuity in sequential line numbers.
- * the next line of input comes from parse.y:15
- */
-static int
-getlinepragma(void)
-{
- int i, c, n;
- char *cp, *ep, *linep;
- Hist *h;
-
- c = getr();
- if(c == 'g')
- goto go;
- if(c != 'l')
- goto out;
- for(i=1; i<5; i++) {
- c = getr();
- if(c != "line "[i])
- goto out;
- }
-
- cp = lexbuf;
- ep = lexbuf+sizeof(lexbuf)-5;
- linep = nil;
- for(;;) {
- c = getr();
- if(c == EOF)
- goto out;
- if(c == '\n')
- break;
- if(c == ' ')
- continue;
- if(c == ':')
- linep = cp;
- if(cp < ep)
- *cp++ = c;
- }
- *cp = 0;
-
- if(linep == nil || linep >= ep)
- goto out;
- *linep++ = '\0';
- n = 0;
- for(cp=linep; *cp; cp++) {
- if(*cp < '0' || *cp > '9')
- goto out;
- n = n*10 + *cp - '0';
- if(n > 1e8) {
- yyerror("line number out of range");
- errorexit();
- }
- }
- if(n <= 0)
- goto out;
-
- // try to avoid allocating file name over and over
- for(h=ctxt->hist; h!=nil; h=h->link) {
- if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
- linehist(h->name, n, 0);
- goto out;
- }
- }
- linehist(strdup(lexbuf), n, 0);
- goto out;
-
-go:
- cp = lexbuf;
- ep = lexbuf+sizeof(lexbuf)-5;
- *cp++ = 'g'; // already read
- for(;;) {
- c = getr();
- if(c == EOF || c >= Runeself)
- goto out;
- if(c == '\n')
- break;
- if(cp < ep)
- *cp++ = c;
- }
- *cp = 0;
-
- if(strncmp(lexbuf, "go:cgo_", 7) == 0)
- pragcgo(lexbuf);
-
- ep = strchr(lexbuf, ' ');
- if(ep != nil)
- *ep = 0;
-
- if(strcmp(lexbuf, "go:linkname") == 0) {
- if(!imported_unsafe)
- yyerror("//go:linkname only allowed in Go files that import \"unsafe\"");
- if(ep == nil) {
- yyerror("usage: //go:linkname localname linkname");
- goto out;
- }
- cp = ep+1;
- while(yy_isspace(*cp))
- cp++;
- ep = strchr(cp, ' ');
- if(ep == nil) {
- yyerror("usage: //go:linkname localname linkname");
- goto out;
- }
- *ep++ = 0;
- while(yy_isspace(*ep))
- ep++;
- if(*ep == 0) {
- yyerror("usage: //go:linkname localname linkname");
- goto out;
- }
- lookup(cp)->linkname = strdup(ep);
- goto out;
- }
-
- if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
- nointerface = 1;
- goto out;
- }
- if(strcmp(lexbuf, "go:noescape") == 0) {
- noescape = 1;
- goto out;
- }
- if(strcmp(lexbuf, "go:nosplit") == 0) {
- nosplit = 1;
- goto out;
- }
- if(strcmp(lexbuf, "go:nowritebarrier") == 0) {
- if(!compiling_runtime)
- yyerror("//go:nowritebarrier only allowed in runtime");
- nowritebarrier = 1;
- goto out;
- }
-
-out:
- return c;
-}
-
-static char*
-getimpsym(char **pp)
-{
- char *p, *start;
-
- more(pp); // skip spaces
-
- p = *pp;
- if(*p == '\0' || *p == '"')
- return nil;
-
- start = p;
- while(*p != '\0' && !yy_isspace(*p) && *p != '"')
- p++;
- if(*p != '\0')
- *p++ = '\0';
-
- *pp = p;
- return start;
-}
-
-static char*
-getquoted(char **pp)
-{
- char *p, *start;
-
- more(pp); // skip spaces
-
- p = *pp;
- if(*p != '"')
- return nil;
- p++;
-
- start = p;
- while(*p != '"') {
- if(*p == '\0')
- return nil;
- p++;
- }
- *p++ = '\0';
- *pp = p;
- return start;
-}
-
-// Copied nearly verbatim from the C compiler's #pragma parser.
-// TODO: Rewrite more cleanly once the compiler is written in Go.
-static void
-pragcgo(char *text)
-{
- char *local, *remote, *p, *q, *verb;
-
- for(q=text; *q != '\0' && *q != ' '; q++)
- ;
- if(*q == ' ')
- *q++ = '\0';
-
- verb = text+3; // skip "go:"
-
- if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
- p = getquoted(&q);
- if(p == nil)
- goto err1;
- fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
- goto out;
-
- err1:
- yyerror("usage: //go:cgo_dynamic_linker \"path\"");
- goto out;
- }
-
- if(strcmp(verb, "dynexport") == 0)
- verb = "cgo_export_dynamic";
- if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
- local = getimpsym(&q);
- if(local == nil)
- goto err2;
- if(!more(&q)) {
- fmtprint(&pragcgobuf, "%s %q\n", verb, local);
- goto out;
- }
- remote = getimpsym(&q);
- if(remote == nil)
- goto err2;
- fmtprint(&pragcgobuf, "%s %q %q\n", verb, local, remote);
- goto out;
-
- err2:
- yyerror("usage: //go:%s local [remote]", verb);
- goto out;
- }
-
- if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
- local = getimpsym(&q);
- if(local == nil)
- goto err3;
- if(!more(&q)) {
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local);
- goto out;
- }
- remote = getimpsym(&q);
- if(remote == nil)
- goto err3;
- if(!more(&q)) {
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local, remote);
- goto out;
- }
- p = getquoted(&q);
- if(p == nil)
- goto err3;
- fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local, remote, p);
- goto out;
-
- err3:
- yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]");
- goto out;
- }
-
- if(strcmp(verb, "cgo_import_static") == 0) {
- local = getimpsym(&q);
- if(local == nil || more(&q))
- goto err4;
- fmtprint(&pragcgobuf, "cgo_import_static %q\n", local);
- goto out;
-
- err4:
- yyerror("usage: //go:cgo_import_static local");
- goto out;
- }
-
- if(strcmp(verb, "cgo_ldflag") == 0) {
- p = getquoted(&q);
- if(p == nil)
- goto err5;
- fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
- goto out;
-
- err5:
- yyerror("usage: //go:cgo_ldflag \"arg\"");
- goto out;
- }
-
-out:;
-}
-
-int32
-yylex(void)
-{
- int lx;
-
- lx = _yylex();
-
- if(curio.nlsemi && lx == EOF) {
- // Treat EOF as "end of line" for the purposes
- // of inserting a semicolon.
- lx = ';';
- }
-
- switch(lx) {
- case LNAME:
- case LLITERAL:
- case LBREAK:
- case LCONTINUE:
- case LFALL:
- case LRETURN:
- case LINC:
- case LDEC:
- case ')':
- case '}':
- case ']':
- curio.nlsemi = 1;
- break;
- default:
- curio.nlsemi = 0;
- break;
- }
-
- // Track last two tokens returned by yylex.
- yyprev = yylast;
- yylast = lx;
- return lx;
-}
-
-static int
-getc(void)
-{
- int c, c1, c2;
-
- c = curio.peekc;
- if(c != 0) {
- curio.peekc = curio.peekc1;
- curio.peekc1 = 0;
- goto check;
- }
-
- if(curio.bin == nil) {
- c = *curio.cp & 0xff;
- if(c != 0)
- curio.cp++;
- } else {
- loop:
- c = BGETC(curio.bin);
- if(c == 0xef) {
- c1 = BGETC(curio.bin);
- c2 = BGETC(curio.bin);
- if(c1 == 0xbb && c2 == 0xbf) {
- yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file");
- goto loop;
- }
- Bungetc(curio.bin);
- Bungetc(curio.bin);
- }
- }
-
-check:
- switch(c) {
- case 0:
- if(curio.bin != nil) {
- yyerror("illegal NUL byte");
- break;
- }
- case EOF:
- // insert \n at EOF
- if(curio.eofnl || curio.last == '\n')
- return EOF;
- curio.eofnl = 1;
- c = '\n';
- case '\n':
- if(pushedio.bin == nil)
- lexlineno++;
- break;
- }
- curio.last = c;
- return c;
-}
-
-static void
-ungetc(int c)
-{
- curio.peekc1 = curio.peekc;
- curio.peekc = c;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno--;
-}
-
-static int32
-getr(void)
-{
- int c, i;
- char str[UTFmax+1];
- Rune rune;
-
- c = getc();
- if(c < Runeself)
- return c;
- i = 0;
- str[i++] = c;
-
-loop:
- c = getc();
- str[i++] = c;
- if(!fullrune(str, i))
- goto loop;
- c = chartorune(&rune, str);
- if(rune == Runeerror && c == 1) {
- lineno = lexlineno;
- yyerror("illegal UTF-8 sequence");
- flusherrors();
- print("\t");
- for(c=0; c<i; c++)
- print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
- print("\n");
- }
- return rune;
-}
-
-static int
-escchar(int e, int *escflg, vlong *val)
-{
- int i, u, c;
- vlong l;
-
- *escflg = 0;
-
- c = getr();
- switch(c) {
- case EOF:
- yyerror("eof in string");
- return 1;
- case '\n':
- yyerror("newline in string");
- return 1;
- case '\\':
- break;
- default:
- if(c == e)
- return 1;
- *val = c;
- return 0;
- }
-
- u = 0;
- c = getr();
- switch(c) {
- case 'x':
- *escflg = 1; // it's a byte
- i = 2;
- goto hex;
-
- case 'u':
- i = 4;
- u = 1;
- goto hex;
-
- case 'U':
- i = 8;
- u = 1;
- goto hex;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- *escflg = 1; // it's a byte
- goto oct;
-
- case 'a': c = '\a'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\\': c = '\\'; break;
-
- default:
- if(c != e)
- yyerror("unknown escape sequence: %c", c);
- }
- *val = c;
- return 0;
-
-hex:
- l = 0;
- for(; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '9') {
- l = l*16 + c-'0';
- continue;
- }
- if(c >= 'a' && c <= 'f') {
- l = l*16 + c-'a' + 10;
- continue;
- }
- if(c >= 'A' && c <= 'F') {
- l = l*16 + c-'A' + 10;
- continue;
- }
- yyerror("non-hex character in escape sequence: %c", c);
- ungetc(c);
- break;
- }
- if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
- yyerror("invalid Unicode code point in escape sequence: %#llx", l);
- l = Runeerror;
- }
- *val = l;
- return 0;
-
-oct:
- l = c - '0';
- for(i=2; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- continue;
- }
- yyerror("non-octal character in escape sequence: %c", c);
- ungetc(c);
- }
- if(l > 255)
- yyerror("octal escape value > 255: %d", l);
-
- *val = l;
- return 0;
-}
-
-static struct
-{
- char* name;
- int lexical;
- int etype;
- int op;
-} syms[] =
-{
-/* name lexical etype op
- */
-/* basic types */
- {"int8", LNAME, TINT8, OXXX},
- {"int16", LNAME, TINT16, OXXX},
- {"int32", LNAME, TINT32, OXXX},
- {"int64", LNAME, TINT64, OXXX},
-
- {"uint8", LNAME, TUINT8, OXXX},
- {"uint16", LNAME, TUINT16, OXXX},
- {"uint32", LNAME, TUINT32, OXXX},
- {"uint64", LNAME, TUINT64, OXXX},
-
- {"float32", LNAME, TFLOAT32, OXXX},
- {"float64", LNAME, TFLOAT64, OXXX},
-
- {"complex64", LNAME, TCOMPLEX64, OXXX},
- {"complex128", LNAME, TCOMPLEX128, OXXX},
-
- {"bool", LNAME, TBOOL, OXXX},
- {"string", LNAME, TSTRING, OXXX},
-
- {"any", LNAME, TANY, OXXX},
-
- {"break", LBREAK, Txxx, OXXX},
- {"case", LCASE, Txxx, OXXX},
- {"chan", LCHAN, Txxx, OXXX},
- {"const", LCONST, Txxx, OXXX},
- {"continue", LCONTINUE, Txxx, OXXX},
- {"default", LDEFAULT, Txxx, OXXX},
- {"else", LELSE, Txxx, OXXX},
- {"defer", LDEFER, Txxx, OXXX},
- {"fallthrough", LFALL, Txxx, OXXX},
- {"for", LFOR, Txxx, OXXX},
- {"func", LFUNC, Txxx, OXXX},
- {"go", LGO, Txxx, OXXX},
- {"goto", LGOTO, Txxx, OXXX},
- {"if", LIF, Txxx, OXXX},
- {"import", LIMPORT, Txxx, OXXX},
- {"interface", LINTERFACE, Txxx, OXXX},
- {"map", LMAP, Txxx, OXXX},
- {"package", LPACKAGE, Txxx, OXXX},
- {"range", LRANGE, Txxx, OXXX},
- {"return", LRETURN, Txxx, OXXX},
- {"select", LSELECT, Txxx, OXXX},
- {"struct", LSTRUCT, Txxx, OXXX},
- {"switch", LSWITCH, Txxx, OXXX},
- {"type", LTYPE, Txxx, OXXX},
- {"var", LVAR, Txxx, OXXX},
-
- {"append", LNAME, Txxx, OAPPEND},
- {"cap", LNAME, Txxx, OCAP},
- {"close", LNAME, Txxx, OCLOSE},
- {"complex", LNAME, Txxx, OCOMPLEX},
- {"copy", LNAME, Txxx, OCOPY},
- {"delete", LNAME, Txxx, ODELETE},
- {"imag", LNAME, Txxx, OIMAG},
- {"len", LNAME, Txxx, OLEN},
- {"make", LNAME, Txxx, OMAKE},
- {"new", LNAME, Txxx, ONEW},
- {"panic", LNAME, Txxx, OPANIC},
- {"print", LNAME, Txxx, OPRINT},
- {"println", LNAME, Txxx, OPRINTN},
- {"real", LNAME, Txxx, OREAL},
- {"recover", LNAME, Txxx, ORECOVER},
-
- {"notwithstanding", LIGNORE, Txxx, OXXX},
- {"thetruthofthematter", LIGNORE, Txxx, OXXX},
- {"despiteallobjections", LIGNORE, Txxx, OXXX},
- {"whereas", LIGNORE, Txxx, OXXX},
- {"insofaras", LIGNORE, Txxx, OXXX},
-};
-
-static void
-lexinit(void)
-{
- int i, lex;
- Sym *s, *s1;
- Type *t;
- int etype;
- Val v;
-
- /*
- * initialize basic types array
- * initialize known symbols
- */
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx) {
- if(etype < 0 || etype >= nelem(types))
- fatal("lexinit: %s bad etype", s->name);
- s1 = pkglookup(syms[i].name, builtinpkg);
- t = types[etype];
- if(t == T) {
- t = typ(etype);
- t->sym = s1;
-
- if(etype != TANY && etype != TSTRING)
- dowidth(t);
- types[etype] = t;
- }
- s1->lexical = LNAME;
- s1->def = typenod(t);
- continue;
- }
-
- etype = syms[i].op;
- if(etype != OXXX) {
- s1 = pkglookup(syms[i].name, builtinpkg);
- s1->lexical = LNAME;
- s1->def = nod(ONAME, N, N);
- s1->def->sym = s1;
- s1->def->etype = etype;
- s1->def->builtin = 1;
- }
- }
-
- // logically, the type of a string literal.
- // types[TSTRING] is the named type string
- // (the type of x in var x string or var x = "hello").
- // this is the ideal form
- // (the type of x in const x = "hello").
- idealstring = typ(TSTRING);
- idealbool = typ(TBOOL);
-
- s = pkglookup("true", builtinpkg);
- s->def = nodbool(1);
- s->def->sym = lookup("true");
- s->def->type = idealbool;
-
- s = pkglookup("false", builtinpkg);
- s->def = nodbool(0);
- s->def->sym = lookup("false");
- s->def->type = idealbool;
-
- s = lookup("_");
- s->block = -100;
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- types[TBLANK] = typ(TBLANK);
- s->def->type = types[TBLANK];
- nblank = s->def;
-
- s = pkglookup("_", builtinpkg);
- s->block = -100;
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- types[TBLANK] = typ(TBLANK);
- s->def->type = types[TBLANK];
-
- types[TNIL] = typ(TNIL);
- s = pkglookup("nil", builtinpkg);
- v.ctype = CTNIL;
- s->def = nodlit(v);
- s->def->sym = s;
-}
-
-static void
-lexinit1(void)
-{
- Sym *s, *s1;
- Type *t, *f, *rcvr, *in, *out;
-
- // t = interface { Error() string }
- rcvr = typ(TSTRUCT);
- rcvr->type = typ(TFIELD);
- rcvr->type->type = ptrto(typ(TSTRUCT));
- rcvr->funarg = 1;
- in = typ(TSTRUCT);
- in->funarg = 1;
- out = typ(TSTRUCT);
- out->type = typ(TFIELD);
- out->type->type = types[TSTRING];
- out->funarg = 1;
- f = typ(TFUNC);
- *getthis(f) = rcvr;
- *getoutarg(f) = out;
- *getinarg(f) = in;
- f->thistuple = 1;
- f->intuple = 0;
- f->outnamed = 0;
- f->outtuple = 1;
- t = typ(TINTER);
- t->type = typ(TFIELD);
- t->type->sym = lookup("Error");
- t->type->type = f;
-
- // error type
- s = lookup("error");
- s->lexical = LNAME;
- s1 = pkglookup("error", builtinpkg);
- errortype = t;
- errortype->sym = s1;
- s1->lexical = LNAME;
- s1->def = typenod(errortype);
-
- // byte alias
- s = lookup("byte");
- s->lexical = LNAME;
- s1 = pkglookup("byte", builtinpkg);
- bytetype = typ(TUINT8);
- bytetype->sym = s1;
- s1->lexical = LNAME;
- s1->def = typenod(bytetype);
-
- // rune alias
- s = lookup("rune");
- s->lexical = LNAME;
- s1 = pkglookup("rune", builtinpkg);
- runetype = typ(TINT32);
- runetype->sym = s1;
- s1->lexical = LNAME;
- s1->def = typenod(runetype);
-}
-
-static void
-lexfini(void)
-{
- Sym *s;
- int lex, etype, i;
- Val v;
-
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- if(lex != LNAME)
- continue;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) {
- s->def = typenod(types[etype]);
- s->origpkg = builtinpkg;
- }
-
- etype = syms[i].op;
- if(etype != OXXX && s->def == N) {
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- s->def->etype = etype;
- s->def->builtin = 1;
- s->origpkg = builtinpkg;
- }
- }
-
- // backend-specific builtin types (e.g. int).
- for(i=0; thearch.typedefs[i].name; i++) {
- s = lookup(thearch.typedefs[i].name);
- if(s->def == N) {
- s->def = typenod(types[thearch.typedefs[i].etype]);
- s->origpkg = builtinpkg;
- }
- }
-
- // there's only so much table-driven we can handle.
- // these are special cases.
- s = lookup("byte");
- if(s->def == N) {
- s->def = typenod(bytetype);
- s->origpkg = builtinpkg;
- }
-
- s = lookup("error");
- if(s->def == N) {
- s->def = typenod(errortype);
- s->origpkg = builtinpkg;
- }
-
- s = lookup("rune");
- if(s->def == N) {
- s->def = typenod(runetype);
- s->origpkg = builtinpkg;
- }
-
- s = lookup("nil");
- if(s->def == N) {
- v.ctype = CTNIL;
- s->def = nodlit(v);
- s->def->sym = s;
- s->origpkg = builtinpkg;
- }
-
- s = lookup("iota");
- if(s->def == N) {
- s->def = nod(OIOTA, N, N);
- s->def->sym = s;
- s->origpkg = builtinpkg;
- }
-
- s = lookup("true");
- if(s->def == N) {
- s->def = nodbool(1);
- s->def->sym = s;
- s->origpkg = builtinpkg;
- }
-
- s = lookup("false");
- if(s->def == N) {
- s->def = nodbool(0);
- s->def->sym = s;
- s->origpkg = builtinpkg;
- }
-
- nodfp = nod(ONAME, N, N);
- nodfp->type = types[TINT32];
- nodfp->xoffset = 0;
- nodfp->class = PPARAM;
- nodfp->sym = lookup(".fp");
-}
-
-struct
-{
- int lex;
- char* name;
-} lexn[] =
-{
- {LANDAND, "ANDAND"},
- {LANDNOT, "ANDNOT"},
- {LASOP, "ASOP"},
- {LBREAK, "BREAK"},
- {LCASE, "CASE"},
- {LCHAN, "CHAN"},
- {LCOLAS, "COLAS"},
- {LCOMM, "<-"},
- {LCONST, "CONST"},
- {LCONTINUE, "CONTINUE"},
- {LDDD, "..."},
- {LDEC, "DEC"},
- {LDEFAULT, "DEFAULT"},
- {LDEFER, "DEFER"},
- {LELSE, "ELSE"},
- {LEQ, "EQ"},
- {LFALL, "FALL"},
- {LFOR, "FOR"},
- {LFUNC, "FUNC"},
- {LGE, "GE"},
- {LGO, "GO"},
- {LGOTO, "GOTO"},
- {LGT, "GT"},
- {LIF, "IF"},
- {LIMPORT, "IMPORT"},
- {LINC, "INC"},
- {LINTERFACE, "INTERFACE"},
- {LLE, "LE"},
- {LLITERAL, "LITERAL"},
- {LLSH, "LSH"},
- {LLT, "LT"},
- {LMAP, "MAP"},
- {LNAME, "NAME"},
- {LNE, "NE"},
- {LOROR, "OROR"},
- {LPACKAGE, "PACKAGE"},
- {LRANGE, "RANGE"},
- {LRETURN, "RETURN"},
- {LRSH, "RSH"},
- {LSELECT, "SELECT"},
- {LSTRUCT, "STRUCT"},
- {LSWITCH, "SWITCH"},
- {LTYPE, "TYPE"},
- {LVAR, "VAR"},
-};
-
-char*
-lexname(int lex)
-{
- int i;
- static char buf[100];
-
- for(i=0; i<nelem(lexn); i++)
- if(lexn[i].lex == lex)
- return lexn[i].name;
- snprint(buf, sizeof(buf), "LEX-%d", lex);
- return buf;
-}
-
-struct
-{
- char *have;
- char *want;
-} yytfix[] =
-{
- {"$end", "EOF"},
- {"LLITERAL", "literal"},
- {"LASOP", "op="},
- {"LBREAK", "break"},
- {"LCASE", "case"},
- {"LCHAN", "chan"},
- {"LCOLAS", ":="},
- {"LCONST", "const"},
- {"LCONTINUE", "continue"},
- {"LDDD", "..."},
- {"LDEFAULT", "default"},
- {"LDEFER", "defer"},
- {"LELSE", "else"},
- {"LFALL", "fallthrough"},
- {"LFOR", "for"},
- {"LFUNC", "func"},
- {"LGO", "go"},
- {"LGOTO", "goto"},
- {"LIF", "if"},
- {"LIMPORT", "import"},
- {"LINTERFACE", "interface"},
- {"LMAP", "map"},
- {"LNAME", "name"},
- {"LPACKAGE", "package"},
- {"LRANGE", "range"},
- {"LRETURN", "return"},
- {"LSELECT", "select"},
- {"LSTRUCT", "struct"},
- {"LSWITCH", "switch"},
- {"LTYPE", "type"},
- {"LVAR", "var"},
- {"LANDAND", "&&"},
- {"LANDNOT", "&^"},
- {"LBODY", "{"},
- {"LCOMM", "<-"},
- {"LDEC", "--"},
- {"LINC", "++"},
- {"LEQ", "=="},
- {"LGE", ">="},
- {"LGT", ">"},
- {"LLE", "<="},
- {"LLT", "<"},
- {"LLSH", "<<"},
- {"LRSH", ">>"},
- {"LOROR", "||"},
- {"LNE", "!="},
-
- // spell out to avoid confusion with punctuation in error messages
- {"';'", "semicolon or newline"},
- {"','", "comma"},
-};
-
-static void
-yytinit(void)
-{
- int i, j;
- extern char *yytname[];
- char *s, *t;
-
- for(i=0; yytname[i] != nil; i++) {
- s = yytname[i];
-
- if(strcmp(s, "LLITERAL") == 0) {
- strcpy(litbuf, "literal");
- yytname[i] = litbuf;
- goto loop;
- }
-
- // apply yytfix if possible
- for(j=0; j<nelem(yytfix); j++) {
- if(strcmp(s, yytfix[j].have) == 0) {
- yytname[i] = yytfix[j].want;
- goto loop;
- }
- }
-
- // turn 'x' into x.
- if(s[0] == '\'') {
- t = strdup(s+1);
- t[strlen(t)-1] = '\0';
- yytname[i] = t;
- }
- loop:;
- }
-}
-
-static void
-pkgnotused(int lineno, Strlit *path, char *name)
-{
- char *elem;
-
- // If the package was imported with a name other than the final
- // import path element, show it explicitly in the error message.
- // Note that this handles both renamed imports and imports of
- // packages containing unconventional package declarations.
- // Note that this uses / always, even on Windows, because Go import
- // paths always use forward slashes.
- elem = strrchr(path->s, '/');
- if(elem != nil)
- elem++;
- else
- elem = path->s;
- if(name == nil || strcmp(elem, name) == 0)
- yyerrorl(lineno, "imported and not used: \"%Z\"", path);
- else
- yyerrorl(lineno, "imported and not used: \"%Z\" as %s", path, name);
-}
-
-void
-mkpackage(char* pkgname)
-{
- Sym *s;
- int32 h;
- char *p, *q;
-
- if(localpkg->name == nil) {
- if(strcmp(pkgname, "_") == 0)
- yyerror("invalid package name _");
- localpkg->name = pkgname;
- } else {
- if(strcmp(pkgname, localpkg->name) != 0)
- yyerror("package %s; expected %s", pkgname, localpkg->name);
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->def == N || s->pkg != localpkg)
- continue;
- if(s->def->op == OPACK) {
- // throw away top-level package name leftover
- // from previous file.
- // leave s->block set to cause redeclaration
- // errors if a conflicting top-level name is
- // introduced by a different file.
- if(!s->def->used && !nsyntaxerrors)
- pkgnotused(s->def->lineno, s->def->pkg->path, s->name);
- s->def = N;
- continue;
- }
- if(s->def->sym != s) {
- // throw away top-level name left over
- // from previous import . "x"
- if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
- pkgnotused(s->def->pack->lineno, s->def->pack->pkg->path, nil);
- s->def->pack->used = 1;
- }
- s->def = N;
- continue;
- }
- }
- }
- }
-
- if(outfile == nil) {
- p = strrchr(infile, '/');
- if(ctxt->windows) {
- q = strrchr(infile, '\\');
- if(q > p)
- p = q;
- }
- if(p == nil)
- p = infile;
- else
- p = p+1;
- snprint(namebuf, sizeof(namebuf), "%s", p);
- p = strrchr(namebuf, '.');
- if(p != nil)
- *p = 0;
- outfile = smprint("%s.%c", namebuf, thearch.thechar);
- }
-}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
deleted file mode 100644
index 46cb6b712d..0000000000
--- a/src/cmd/gc/md5.c
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// 64-bit MD5 (does full MD5 but returns 64 bits only).
-// Translation of ../../crypto/md5/md5*.go.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "md5.h"
-
-static int md5block(MD5 *dig, uchar *p, int nn);
-
-enum {
- _Chunk = 64
-};
-
-#define _Init0 0x67452301
-#define _Init1 0xEFCDAB89
-#define _Init2 0x98BADCFE
-#define _Init3 0x10325476
-/*c2go
-enum {
- _Init0 = 0x67452301,
- _Init1 = 0xEFCDAB89,
- _Init2 = 0x98BADCFE,
- _Init3 = 0x10325476
-};
-*/
-
-void
-md5reset(MD5 *d)
-{
- d->s[0] = _Init0;
- d->s[1] = _Init1;
- d->s[2] = _Init2;
- d->s[3] = _Init3;
- d->nx = 0;
- d->len = 0;
-}
-
-void
-md5write(MD5 *d, uchar *p, int nn)
-{
- int i, n;
-
- d->len += nn;
- if(d->nx > 0) {
- n = nn;
- if(n > _Chunk - d->nx)
- n = _Chunk - d->nx;
- for(i=0; i<n; i++)
- d->x[d->nx+i] = p[i];
- d->nx += n;
- if(d->nx == _Chunk) {
- md5block(d, d->x, _Chunk);
- d->nx = 0;
- }
- p += n;
- nn -= n;
- }
- n = md5block(d, p, nn);
- p += n;
- nn -= n;
- if(nn > 0) {
- for(i=0; i<nn; i++)
- d->x[i] = p[i];
- d->nx = nn;
- }
-}
-
-uint64
-md5sum(MD5 *d, uint64 *hi)
-{
- uchar tmp[64];
- int i;
- uint64 len;
-
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- len = d->len;
- memset(tmp, 0, sizeof tmp);
- tmp[0] = 0x80;
- if(len%64 < 56)
- md5write(d, tmp, 56-len%64);
- else
- md5write(d, tmp, 64+56-len%64);
-
- // Length in bits.
- len <<= 3;
- for(i=0; i<8; i++)
- tmp[i] = len>>(8*i);
- md5write(d, tmp, 8);
-
- if(d->nx != 0)
- fatal("md5sum");
-
- if(hi != nil)
- *hi = d->s[2] | ((uint64)d->s[3]<<32);
- return d->s[0] | ((uint64)d->s[1]<<32);
-}
-
-
-// MD5 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-// table[i] = int((1<<32) * abs(sin(i+1 radians))).
-static uint32 table[64] = {
- // round 1
- 0xd76aa478,
- 0xe8c7b756,
- 0x242070db,
- 0xc1bdceee,
- 0xf57c0faf,
- 0x4787c62a,
- 0xa8304613,
- 0xfd469501,
- 0x698098d8,
- 0x8b44f7af,
- 0xffff5bb1,
- 0x895cd7be,
- 0x6b901122,
- 0xfd987193,
- 0xa679438e,
- 0x49b40821,
-
- // round 2
- 0xf61e2562,
- 0xc040b340,
- 0x265e5a51,
- 0xe9b6c7aa,
- 0xd62f105d,
- 0x2441453,
- 0xd8a1e681,
- 0xe7d3fbc8,
- 0x21e1cde6,
- 0xc33707d6,
- 0xf4d50d87,
- 0x455a14ed,
- 0xa9e3e905,
- 0xfcefa3f8,
- 0x676f02d9,
- 0x8d2a4c8a,
-
- // round3
- 0xfffa3942,
- 0x8771f681,
- 0x6d9d6122,
- 0xfde5380c,
- 0xa4beea44,
- 0x4bdecfa9,
- 0xf6bb4b60,
- 0xbebfbc70,
- 0x289b7ec6,
- 0xeaa127fa,
- 0xd4ef3085,
- 0x4881d05,
- 0xd9d4d039,
- 0xe6db99e5,
- 0x1fa27cf8,
- 0xc4ac5665,
-
- // round 4
- 0xf4292244,
- 0x432aff97,
- 0xab9423a7,
- 0xfc93a039,
- 0x655b59c3,
- 0x8f0ccc92,
- 0xffeff47d,
- 0x85845dd1,
- 0x6fa87e4f,
- 0xfe2ce6e0,
- 0xa3014314,
- 0x4e0811a1,
- 0xf7537e82,
- 0xbd3af235,
- 0x2ad7d2bb,
- 0xeb86d391,
-};
-
-static uint32 shift1[] = { 7, 12, 17, 22 };
-static uint32 shift2[] = { 5, 9, 14, 20 };
-static uint32 shift3[] = { 4, 11, 16, 23 };
-static uint32 shift4[] = { 6, 10, 15, 21 };
-
-static int
-md5block(MD5 *dig, uchar *p, int nn)
-{
- uint32 a, b, c, d, aa, bb, cc, dd;
- int i, j, n;
- uint32 X[16];
-
- a = dig->s[0];
- b = dig->s[1];
- c = dig->s[2];
- d = dig->s[3];
- n = 0;
-
- while(nn >= _Chunk) {
- aa = a;
- bb = b;
- cc = c;
- dd = d;
-
- for(i=0; i<16; i++) {
- j = i*4;
- X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | ((uint32)p[j+3]<<24);
- }
-
- // Round 1.
- for(i=0; i<16; i++) {
- uint32 x, t, s, f;
- x = i;
- t = i;
- s = shift1[i%4];
- f = ((c ^ d) & b) ^ d;
- a += f + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 2.
- for(i=0; i<16; i++) {
- uint32 x, t, s, g;
-
- x = (1+5*i)%16;
- t = 16+i;
- s = shift2[i%4];
- g = ((b ^ c) & d) ^ c;
- a += g + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 3.
- for(i=0; i<16; i++) {
- uint32 x, t, s, h;
-
- x = (5+3*i)%16;
- t = 32+i;
- s = shift3[i%4];
- h = b ^ c ^ d;
- a += h + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 4.
- for(i=0; i<16; i++) {
- uint32 x, s, t, ii;
-
- x = (7*i)%16;
- s = shift4[i%4];
- t = 48+i;
- ii = c ^ (b | ~d);
- a += ii + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- a += aa;
- b += bb;
- c += cc;
- d += dd;
-
- p += _Chunk;
- n += _Chunk;
- nn -= _Chunk;
- }
-
- dig->s[0] = a;
- dig->s[1] = b;
- dig->s[2] = c;
- dig->s[3] = d;
- return n;
-}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
deleted file mode 100644
index 5a60106b21..0000000000
--- a/src/cmd/gc/md5.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-typedef struct MD5 MD5;
-struct MD5
-{
- uint32 s[4];
- uchar x[64];
- int nx;
- uint64 len;
-};
-
-void md5reset(MD5*);
-void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*, uint64*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
deleted file mode 100755
index 696aa82424..0000000000
--- a/src/cmd/gc/mkbuiltin
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Generate builtin.c from $* (runtime.go and unsafe.go).
-# Run this after changing runtime.go and unsafe.go
-# or after changing the export metadata format in the compiler.
-# Either way, you need to have a working compiler binary first.
-
-set -e
-
-eval $(go tool dist env)
-if [ -z "$GOCHAR" ]; then
- echo 'missing $GOCHAR - go tool dist failed?' 1>&2
- exit 1
-fi
-
-GC=${GOCHAR}g
-gcc -o mkbuiltin1 mkbuiltin1.c
-rm -f _builtin.c
-echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c
-echo "#include <u.h>" >>_builtin.c
-echo "#include <libc.h>" >>_builtin.c
-echo '#include "go.h"' >>_builtin.c
-
-for i in runtime unsafe
-do
- go tool $GC -A $i.go
- O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c
-done
-
-# If _builtin.c has changed vs builtin.c,
-# check in the new change.
-cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c
-rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
deleted file mode 100644
index 69027fdf5d..0000000000
--- a/src/cmd/gc/mkbuiltin1.c
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// Compile .go file, import data from .6 file, and generate C string version.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-
-void esc(char*);
-void fatal(char*, ...);
-
-int
-main(int argc, char **argv)
-{
- char *name;
- FILE *fin;
- char buf[1024], initfunc[1024], *p, *q;
-
- if(argc != 2) {
- fprintf(stderr, "usage: mkbuiltin1 sys\n");
- fatal("in file $1.6 s/PACKAGE/$1/");
- }
-
- name = argv[1];
- snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
-
- snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
- if((fin = fopen(buf, "r")) == NULL) {
- fatal("open %s: %s", buf, strerror(errno));
- }
-
- // look for $$ that introduces imports
- while(fgets(buf, sizeof buf, fin) != NULL)
- if(strstr(buf, "$$"))
- goto begin;
- fatal("did not find beginning of imports");
-
-begin:
- printf("char *%simport =\n", name);
-
- // process imports, stopping at $$ that closes them
- while(fgets(buf, sizeof buf, fin) != NULL) {
- buf[strlen(buf)-1] = 0; // chop \n
- if(strstr(buf, "$$"))
- goto end;
-
- // chop leading white space
- for(p=buf; *p==' ' || *p == '\t'; p++)
- ;
-
- // cut out decl of init_$1_function - it doesn't exist
- if(strstr(buf, initfunc))
- continue;
-
- // sys.go claims to be in package PACKAGE to avoid
- // conflicts during "6g sys.go". rename PACKAGE to $2.
- printf("\t\"");
- while((q = strstr(p, "PACKAGE")) != NULL) {
- *q = 0;
- esc(p); // up to the substitution
- printf("%s", name); // the sub name
- p = q+7; // continue with rest
- }
-
- esc(p);
- printf("\\n\"\n");
- }
- fatal("did not find end of imports");
-
-end:
- printf("\t\"$$\\n\";\n");
- return 0;
-}
-
-void
-esc(char *p)
-{
- for(; *p; p++) {
- if(*p == '\\' || *p == '\"')
- printf("\\");
- putchar(*p);
- }
-}
-
-void
-fatal(char *msg, ...)
-{
- va_list arg;
-
- va_start(arg, msg);
- fprintf(stderr, "fatal: ");
- vfprintf(stderr, msg, arg);
- fprintf(stderr, "\n");
- exit(2);
-}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
deleted file mode 100755
index d3f27e8152..0000000000
--- a/src/cmd/gc/mkopnames
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Disable colored grep if user has it set to --color=always.
-# (Arguably user error.)
-export GREP_OPTIONS=""
-
-echo '// auto generated by mkopnames'
-echo 'static char*'
-echo 'opnames[] = '
-echo '{'
-sed -n '/OXXX/,/OEND/p' go.h |
- cpp |
- sed 's!//.*!!; /^#/d' |
- tr ' ' '\012' |
- tr -d ' \011,' |
- grep . |
- sort |
- grep -v '^OEND$' |
- sed 's/O//; s/.*/ [O&] = "&",/'
-echo '};'
-
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
deleted file mode 100644
index 6a0eb2d6d9..0000000000
--- a/src/cmd/gc/mparith1.c
+++ /dev/null
@@ -1,655 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/// uses arithmetic
-
-int
-mpcmpfixflt(Mpint *a, Mpflt *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", a);
- mpatoflt(&c, buf);
- return mpcmpfltflt(&c, b);
-}
-
-int
-mpcmpfltfix(Mpflt *a, Mpint *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", b);
- mpatoflt(&c, buf);
- return mpcmpfltflt(a, &c);
-}
-
-int
-mpcmpfixfix(Mpint *a, Mpint *b)
-{
- Mpint c;
-
- mpmovefixfix(&c, a);
- mpsubfixfix(&c, b);
- return mptestfix(&c);
-}
-
-int
-mpcmpfixc(Mpint *b, vlong c)
-{
- Mpint c1;
-
- mpmovecfix(&c1, c);
- return mpcmpfixfix(b, &c1);
-}
-
-int
-mpcmpfltflt(Mpflt *a, Mpflt *b)
-{
- Mpflt c;
-
- mpmovefltflt(&c, a);
- mpsubfltflt(&c, b);
- return mptestflt(&c);
-}
-
-int
-mpcmpfltc(Mpflt *b, double c)
-{
- Mpflt a;
-
- mpmovecflt(&a, c);
- return mpcmpfltflt(b, &a);
-}
-
-void
-mpsubfixfix(Mpint *a, Mpint *b)
-{
- mpnegfix(a);
- mpaddfixfix(a, b, 0);
- mpnegfix(a);
-}
-
-void
-mpsubfltflt(Mpflt *a, Mpflt *b)
-{
- mpnegflt(a);
- mpaddfltflt(a, b);
- mpnegflt(a);
-}
-
-void
-mpaddcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpaddfixfix(a, &b, 0);
-}
-
-void
-mpaddcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpaddfltflt(a, &b);
-}
-
-void
-mpmulcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpmulfixfix(a, &b);
-}
-
-void
-mpmulcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpmulfltflt(a, &b);
-}
-
-void
-mpdivfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &q);
-}
-
-void
-mpmodfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &r);
-}
-
-void
-mpcomfix(Mpint *a)
-{
- Mpint b;
-
- mpmovecfix(&b, 1);
- mpnegfix(a);
- mpsubfixfix(a, &b);
-}
-
-void
-mpmovefixflt(Mpflt *a, Mpint *b)
-{
- a->val = *b;
- a->exp = 0;
- mpnorm(a);
-}
-
-// convert (truncate) b to a.
-// return -1 (but still convert) if b was non-integer.
-static int
-mpexactfltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
-
- *a = b->val;
- mpshiftfix(a, b->exp);
- if(b->exp < 0) {
- f.val = *a;
- f.exp = 0;
- mpnorm(&f);
- if(mpcmpfltflt(b, &f) != 0)
- return -1;
- }
- return 0;
-}
-
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
- int i;
-
- if(mpexactfltfix(a, b) == 0)
- return 0;
-
- // try rounding down a little
- f = *b;
- f.val.a[0] = 0;
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- // try rounding up a little
- for(i=1; i<Mpprec; i++) {
- f.val.a[i]++;
- if(f.val.a[i] != Mpbase)
- break;
- f.val.a[i] = 0;
- }
- mpnorm(&f);
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- return -1;
-}
-
-void
-mpmovefixfix(Mpint *a, Mpint *b)
-{
- *a = *b;
-}
-
-void
-mpmovefltflt(Mpflt *a, Mpflt *b)
-{
- *a = *b;
-}
-
-static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
-static void
-mppow10flt(Mpflt *a, int p)
-{
- if(p < 0)
- abort();
- if(p < nelem(tab)) {
- mpmovecflt(a, tab[p]);
- return;
- }
- mppow10flt(a, p>>1);
- mpmulfltflt(a, a);
- if(p & 1)
- mpmulcflt(a, 10);
-}
-
-static void
-mphextofix(Mpint *a, char *s, int n)
-{
- char c;
- long d;
- int bit, hexdigitp, end;
-
- while(*s == '0') {
- s++;
- n--;
- }
-
- // overflow
- if(4*n > Mpscale*Mpprec) {
- a->ovf = 1;
- return;
- }
-
- end = n-1;
- for(hexdigitp=end; hexdigitp>=0; hexdigitp--) {
- c = s[hexdigitp];
- if(c >= '0' && c <= '9')
- d = c-'0';
- else if(c >= 'A' && c <= 'F')
- d = c-'A'+10;
- else
- d = c-'a'+10;
-
- bit = 4*(end - hexdigitp);
- while(d > 0) {
- if(d & 1)
- a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale);
- bit++;
- d = d >> 1;
- }
- }
-}
-
-//
-// floating point input
-// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
-//
-void
-mpatoflt(Mpflt *a, char *as)
-{
- Mpflt b;
- int dp, c, f, ef, ex, eb, base;
- char *s, *start;
-
- while(*as == ' ' || *as == '\t')
- as++;
-
- /* determine base */
- s = as;
- base = -1;
- while(base == -1) {
- switch(*s++) {
- case '-':
- case '+':
- break;
-
- case '0':
- if(*s == 'x')
- base = 16;
- else
- base = 10;
- break;
-
- default:
- base = 10;
- }
- }
-
- s = as;
- dp = 0; /* digits after decimal point */
- f = 0; /* sign */
- ex = 0; /* exponent */
- eb = 0; /* binary point */
-
- mpmovecflt(a, 0.0);
- if(base == 16) {
- start = nil;
- for(;;) {
- c = *s;
- if(c == '-') {
- f = 1;
- s++;
- }
- else if(c == '+') {
- s++;
- }
- else if(c == '0' && s[1] == 'x') {
- s += 2;
- start = s;
- }
- else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
- s++;
- }
- else {
- break;
- }
- }
- if(start == nil) {
- yyerror("malformed hex constant: %s", as);
- goto bad;
- }
-
- mphextofix(&a->val, start, s-start);
- if(a->val.ovf) {
- yyerror("constant too large: %s", as);
- goto bad;
- }
- a->exp = 0;
- mpnorm(a);
- }
- for(;;) {
- c = *s++;
- switch(c) {
- default:
- yyerror("malformed constant: %s (at %c)", as, c);
- goto bad;
-
- case '-':
- f = 1;
-
- case ' ':
- case '\t':
- case '+':
- continue;
-
- case '.':
- if(base == 16) {
- yyerror("decimal point in hex constant: %s", as);
- goto bad;
- }
- dp = 1;
- continue;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- mpmulcflt(a, 10);
- mpaddcflt(a, c-'0');
- if(dp)
- dp++;
- continue;
-
- case 'P':
- case 'p':
- eb = 1;
-
- case 'E':
- case 'e':
- ex = 0;
- ef = 0;
- for(;;) {
- c = *s++;
- if(c == '+' || c == ' ' || c == '\t')
- continue;
- if(c == '-') {
- ef = 1;
- continue;
- }
- if(c >= '0' && c <= '9') {
- ex = ex*10 + (c-'0');
- if(ex > 1e8) {
- yyerror("constant exponent out of range: %s", as);
- errorexit();
- }
- continue;
- }
- break;
- }
- if(ef)
- ex = -ex;
-
- case 0:
- break;
- }
- break;
- }
-
- if(eb) {
- if(dp) {
- yyerror("decimal point and binary point in constant: %s", as);
- goto bad;
- }
- mpsetexp(a, a->exp+ex);
- goto out;
- }
-
- if(dp)
- dp--;
- if(mpcmpfltc(a, 0.0) != 0) {
- if(ex >= dp) {
- mppow10flt(&b, ex-dp);
- mpmulfltflt(a, &b);
- } else {
- // 4 approximates least_upper_bound(log2(10)).
- if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
- mpmovecflt(a, 0.0);
- }
- else {
- mppow10flt(&b, dp-ex);
- mpdivfltflt(a, &b);
- }
- }
- }
-
-out:
- if(f)
- mpnegflt(a);
- return;
-
-bad:
- mpmovecflt(a, 0.0);
-}
-
-//
-// fixed point input
-// required syntax is [+-][0[x]]d*
-//
-void
-mpatofix(Mpint *a, char *as)
-{
- int c, f;
- char *s, *s0;
-
- s = as;
- f = 0;
- mpmovecfix(a, 0);
-
- c = *s++;
- switch(c) {
- case '-':
- f = 1;
-
- case '+':
- c = *s++;
- if(c != '0')
- break;
-
- case '0':
- goto oct;
- }
-
- while(c) {
- if(c >= '0' && c <= '9') {
- mpmulcfix(a, 10);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- yyerror("malformed decimal constant: %s", as);
- goto bad;
- }
- goto out;
-
-oct:
- c = *s++;
- if(c == 'x' || c == 'X')
- goto hex;
- while(c) {
- if(c >= '0' && c <= '7') {
- mpmulcfix(a, 8);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- yyerror("malformed octal constant: %s", as);
- goto bad;
- }
- goto out;
-
-hex:
- s0 = s;
- c = *s;
- while(c) {
- if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
- s++;
- c = *s;
- continue;
- }
- yyerror("malformed hex constant: %s", as);
- goto bad;
- }
- mphextofix(a, s0, s-s0);
- if(a->ovf) {
- yyerror("constant too large: %s", as);
- goto bad;
- }
-
-out:
- if(f)
- mpnegfix(a);
- return;
-
-bad:
- mpmovecfix(a, 0);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char buf[500];
- int p;
- Mpint *xval, q, r, ten, sixteen;
- int f, digit;
-
- xval = va_arg(fp->args, Mpint*);
- mpmovefixfix(&q, xval);
- f = 0;
- if(mptestfix(&q) < 0) {
- f = 1;
- mpnegfix(&q);
- }
-
- p = sizeof(buf);
- buf[--p] = 0;
- if(fp->flags & FmtSharp) {
- // Hexadecimal
- mpmovecfix(&sixteen, 16);
- for(;;) {
- mpdivmodfixfix(&q, &r, &q, &sixteen);
- digit = mpgetfix(&r);
- if(digit < 10)
- buf[--p] = digit + '0';
- else
- buf[--p] = digit - 10 + 'A';
- if(mptestfix(&q) <= 0)
- break;
- }
- buf[--p] = 'x';
- buf[--p] = '0';
- } else {
- // Decimal
- mpmovecfix(&ten, 10);
- for(;;) {
- mpdivmodfixfix(&q, &r, &q, &ten);
- buf[--p] = mpgetfix(&r) + '0';
- if(mptestfix(&q) <= 0)
- break;
- }
- }
- if(f)
- buf[--p] = '-';
- return fmtstrcpy(fp, &buf[p]);
-}
-
-int
-Fconv(Fmt *fp)
-{
- char buf[500];
- Mpflt *fvp, fv;
- double d, dexp;
- int exp;
-
- fvp = va_arg(fp->args, Mpflt*);
- if(fp->flags & FmtSharp) {
- // alternate form - decimal for error messages.
- // for well in range, convert to double and use print's %g
- exp = fvp->exp + sigfig(fvp)*Mpscale;
- if(-900 < exp && exp < 900) {
- d = mpgetflt(fvp);
- if(d >= 0 && (fp->flags & FmtSign))
- fmtprint(fp, "+");
- return fmtprint(fp, "%g", d);
- }
-
- // very out of range. compute decimal approximation by hand.
- // decimal exponent
- dexp = fvp->exp * 0.301029995663981195; // log_10(2)
- exp = (int)dexp;
- // decimal mantissa
- fv = *fvp;
- fv.val.neg = 0;
- fv.exp = 0;
- d = mpgetflt(&fv);
- d *= pow(10, dexp-exp);
- while(d >= 9.99995) {
- d /= 10;
- exp++;
- }
- if(fvp->val.neg)
- fmtprint(fp, "-");
- else if(fp->flags & FmtSign)
- fmtprint(fp, "+");
- return fmtprint(fp, "%.5fe+%d", d, exp);
- }
-
- if(sigfig(fvp) == 0) {
- snprint(buf, sizeof(buf), "0p+0");
- goto out;
- }
- fv = *fvp;
-
- while(fv.val.a[0] == 0) {
- mpshiftfix(&fv.val, -Mpscale);
- fv.exp += Mpscale;
- }
- while((fv.val.a[0]&1) == 0) {
- mpshiftfix(&fv.val, -1);
- fv.exp += 1;
- }
-
- if(fv.exp >= 0) {
- snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp);
- goto out;
- }
- snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp);
-
-out:
- return fmtstrcpy(fp, buf);
-}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
deleted file mode 100644
index 37aafbb5f5..0000000000
--- a/src/cmd/gc/mparith2.c
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-//
-// return the significant
-// words of the argument
-//
-static int
-mplen(Mpint *a)
-{
- int i, n;
-
- n = -1;
- for(i=0; i<Mpprec; i++) {
- if(a->a[i] != 0)
- n = i;
- }
- return n+1;
-}
-
-//
-// left shift mpint by one
-// ignores sign
-//
-static void
-mplsh(Mpint *a, int quiet)
-{
- long x;
- int i, c;
-
- c = 0;
- for(i=0; i<Mpprec; i++) {
- x = (a->a[i] << 1) + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- a->a[i] = x;
- }
- a->ovf = c;
- if(a->ovf && !quiet)
- yyerror("constant shift overflow");
-}
-
-//
-// left shift mpint by Mpscale
-// ignores sign
-//
-static void
-mplshw(Mpint *a, int quiet)
-{
- int i;
-
- i = Mpprec-1;
- if(a->a[i]) {
- a->ovf = 1;
- if(!quiet)
- yyerror("constant shift overflow");
- }
- for(; i > 0; i--)
- a->a[i] = a->a[i-1];
- a->a[i] = 0;
-}
-
-//
-// right shift mpint by one
-// ignores sign and overflow
-//
-static void
-mprsh(Mpint *a)
-{
- long x, lo;
- int i, c;
-
- c = 0;
- lo = a->a[0] & 1;
- for(i=Mpprec-1; i>=0; i--) {
- x = a->a[i];
- a->a[i] = (x + c) >> 1;
- c = 0;
- if(x & 1)
- c = Mpbase;
- }
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// right shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mprshw(Mpint *a)
-{
- long lo;
- int i;
-
- lo = a->a[0];
- for(i=0; i<Mpprec-1; i++) {
- a->a[i] = a->a[i+1];
- }
- a->a[i] = 0;
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// return the sign of (abs(a)-abs(b))
-//
-static int
-mpcmp(Mpint *a, Mpint *b)
-{
- long x;
- int i;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in cmp");
- return 0;
- }
-
- for(i=Mpprec-1; i>=0; i--) {
- x = a->a[i] - b->a[i];
- if(x > 0)
- return +1;
- if(x < 0)
- return -1;
- }
- return 0;
-}
-
-//
-// negate a
-// ignore sign and ovf
-//
-static void
-mpneg(Mpint *a)
-{
- long x;
- int i, c;
-
- c = 0;
- for(i=0; i<Mpprec; i++) {
- x = -a->a[i] -c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- a->a[i] = x;
- }
-}
-
-// shift left by s (or right by -s)
-void
-mpshiftfix(Mpint *a, int s)
-{
- if(s >= 0) {
- while(s >= Mpscale) {
- mplshw(a, 0);
- s -= Mpscale;
- }
- while(s > 0) {
- mplsh(a, 0);
- s--;
- }
- } else {
- s = -s;
- while(s >= Mpscale) {
- mprshw(a);
- s -= Mpscale;
- }
- while(s > 0) {
- mprsh(a);
- s--;
- }
- }
-}
-
-/// implements fix arihmetic
-
-void
-mpaddfixfix(Mpint *a, Mpint *b, int quiet)
-{
- int i, c;
- long x;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mpaddxx");
- a->ovf = 1;
- return;
- }
-
- c = 0;
- if(a->neg != b->neg)
- goto sub;
-
- // perform a+b
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] + b->a[i] + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- a->a[i] = x;
- }
- a->ovf = c;
- if(a->ovf && !quiet)
- yyerror("constant addition overflow");
-
- return;
-
-sub:
- // perform a-b
- switch(mpcmp(a, b)) {
- case 0:
- mpmovecfix(a, 0);
- break;
-
- case 1:
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] - b->a[i] - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- a->a[i] = x;
- }
- break;
-
- case -1:
- a->neg ^= 1;
- for(i=0; i<Mpprec; i++) {
- x = b->a[i] - a->a[i] - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- a->a[i] = x;
- }
- break;
- }
-}
-
-void
-mpmulfixfix(Mpint *a, Mpint *b)
-{
-
- int i, j, na, nb;
- long x;
- Mpint s, q;
- Mpint *c;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mpmulfixfix");
- a->ovf = 1;
- return;
- }
-
- // pick the smaller
- // to test for bits
- na = mplen(a);
- nb = mplen(b);
- if(na > nb) {
- mpmovefixfix(&s, a);
- c = b;
- na = nb;
- } else {
- mpmovefixfix(&s, b);
- c = a;
- }
- s.neg = 0;
-
- mpmovecfix(&q, 0);
- for(i=0; i<na; i++) {
- x = c->a[i];
- for(j=0; j<Mpscale; j++) {
- if(x & 1) {
- if(s.ovf) {
- q.ovf = 1;
- goto out;
- }
- mpaddfixfix(&q, &s, 1);
- if(q.ovf)
- goto out;
- }
- mplsh(&s, 1);
- x >>= 1;
- }
- }
-
-out:
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("constant multiplication overflow");
-}
-
-void
-mpmulfract(Mpint *a, Mpint *b)
-{
-
- int i, j;
- long x;
- Mpint s, q;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mpmulflt");
- a->ovf = 1;
- return;
- }
-
- mpmovefixfix(&s, b);
- s.neg = 0;
- mpmovecfix(&q, 0);
-
- i = Mpprec-1;
- x = a->a[i];
- if(x != 0)
- yyerror("mpmulfract not normal");
-
- for(i--; i >= 0; i--) {
- x = a->a[i];
- if(x == 0) {
- mprshw(&s);
- continue;
- }
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(x & Mpbase)
- mpaddfixfix(&q, &s, 1);
- mprsh(&s);
- }
- }
-
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("constant multiplication overflow");
-}
-
-void
-mporfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x;
-
- x = 0;
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] | b->a[i];
- a->a[i] = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x;
-
- x = 0;
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mpandfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] & b->a[i];
- a->a[i] = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandnotfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x;
-
- x = 0;
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mpandnotfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] & ~b->a[i];
- a->a[i] = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpxorfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x;
-
- x = 0;
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- for(i=0; i<Mpprec; i++) {
- x = a->a[i] ^ b->a[i];
- a->a[i] = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mplshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, s);
-}
-
-void
-mprshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("ovf in mprshfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- if(a->neg)
- mpmovecfix(a, -1);
- else
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, -s);
-}
-
-void
-mpnegfix(Mpint *a)
-{
- a->neg ^= 1;
-}
-
-vlong
-mpgetfix(Mpint *a)
-{
- vlong v;
-
- if(a->ovf) {
- if(nsavederrors+nerrors == 0)
- yyerror("constant overflow");
- return 0;
- }
-
- v = (uvlong)a->a[0];
- v |= (uvlong)a->a[1] << Mpscale;
- v |= (uvlong)a->a[2] << (Mpscale+Mpscale);
- if(a->neg)
- v = -(uvlong)v;
- return v;
-}
-
-void
-mpmovecfix(Mpint *a, vlong c)
-{
- int i;
- vlong x;
-
- a->neg = 0;
- a->ovf = 0;
-
- x = c;
- if(x < 0) {
- a->neg = 1;
- x = -(uvlong)x;
- }
-
- for(i=0; i<Mpprec; i++) {
- a->a[i] = x&Mpmask;
- x >>= Mpscale;
- }
-}
-
-void
-mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
-{
- int i, ns, ds;
-
- ns = n->neg;
- ds = d->neg;
- n->neg = 0;
- d->neg = 0;
-
- mpmovefixfix(r, n);
- mpmovecfix(q, 0);
-
- // shift denominator until it
- // is larger than numerator
- for(i=0; i<Mpprec*Mpscale; i++) {
- if(mpcmp(d, r) > 0)
- break;
- mplsh(d, 1);
- }
-
- // if it never happens
- // denominator is probably zero
- if(i >= Mpprec*Mpscale) {
- q->ovf = 1;
- r->ovf = 1;
- n->neg = ns;
- d->neg = ds;
- yyerror("constant division overflow");
- return;
- }
-
- // shift denominator back creating
- // quotient a bit at a time
- // when done the remaining numerator
- // will be the remainder
- for(; i>0; i--) {
- mplsh(q, 1);
- mprsh(d);
- if(mpcmp(d, r) <= 0) {
- mpaddcfix(q, 1);
- mpsubfixfix(r, d);
- }
- }
-
- n->neg = ns;
- d->neg = ds;
- r->neg = ns;
- q->neg = ns^ds;
-}
-
-static int
-mpiszero(Mpint *a)
-{
- int i;
-
- for(i=Mpprec-1; i>=0; i--)
- if(a->a[i] != 0)
- return 0;
- return 1;
-}
-
-void
-mpdivfract(Mpint *a, Mpint *b)
-{
- Mpint n, d;
- int i, j, neg;
- long x;
-
- mpmovefixfix(&n, a); // numerator
- mpmovefixfix(&d, b); // denominator
-
- neg = n.neg ^ d.neg;
- n.neg = 0;
- d.neg = 0;
- for(i=Mpprec-1; i >= 0; i--) {
- x = 0;
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(mpcmp(&d, &n) <= 0) {
- if(!mpiszero(&d))
- x |= 1;
- mpsubfixfix(&n, &d);
- }
- mprsh(&d);
- }
- a->a[i] = x;
- }
- a->neg = neg;
-}
-
-int
-mptestfix(Mpint *a)
-{
- Mpint b;
- int r;
-
- mpmovecfix(&b, 0);
- r = mpcmp(a, &b);
- if(a->neg) {
- if(r > 0)
- return -1;
- if(r < 0)
- return +1;
- }
- return r;
-}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
deleted file mode 100644
index 6afd75c023..0000000000
--- a/src/cmd/gc/mparith3.c
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * returns the leading non-zero
- * word of the number
- */
-int
-sigfig(Mpflt *a)
-{
- int i;
-
- for(i=Mpprec-1; i>=0; i--)
- if(a->val.a[i] != 0)
- break;
-//print("sigfig %d %d\n", i-z+1, z);
- return i+1;
-}
-
-/*
- * sets the exponent.
- * a too large exponent is an error.
- * a too small exponent rounds the number to zero.
- */
-void
-mpsetexp(Mpflt *a, int exp) {
- if((short)exp != exp) {
- if(exp > 0) {
- yyerror("float constant is too large");
- a->exp = 0x7fff;
- }
- else {
- mpmovecflt(a, 0);
- }
- }
- else {
- a->exp = exp;
- }
-}
-
-/*
- * shifts the leading non-zero
- * word of the number to Mpnorm
- */
-void
-mpnorm(Mpflt *a)
-{
- int s, os;
- long x;
-
- os = sigfig(a);
- if(os == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // this will normalize to the nearest word
- x = a->val.a[os-1];
- s = (Mpnorm-os) * Mpscale;
-
- // further normalize to the nearest bit
- for(;;) {
- x <<= 1;
- if(x & Mpbase)
- break;
- s++;
- if(x == 0) {
- // this error comes from trying to
- // convert an Inf or something
- // where the initial x=0x80000000
- s = (Mpnorm-os) * Mpscale;
- break;
- }
- }
-
- mpshiftfix(&a->val, s);
- mpsetexp(a, a->exp-s);
-}
-
-/// implements float arihmetic
-
-void
-mpaddfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb, s;
- Mpflt c;
-
- if(Mpdebug)
- print("\n%F + %F", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- mpmovefltflt(a, b);
- goto out;
- }
-
- sb = sigfig(b);
- if(sb == 0)
- goto out;
-
- s = a->exp - b->exp;
- if(s > 0) {
- // a is larger, shift b right
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, -s);
- mpaddfixfix(&a->val, &c.val, 0);
- goto out;
- }
- if(s < 0) {
- // b is larger, shift a right
- mpshiftfix(&a->val, s);
- mpsetexp(a, a->exp-s);
- mpaddfixfix(&a->val, &b->val, 0);
- goto out;
- }
- mpaddfixfix(&a->val, &b->val, 0);
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpmulfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
-
- if(Mpdebug)
- print("%F\n * %F\n", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero
- mpmovefltflt(a, b);
- return;
- }
-
- mpmulfract(&a->val, &b->val);
- mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpdivfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
- Mpflt c;
-
- if(Mpdebug)
- print("%F\n / %F\n", a, b);
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero and ovfl
- a->exp = 0;
- a->val.neg = 0;
- a->val.ovf = 1;
- yyerror("constant division by zero");
- return;
- }
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // adjust b to top
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, Mpscale);
-
- // divide
- mpdivfract(&a->val, &c.val);
- mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-static double
-mpgetfltN(Mpflt *a, int prec, int bias)
-{
- int s, i, e, minexp;
- uvlong v;
- double f;
-
- if(a->val.ovf && nsavederrors+nerrors == 0)
- yyerror("mpgetflt ovf");
-
- s = sigfig(a);
- if(s == 0)
- return 0;
-
- if(s != Mpnorm) {
- yyerror("mpgetflt norm");
- mpnorm(a);
- }
-
- while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
- mpshiftfix(&a->val, 1);
- mpsetexp(a, a->exp-1); // can set 'a' to zero
- s = sigfig(a);
- if(s == 0)
- return 0;
- }
-
- // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
- s = prec+2;
- v = 0;
- for(i=Mpnorm-1; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- if(s > 0) {
- v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
- if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
- v |= 1;
- i--;
- }
- for(; i >= 0; i--) {
- if(a->val.a[i] != 0)
- v |= 1;
- }
-
- // gradual underflow
- e = Mpnorm*Mpscale + a->exp - prec;
- minexp = bias+1-prec+1;
- if(e < minexp) {
- s = minexp - e;
- if(s > prec+1)
- s = prec+1;
- if((v & ((1ULL<<s)-1)) != 0)
- v |= 1ULL<<s;
- v >>= s;
- e = minexp;
- }
-
- // round to even
- v |= (v&4)>>2;
- v += v&1;
- v >>= 2;
-
- f = (double)(v);
- f = ldexp(f, e);
-
- if(a->val.neg)
- f = -f;
-
- return f;
-}
-
-double
-mpgetflt(Mpflt *a)
-{
- return mpgetfltN(a, 53, -1023);
-}
-
-double
-mpgetflt32(Mpflt *a)
-{
- return mpgetfltN(a, 24, -127);
-}
-
-void
-mpmovecflt(Mpflt *a, double c)
-{
- int i;
- double f;
- long l;
-
- if(Mpdebug)
- print("\nconst %g", c);
- mpmovecfix(&a->val, 0);
- a->exp = 0;
- if(c == 0)
- goto out;
- if(c < 0) {
- a->val.neg = 1;
- c = -c;
- }
-
- f = frexp(c, &i);
- a->exp = i;
-
- for(i=0; i<10; i++) {
- f = f*Mpbase;
- l = floor(f);
- f = f - l;
- a->exp -= Mpscale;
- a->val.a[0] = l;
- if(f == 0)
- break;
- mpshiftfix(&a->val, Mpscale);
- }
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n", a);
-}
-
-void
-mpnegflt(Mpflt *a)
-{
- a->val.neg ^= 1;
-}
-
-int
-mptestflt(Mpflt *a)
-{
- int s;
-
- if(Mpdebug)
- print("\n%F?", a);
- s = sigfig(a);
- if(s != 0) {
- s = +1;
- if(a->val.neg)
- s = -1;
- }
- if(Mpdebug)
- print(" = %d\n", s);
- return s;
-}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
deleted file mode 100644
index 3983f99d6d..0000000000
--- a/src/cmd/gc/obj.c
+++ /dev/null
@@ -1,498 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-
-/*
- * architecture-independent object file output
- */
-
-static void dumpglobls(void);
-
-enum
-{
- ArhdrSize = 60
-};
-
-static void
-formathdr(char *arhdr, char *name, vlong size)
-{
- snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
- name, 0, 0, 0, 0644, size);
- arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
-}
-
-void
-dumpobj(void)
-{
- NodeList *externs, *tmp;
- char arhdr[ArhdrSize];
- vlong startobj, size;
- Sym *zero;
-
- bout = Bopen(outfile, OWRITE);
- if(bout == nil) {
- flusherrors();
- print("can't create %s: %r\n", outfile);
- errorexit();
- }
-
- startobj = 0;
- if(writearchive) {
- Bwrite(bout, "!<arch>\n", 8);
- memset(arhdr, 0, sizeof arhdr);
- Bwrite(bout, arhdr, sizeof arhdr);
- startobj = Boffset(bout);
- }
- Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
- dumpexport();
-
- if(writearchive) {
- Bflush(bout);
- size = Boffset(bout) - startobj;
- if(size&1)
- Bputc(bout, 0);
- Bseek(bout, startobj - ArhdrSize, 0);
- formathdr(arhdr, "__.PKGDEF", size);
- Bwrite(bout, arhdr, ArhdrSize);
- Bflush(bout);
-
- Bseek(bout, startobj + size + (size&1), 0);
- memset(arhdr, 0, ArhdrSize);
- Bwrite(bout, arhdr, ArhdrSize);
- startobj = Boffset(bout);
- Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
- }
-
- if(pragcgobuf.to > pragcgobuf.start) {
- if(writearchive) {
- // write empty export section; must be before cgo section
- Bprint(bout, "\n$$\n\n$$\n\n");
- }
- Bprint(bout, "\n$$ // cgo\n");
- Bprint(bout, "%s\n$$\n\n", fmtstrflush(&pragcgobuf));
- }
-
-
- Bprint(bout, "\n!\n");
-
- externs = nil;
- if(externdcl != nil)
- externs = externdcl->end;
-
- dumpglobls();
- dumptypestructs();
-
- // Dump extra globals.
- tmp = externdcl;
- if(externs != nil)
- externdcl = externs->next;
- dumpglobls();
- externdcl = tmp;
-
- zero = pkglookup("zerovalue", runtimepkg);
- ggloblsym(zero, zerosize, DUPOK|RODATA);
-
- dumpdata();
- writeobj(ctxt, bout);
-
- if(writearchive) {
- Bflush(bout);
- size = Boffset(bout) - startobj;
- if(size&1)
- Bputc(bout, 0);
- Bseek(bout, startobj - ArhdrSize, 0);
- snprint(namebuf, sizeof namebuf, "_go_.%c", thearch.thechar);
- formathdr(arhdr, namebuf, size);
- Bwrite(bout, arhdr, ArhdrSize);
- }
- Bterm(bout);
-}
-
-static void
-dumpglobls(void)
-{
- Node *n;
- NodeList *l;
-
- // add globals
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME)
- continue;
-
- if(n->type == T)
- fatal("external %N nil type\n", n);
- if(n->class == PFUNC)
- continue;
- if(n->sym->pkg != localpkg)
- continue;
- dowidth(n->type);
-
- ggloblnod(n);
- }
-
- for(l=funcsyms; l; l=l->next) {
- n = l->n;
- dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
- ggloblsym(n->sym, widthptr, DUPOK|RODATA);
- }
-
- // Do not reprocess funcsyms on next dumpglobls call.
- funcsyms = nil;
-}
-
-void
-Bputname(Biobuf *b, LSym *s)
-{
- Bwrite(b, s->name, strlen(s->name)+1);
-}
-
-LSym*
-linksym(Sym *s)
-{
- char *p;
-
- if(s == nil)
- return nil;
- if(s->lsym != nil)
- return s->lsym;
- if(isblanksym(s))
- s->lsym = linklookup(ctxt, "_", 0);
- else if(s->linkname != nil)
- s->lsym = linklookup(ctxt, s->linkname, 0);
- else {
- p = smprint("%s.%s", s->pkg->prefix, s->name);
- s->lsym = linklookup(ctxt, p, 0);
- free(p);
- }
- return s->lsym;
-}
-
-int
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- // Update symbol data directly instead of generating a
- // DATA instruction that liblink will have to interpret later.
- // This reduces compilation time and memory usage.
- off = rnd(off, wid);
- return setuintxx(ctxt, linksym(s), off, v, wid);
-}
-
-int
-duint8(Sym *s, int off, uint8 v)
-{
- return duintxx(s, off, v, 1);
-}
-
-int
-duint16(Sym *s, int off, uint16 v)
-{
- return duintxx(s, off, v, 2);
-}
-
-int
-duint32(Sym *s, int off, uint32 v)
-{
- return duintxx(s, off, v, 4);
-}
-
-int
-duint64(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, 8);
-}
-
-int
-duintptr(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, widthptr);
-}
-
-Sym*
-stringsym(char *s, int len)
-{
- static int gen;
- Sym *sym;
- int off, n, m;
- struct {
- Strlit lit;
- char buf[110];
- } tmp;
- Pkg *pkg;
-
- if(len > 100) {
- // huge strings are made static to avoid long names
- snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
- pkg = localpkg;
- } else {
- // small strings get named by their contents,
- // so that multiple modules using the same string
- // can share it.
- tmp.lit.len = len;
- memmove(tmp.lit.s, s, len);
- tmp.lit.s[len] = '\0';
- snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
- pkg = gostringpkg;
- }
- sym = pkglookup(namebuf, pkg);
-
- // SymUniq flag indicates that data is generated already
- if(sym->flags & SymUniq)
- return sym;
- sym->flags |= SymUniq;
- sym->def = newname(sym);
-
- off = 0;
-
- // string header
- off = dsymptr(sym, off, sym, widthptr+widthint);
- off = duintxx(sym, off, len, widthint);
-
- // string data
- for(n=0; n<len; n+=m) {
- m = 8;
- if(m > len-n)
- m = len-n;
- off = dsname(sym, off, s+n, m);
- }
- off = duint8(sym, off, 0); // terminating NUL for runtime
- off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
- ggloblsym(sym, off, DUPOK|RODATA);
-
- return sym;
-}
-
-void
-slicebytes(Node *nam, char *s, int len)
-{
- int off, n, m;
- static int gen;
- Sym *sym;
-
- snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
- sym = pkglookup(namebuf, localpkg);
- sym->def = newname(sym);
-
- off = 0;
- for(n=0; n<len; n+=m) {
- m = 8;
- if(m > len-n)
- m = len-n;
- off = dsname(sym, off, s+n, m);
- }
- ggloblsym(sym, off, NOPTR);
-
- if(nam->op != ONAME)
- fatal("slicebytes %N", nam);
- off = nam->xoffset;
- off = dsymptr(nam->sym, off, sym, 0);
- off = duintxx(nam->sym, off, len, widthint);
- duintxx(nam->sym, off, len, widthint);
-}
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = thearch.gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.offset = off;
- p->from.sym = linksym(s);
- p->from3.type = TYPE_CONST;
- p->from3.offset = n;
-
- p->to.type = TYPE_SCONST;
- memmove(p->to.u.sval, t, n);
- return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(s, len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = widthptr+widthint; // skip header
- a->etype = simtype[TINT];
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(sval->s, sval->len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = 0; // header
- a->etype = TSTRING;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
-
- if(nr->op == OLITERAL) {
- switch(nr->val.ctype) {
- case CTCPLX:
- gdatacomplex(nam, nr->val.u.cval);
- return;
- case CTSTR:
- gdatastring(nam, nr->val.u.sval);
- return;
- }
- }
- p = thearch.gins(ADATA, nam, nr);
- p->from3.type = TYPE_CONST;
- p->from3.offset = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
- Prog *p;
- int w;
-
- w = cplxsubtype(nam->type->etype);
- w = types[w]->width;
-
- p = thearch.gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->real);
-
- p = thearch.gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->from.offset += w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
- Prog *p;
- Node nod1;
-
- p = thearch.gins(ADATA, nam, N);
- datastring(sval->s, sval->len, &p->to);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[tptr]->width;
- p->to.type = TYPE_ADDR;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT], sval->len);
- p = thearch.gins(ADATA, nam, &nod1);
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthint;
- p->from.offset += widthptr;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = thearch.gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
- Prog *p;
-
- if(lit == nil)
- return duintptr(s, off, 0);
-
- off = rnd(off, widthptr);
- p = thearch.gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- datagostring(lit, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
- int n;
- Strlit *lit;
-
- if(str == nil)
- return duintptr(s, off, 0);
-
- n = strlen(str);
- lit = mal(sizeof *lit + n);
- strcpy(lit->s, str);
- lit->len = n;
- return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
-
- p = thearch.gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- p->to.type = TYPE_ADDR;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(x);
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
deleted file mode 100644
index 8e670bdc13..0000000000
--- a/src/cmd/gc/order.c
+++ /dev/null
@@ -1,1164 +0,0 @@
-// 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.
-
-// Rewrite tree to use separate statements to enforce
-// order of evaluation. Makes walk easier, because it
-// can (after this runs) reorder at will within an expression.
-//
-// Rewrite x op= y into x = x op y.
-//
-// Introduce temporaries as needed by runtime routines.
-// For example, the map runtime routines take the map key
-// by reference, so make sure all map keys are addressable
-// by copying them to temporaries as needed.
-// The same is true for channel operations.
-//
-// Arrange that map index expressions only appear in direct
-// assignments x = m[k] or m[k] = x, never in larger expressions.
-//
-// Arrange that receive expressions only appear in direct assignments
-// x = <-c or as standalone statements <-c, never in larger expressions.
-
-// TODO(rsc): The temporary introduction during multiple assignments
-// should be moved into this file, so that the temporaries can be cleaned
-// and so that conversions implicit in the OAS2FUNC and OAS2RECV
-// nodes can be made explicit and then have their temporaries cleaned.
-
-// TODO(rsc): Goto and multilevel break/continue can jump over
-// inserted VARKILL annotations. Work out a way to handle these.
-// The current implementation is safe, in that it will execute correctly.
-// But it won't reuse temporaries as aggressively as it might, and
-// it can result in unnecessary zeroing of those variables in the function
-// prologue.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// Order holds state during the ordering process.
-typedef struct Order Order;
-struct Order
-{
- NodeList *out; // list of generated statements
- NodeList *temp; // head of stack of temporary variables
- NodeList *free; // free list of NodeList* structs (for use in temp)
-};
-
-static void orderstmt(Node*, Order*);
-static void orderstmtlist(NodeList*, Order*);
-static void orderblock(NodeList **l);
-static void orderexpr(Node**, Order*);
-static void orderexprinplace(Node**, Order*);
-static void orderexprlist(NodeList*, Order*);
-static void orderexprlistinplace(NodeList*, Order*);
-
-// Order rewrites fn->nbody to apply the ordering constraints
-// described in the comment at the top of the file.
-void
-order(Node *fn)
-{
- char s[50];
-
- if(debug['W'] > 1) {
- snprint(s, sizeof(s), "\nbefore order %S", fn->nname->sym);
- dumplist(s, fn->nbody);
- }
-
- orderblock(&fn->nbody);
-}
-
-// Ordertemp allocates a new temporary with the given type,
-// pushes it onto the temp stack, and returns it.
-// If clear is true, ordertemp emits code to zero the temporary.
-static Node*
-ordertemp(Type *t, Order *order, int clear)
-{
- Node *var, *a;
- NodeList *l;
-
- var = temp(t);
- if(clear) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- order->out = list(order->out, a);
- }
- if((l = order->free) == nil)
- l = mal(sizeof *l);
- order->free = l->next;
- l->next = order->temp;
- l->n = var;
- order->temp = l;
- return var;
-}
-
-// Ordercopyexpr behaves like ordertemp but also emits
-// code to initialize the temporary to the value n.
-//
-// The clear argument is provided for use when the evaluation
-// of tmp = n turns into a function call that is passed a pointer
-// to the temporary as the output space. If the call blocks before
-// tmp has been written, the garbage collector will still treat the
-// temporary as live, so we must zero it before entering that call.
-// Today, this only happens for channel receive operations.
-// (The other candidate would be map access, but map access
-// returns a pointer to the result data instead of taking a pointer
-// to be filled in.)
-static Node*
-ordercopyexpr(Node *n, Type *t, Order *order, int clear)
-{
- Node *a, *var;
-
- var = ordertemp(t, order, clear);
- a = nod(OAS, var, n);
- typecheck(&a, Etop);
- order->out = list(order->out, a);
- return var;
-}
-
-// Ordercheapexpr returns a cheap version of n.
-// The definition of cheap is that n is a variable or constant.
-// If not, ordercheapexpr allocates a new tmp, emits tmp = n,
-// and then returns tmp.
-static Node*
-ordercheapexpr(Node *n, Order *order)
-{
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
- }
- return ordercopyexpr(n, n->type, order, 0);
-}
-
-// Ordersafeexpr returns a safe version of n.
-// The definition of safe is that n can appear multiple times
-// without violating the semantics of the original program,
-// and that assigning to the safe version has the same effect
-// as assigning to the original n.
-//
-// The intended use is to apply to x when rewriting x += y into x = x + y.
-static Node*
-ordersafeexpr(Node *n, Order *order)
-{
- Node *l, *r, *a;
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
-
- case ODOT:
- l = ordersafeexpr(n->left, order);
- if(l == n->left)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->orig = a;
- a->left = l;
- typecheck(&a, Erv);
- return a;
-
- case ODOTPTR:
- case OIND:
- l = ordercheapexpr(n->left, order);
- if(l == n->left)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->orig = a;
- a->left = l;
- typecheck(&a, Erv);
- return a;
-
- case OINDEX:
- case OINDEXMAP:
- if(isfixedarray(n->left->type))
- l = ordersafeexpr(n->left, order);
- else
- l = ordercheapexpr(n->left, order);
- r = ordercheapexpr(n->right, order);
- if(l == n->left && r == n->right)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->orig = a;
- a->left = l;
- a->right = r;
- typecheck(&a, Erv);
- return a;
- }
-
- fatal("ordersafeexpr %O", n->op);
- return nil; // not reached
-}
-
-// Istemp reports whether n is a temporary variable.
-static int
-istemp(Node *n)
-{
- if(n->op != ONAME)
- return 0;
- return strncmp(n->sym->name, "autotmp_", 8) == 0;
-}
-
-// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
-// Taking the address of a variable makes the liveness and optimization analyses
-// lose track of where the variable's lifetime ends. To avoid hurting the analyses
-// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
-// because we emit explicit VARKILL instructions marking the end of those
-// temporaries' lifetimes.
-static int
-isaddrokay(Node *n)
-{
- return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n));
-}
-
-// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
-// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
-// tmp = *np, and then sets *np to the tmp variable.
-static void
-orderaddrtemp(Node **np, Order *order)
-{
- Node *n;
-
- n = *np;
- if(isaddrokay(n))
- return;
- *np = ordercopyexpr(n, n->type, order, 0);
-}
-
-// Marktemp returns the top of the temporary variable stack.
-static NodeList*
-marktemp(Order *order)
-{
- return order->temp;
-}
-
-// Poptemp pops temporaries off the stack until reaching the mark,
-// which must have been returned by marktemp.
-static void
-poptemp(NodeList *mark, Order *order)
-{
- NodeList *l;
-
- while((l = order->temp) != mark) {
- order->temp = l->next;
- l->next = order->free;
- order->free = l;
- }
-}
-
-// Cleantempnopop emits to *out VARKILL instructions for each temporary
-// above the mark on the temporary stack, but it does not pop them
-// from the stack.
-static void
-cleantempnopop(NodeList *mark, Order *order, NodeList **out)
-{
- NodeList *l;
- Node *kill;
-
- for(l=order->temp; l != mark; l=l->next) {
- kill = nod(OVARKILL, l->n, N);
- typecheck(&kill, Etop);
- *out = list(*out, kill);
- }
-}
-
-// Cleantemp emits VARKILL instructions for each temporary above the
-// mark on the temporary stack and removes them from the stack.
-static void
-cleantemp(NodeList *top, Order *order)
-{
- cleantempnopop(top, order, &order->out);
- poptemp(top, order);
-}
-
-// Orderstmtlist orders each of the statements in the list.
-static void
-orderstmtlist(NodeList *l, Order *order)
-{
- for(; l; l=l->next)
- orderstmt(l->n, order);
-}
-
-// Orderblock orders the block of statements *l onto a new list,
-// and then replaces *l with that list.
-static void
-orderblock(NodeList **l)
-{
- Order order;
- NodeList *mark;
-
- memset(&order, 0, sizeof order);
- mark = marktemp(&order);
- orderstmtlist(*l, &order);
- cleantemp(mark, &order);
- *l = order.out;
-}
-
-// Orderexprinplace orders the side effects in *np and
-// leaves them as the init list of the final *np.
-static void
-orderexprinplace(Node **np, Order *outer)
-{
- Node *n;
- NodeList **lp;
- Order order;
-
- n = *np;
- memset(&order, 0, sizeof order);
- orderexpr(&n, &order);
- addinit(&n, order.out);
-
- // insert new temporaries from order
- // at head of outer list.
- lp = &order.temp;
- while(*lp != nil)
- lp = &(*lp)->next;
- *lp = outer->temp;
- outer->temp = order.temp;
-
- *np = n;
-}
-
-// Orderstmtinplace orders the side effects of the single statement *np
-// and replaces it with the resulting statement list.
-void
-orderstmtinplace(Node **np)
-{
- Node *n;
- Order order;
- NodeList *mark;
-
- n = *np;
- memset(&order, 0, sizeof order);
- mark = marktemp(&order);
- orderstmt(n, &order);
- cleantemp(mark, &order);
- *np = liststmt(order.out);
-}
-
-// Orderinit moves n's init list to order->out.
-static void
-orderinit(Node *n, Order *order)
-{
- orderstmtlist(n->ninit, order);
- n->ninit = nil;
-}
-
-// Ismulticall reports whether the list l is f() for a multi-value function.
-// Such an f() could appear as the lone argument to a multi-arg function.
-static int
-ismulticall(NodeList *l)
-{
- Node *n;
-
- // one arg only
- if(l == nil || l->next != nil)
- return 0;
- n = l->n;
-
- // must be call
- switch(n->op) {
- default:
- return 0;
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- break;
- }
-
- // call must return multiple values
- return n->left->type->outtuple > 1;
-}
-
-// Copyret emits t1, t2, ... = n, where n is a function call,
-// and then returns the list t1, t2, ....
-static NodeList*
-copyret(Node *n, Order *order)
-{
- Type *t;
- Node *tmp, *as;
- NodeList *l1, *l2;
- Iter tl;
-
- if(n->type->etype != TSTRUCT || !n->type->funarg)
- fatal("copyret %T %d", n->type, n->left->type->outtuple);
-
- l1 = nil;
- l2 = nil;
- for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
- tmp = temp(t->type);
- l1 = list(l1, tmp);
- l2 = list(l2, tmp);
- }
-
- as = nod(OAS2, N, N);
- as->list = l1;
- as->rlist = list1(n);
- typecheck(&as, Etop);
- orderstmt(as, order);
-
- return l2;
-}
-
-// Ordercallargs orders the list of call arguments *l.
-static void
-ordercallargs(NodeList **l, Order *order)
-{
- if(ismulticall(*l)) {
- // return f() where f() is multiple values.
- *l = copyret((*l)->n, order);
- } else {
- orderexprlist(*l, order);
- }
-}
-
-// Ordercall orders the call expression n.
-// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-static void
-ordercall(Node *n, Order *order)
-{
- orderexpr(&n->left, order);
- orderexpr(&n->right, order); // ODDDARG temp
- ordercallargs(&n->list, order);
-}
-
-// Ordermapassign appends n to order->out, introducing temporaries
-// to make sure that all map assignments have the form m[k] = x,
-// where x is adressable.
-// (Orderexpr has already been called on n, so we know k is addressable.)
-//
-// If n is m[k] = x where x is not addressable, the rewrite is:
-// tmp = x
-// m[k] = tmp
-//
-// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
-// t1 = m
-// t2 = k
-// ...., t3, ... = x
-// t1[t2] = t3
-//
-// The temporaries t1, t2 are needed in case the ... being assigned
-// contain m or k. They are usually unnecessary, but in the unnecessary
-// cases they are also typically registerizable, so not much harm done.
-// And this only applies to the multiple-assignment form.
-// We could do a more precise analysis if needed, like in walk.c.
-//
-// Ordermapassign also inserts these temporaries if needed for
-// calling writebarrierfat with a pointer to n->right.
-static void
-ordermapassign(Node *n, Order *order)
-{
- Node *m, *a;
- NodeList *l;
- NodeList *post;
-
- switch(n->op) {
- default:
- fatal("ordermapassign %O", n->op);
-
- case OAS:
- order->out = list(order->out, n);
- // We call writebarrierfat only for values > 4 pointers long. See walk.c.
- if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) {
- m = n->left;
- n->left = ordertemp(m->type, order, 0);
- a = nod(OAS, m, n->left);
- typecheck(&a, Etop);
- order->out = list(order->out, a);
- }
- break;
-
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2MAPR:
- case OAS2FUNC:
- post = nil;
- for(l=n->list; l != nil; l=l->next) {
- if(l->n->op == OINDEXMAP) {
- m = l->n;
- if(!istemp(m->left))
- m->left = ordercopyexpr(m->left, m->left->type, order, 0);
- if(!istemp(m->right))
- m->right = ordercopyexpr(m->right, m->right->type, order, 0);
- l->n = ordertemp(m->type, order, 0);
- a = nod(OAS, m, l->n);
- typecheck(&a, Etop);
- post = list(post, a);
- }
- }
- order->out = list(order->out, n);
- order->out = concat(order->out, post);
- break;
- }
-}
-
-// Orderstmt orders the statement n, appending to order->out.
-// Temporaries created during the statement are cleaned
-// up using VARKILL instructions as possible.
-static void
-orderstmt(Node *n, Order *order)
-{
- int lno;
- NodeList *l, *t, *t1;
- Node *r, *tmp1, *tmp2, **np;
- Type *ch, *typ;
-
- if(n == N)
- return;
-
- lno = setlineno(n);
-
- orderinit(n, order);
-
- switch(n->op) {
- default:
- fatal("orderstmt %O", n->op);
-
- case OVARKILL:
- order->out = list(order->out, n);
- break;
-
- case OAS:
- case OAS2:
- case OCLOSE:
- case OCOPY:
- case OPRINT:
- case OPRINTN:
- case ORECOVER:
- case ORECV:
- t = marktemp(order);
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- orderexprlist(n->list, order);
- orderexprlist(n->rlist, order);
- switch(n->op) {
- case OAS:
- case OAS2:
- case OAS2DOTTYPE:
- ordermapassign(n, order);
- break;
- default:
- order->out = list(order->out, n);
- break;
- }
- cleantemp(t, order);
- break;
-
- case OASOP:
- // Special: rewrite l op= r into l = l op r.
- // This simplies quite a few operations;
- // most important is that it lets us separate
- // out map read from map write when l is
- // a map index expression.
- t = marktemp(order);
- orderexpr(&n->left, order);
- n->left = ordersafeexpr(n->left, order);
- tmp1 = treecopy(n->left);
- if(tmp1->op == OINDEXMAP)
- tmp1->etype = 0; // now an rvalue not an lvalue
- tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0);
- n->right = nod(n->etype, tmp1, n->right);
- typecheck(&n->right, Erv);
- orderexpr(&n->right, order);
- n->etype = 0;
- n->op = OAS;
- ordermapassign(n, order);
- cleantemp(t, order);
- break;
-
- case OAS2MAPR:
- // Special: make sure key is addressable,
- // and make sure OINDEXMAP is not copied out.
- t = marktemp(order);
- orderexprlist(n->list, order);
- r = n->rlist->n;
- orderexpr(&r->left, order);
- orderexpr(&r->right, order);
- // See case OINDEXMAP below.
- if(r->right->op == OARRAYBYTESTR)
- r->right->op = OARRAYBYTESTRTMP;
- orderaddrtemp(&r->right, order);
- ordermapassign(n, order);
- cleantemp(t, order);
- break;
-
- case OAS2FUNC:
- // Special: avoid copy of func call n->rlist->n.
- t = marktemp(order);
- orderexprlist(n->list, order);
- ordercall(n->rlist->n, order);
- ordermapassign(n, order);
- cleantemp(t, order);
- break;
-
- case OAS2DOTTYPE:
- // Special: use temporary variables to hold result,
- // so that assertI2Tetc can take address of temporary.
- // No temporary for blank assignment.
- t = marktemp(order);
- orderexprlist(n->list, order);
- orderexpr(&n->rlist->n->left, order); // i in i.(T)
- if(isblank(n->list->n))
- order->out = list(order->out, n);
- else {
- typ = n->rlist->n->type;
- tmp1 = ordertemp(typ, order, haspointers(typ));
- order->out = list(order->out, n);
- r = nod(OAS, n->list->n, tmp1);
- typecheck(&r, Etop);
- ordermapassign(r, order);
- n->list = list(list1(tmp1), n->list->next->n);
- }
- cleantemp(t, order);
- break;
-
- case OAS2RECV:
- // Special: use temporary variables to hold result,
- // so that chanrecv can take address of temporary.
- t = marktemp(order);
- orderexprlist(n->list, order);
- orderexpr(&n->rlist->n->left, order); // arg to recv
- ch = n->rlist->n->left->type;
- tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
- if(!isblank(n->list->next->n))
- tmp2 = ordertemp(n->list->next->n->type, order, 0);
- else
- tmp2 = ordertemp(types[TBOOL], order, 0);
- order->out = list(order->out, n);
- r = nod(OAS, n->list->n, tmp1);
- typecheck(&r, Etop);
- ordermapassign(r, order);
- r = nod(OAS, n->list->next->n, tmp2);
- typecheck(&r, Etop);
- ordermapassign(r, order);
- n->list = list(list1(tmp1), tmp2);
- cleantemp(t, order);
- break;
-
- case OBLOCK:
- case OEMPTY:
- // Special: does not save n onto out.
- orderstmtlist(n->list, order);
- break;
-
- case OBREAK:
- case OCONTINUE:
- case ODCL:
- case ODCLCONST:
- case ODCLTYPE:
- case OFALL:
- case OXFALL:
- case OGOTO:
- case OLABEL:
- case ORETJMP:
- // Special: n->left is not an expression; save as is.
- order->out = list(order->out, n);
- break;
-
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- // Special: handle call arguments.
- t = marktemp(order);
- ordercall(n, order);
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case ODEFER:
- case OPROC:
- // Special: order arguments to inner call but not call itself.
- t = marktemp(order);
- switch(n->left->op) {
- case ODELETE:
- // Delete will take the address of the key.
- // Copy key into new temp and do not clean it
- // (it persists beyond the statement).
- orderexprlist(n->left->list, order);
- t1 = marktemp(order);
- np = &n->left->list->next->n; // map key
- *np = ordercopyexpr(*np, (*np)->type, order, 0);
- poptemp(t1, order);
- break;
- default:
- ordercall(n->left, order);
- break;
- }
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case ODELETE:
- t = marktemp(order);
- orderexpr(&n->list->n, order);
- orderexpr(&n->list->next->n, order);
- orderaddrtemp(&n->list->next->n, order); // map key
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case OFOR:
- // Clean temporaries from condition evaluation at
- // beginning of loop body and after for statement.
- t = marktemp(order);
- orderexprinplace(&n->ntest, order);
- l = nil;
- cleantempnopop(t, order, &l);
- n->nbody = concat(l, n->nbody);
- orderblock(&n->nbody);
- orderstmtinplace(&n->nincr);
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case OIF:
- // Clean temporaries from condition at
- // beginning of both branches.
- t = marktemp(order);
- orderexprinplace(&n->ntest, order);
- l = nil;
- cleantempnopop(t, order, &l);
- n->nbody = concat(l, n->nbody);
- l = nil;
- cleantempnopop(t, order, &l);
- n->nelse = concat(l, n->nelse);
- poptemp(t, order);
- orderblock(&n->nbody);
- orderblock(&n->nelse);
- order->out = list(order->out, n);
- break;
-
- case OPANIC:
- // Special: argument will be converted to interface using convT2E
- // so make sure it is an addressable temporary.
- t = marktemp(order);
- orderexpr(&n->left, order);
- if(!isinter(n->left->type))
- orderaddrtemp(&n->left, order);
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case ORANGE:
- // n->right is the expression being ranged over.
- // order it, and then make a copy if we need one.
- // We almost always do, to ensure that we don't
- // see any value changes made during the loop.
- // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
- // The exception is ranging over an array value (not a slice, not a pointer to array),
- // which must make a copy to avoid seeing updates made during
- // the range body. Ranging over an array value is uncommon though.
- t = marktemp(order);
- orderexpr(&n->right, order);
- switch(n->type->etype) {
- default:
- fatal("orderstmt range %T", n->type);
- case TARRAY:
- // Mark []byte(str) range expression to reuse string backing storage.
- // It is safe because the storage cannot be mutated.
- if(n->right->op == OSTRARRAYBYTE)
- n->right->op = OSTRARRAYBYTETMP;
- if(count(n->list) < 2 || isblank(n->list->next->n)) {
- // for i := range x will only use x once, to compute len(x).
- // No need to copy it.
- break;
- }
- // fall through
- case TCHAN:
- case TSTRING:
- // chan, string, slice, array ranges use value multiple times.
- // make copy.
- r = n->right;
- if(r->type->etype == TSTRING && r->type != types[TSTRING]) {
- r = nod(OCONV, r, N);
- r->type = types[TSTRING];
- typecheck(&r, Erv);
- }
- n->right = ordercopyexpr(r, r->type, order, 0);
- break;
- case TMAP:
- // copy the map value in case it is a map literal.
- // TODO(rsc): Make tmp = literal expressions reuse tmp.
- // For maps tmp is just one word so it hardly matters.
- r = n->right;
- n->right = ordercopyexpr(r, r->type, order, 0);
- // n->alloc is the temp for the iterator.
- n->alloc = ordertemp(types[TUINT8], order, 1);
- break;
- }
- for(l=n->list; l; l=l->next)
- orderexprinplace(&l->n, order);
- orderblock(&n->nbody);
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case ORETURN:
- ordercallargs(&n->list, order);
- order->out = list(order->out, n);
- break;
-
- case OSELECT:
- // Special: clean case temporaries in each block entry.
- // Select must enter one of its blocks, so there is no
- // need for a cleaning at the end.
- // Doubly special: evaluation order for select is stricter
- // than ordinary expressions. Even something like p.c
- // has to be hoisted into a temporary, so that it cannot be
- // reordered after the channel evaluation for a different
- // case (if p were nil, then the timing of the fault would
- // give this away).
- t = marktemp(order);
- for(l=n->list; l; l=l->next) {
- if(l->n->op != OXCASE)
- fatal("order select case %O", l->n->op);
- r = l->n->left;
- setlineno(l->n);
- // Append any new body prologue to ninit.
- // The next loop will insert ninit into nbody.
- if(l->n->ninit != nil)
- fatal("order select ninit");
- if(r != nil) {
- switch(r->op) {
- default:
- yyerror("unknown op in select %O", r->op);
- dump("select case", r);
- break;
-
- case OSELRECV:
- case OSELRECV2:
- // If this is case x := <-ch or case x, y := <-ch, the case has
- // the ODCL nodes to declare x and y. We want to delay that
- // declaration (and possible allocation) until inside the case body.
- // Delete the ODCL nodes here and recreate them inside the body below.
- if(r->colas) {
- t = r->ninit;
- if(t != nil && t->n->op == ODCL && t->n->left == r->left)
- t = t->next;
- if(t != nil && t->n->op == ODCL && t->n->left == r->ntest)
- t = t->next;
- if(t == nil)
- r->ninit = nil;
- }
- if(r->ninit != nil) {
- yyerror("ninit on select recv");
- dumplist("ninit", r->ninit);
- }
- // case x = <-c
- // case x, ok = <-c
- // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
- // r->left == N means 'case <-c'.
- // c is always evaluated; x and ok are only evaluated when assigned.
- orderexpr(&r->right->left, order);
- if(r->right->left->op != ONAME)
- r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0);
-
- // Introduce temporary for receive and move actual copy into case body.
- // avoids problems with target being addressed, as usual.
- // NOTE: If we wanted to be clever, we could arrange for just one
- // temporary per distinct type, sharing the temp among all receives
- // with that temp. Similarly one ok bool could be shared among all
- // the x,ok receives. Not worth doing until there's a clear need.
- if(r->left != N && isblank(r->left))
- r->left = N;
- if(r->left != N) {
- // use channel element type for temporary to avoid conversions,
- // such as in case interfacevalue = <-intchan.
- // the conversion happens in the OAS instead.
- tmp1 = r->left;
- if(r->colas) {
- tmp2 = nod(ODCL, tmp1, N);
- typecheck(&tmp2, Etop);
- l->n->ninit = list(l->n->ninit, tmp2);
- }
- r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type));
- tmp2 = nod(OAS, tmp1, r->left);
- typecheck(&tmp2, Etop);
- l->n->ninit = list(l->n->ninit, tmp2);
- }
- if(r->ntest != N && isblank(r->ntest))
- r->ntest = N;
- if(r->ntest != N) {
- tmp1 = r->ntest;
- if(r->colas) {
- tmp2 = nod(ODCL, tmp1, N);
- typecheck(&tmp2, Etop);
- l->n->ninit = list(l->n->ninit, tmp2);
- }
- r->ntest = ordertemp(tmp1->type, order, 0);
- tmp2 = nod(OAS, tmp1, r->ntest);
- typecheck(&tmp2, Etop);
- l->n->ninit = list(l->n->ninit, tmp2);
- }
- orderblock(&l->n->ninit);
- break;
-
- case OSEND:
- if(r->ninit != nil) {
- yyerror("ninit on select send");
- dumplist("ninit", r->ninit);
- }
- // case c <- x
- // r->left is c, r->right is x, both are always evaluated.
- orderexpr(&r->left, order);
- if(!istemp(r->left))
- r->left = ordercopyexpr(r->left, r->left->type, order, 0);
- orderexpr(&r->right, order);
- if(!istemp(r->right))
- r->right = ordercopyexpr(r->right, r->right->type, order, 0);
- break;
- }
- }
- orderblock(&l->n->nbody);
- }
- // Now that we have accumulated all the temporaries, clean them.
- // Also insert any ninit queued during the previous loop.
- // (The temporary cleaning must follow that ninit work.)
- for(l=n->list; l; l=l->next) {
- cleantempnopop(t, order, &l->n->ninit);
- l->n->nbody = concat(l->n->ninit, l->n->nbody);
- l->n->ninit = nil;
- }
- order->out = list(order->out, n);
- poptemp(t, order);
- break;
-
- case OSEND:
- // Special: value being sent is passed as a pointer; make it addressable.
- t = marktemp(order);
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- orderaddrtemp(&n->right, order);
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
-
- case OSWITCH:
- // TODO(rsc): Clean temporaries more aggressively.
- // Note that because walkswitch will rewrite some of the
- // switch into a binary search, this is not as easy as it looks.
- // (If we ran that code here we could invoke orderstmt on
- // the if-else chain instead.)
- // For now just clean all the temporaries at the end.
- // In practice that's fine.
- t = marktemp(order);
- orderexpr(&n->ntest, order);
- for(l=n->list; l; l=l->next) {
- if(l->n->op != OXCASE)
- fatal("order switch case %O", l->n->op);
- orderexprlistinplace(l->n->list, order);
- orderblock(&l->n->nbody);
- }
- order->out = list(order->out, n);
- cleantemp(t, order);
- break;
- }
-
- lineno = lno;
-}
-
-// Orderexprlist orders the expression list l into order.
-static void
-orderexprlist(NodeList *l, Order *order)
-{
- for(; l; l=l->next)
- orderexpr(&l->n, order);
-}
-
-// Orderexprlist orders the expression list l but saves
-// the side effects on the individual expression ninit lists.
-static void
-orderexprlistinplace(NodeList *l, Order *order)
-{
- for(; l; l=l->next)
- orderexprinplace(&l->n, order);
-}
-
-// Orderexpr orders a single expression, appending side
-// effects to order->out as needed.
-static void
-orderexpr(Node **np, Order *order)
-{
- Node *n;
- NodeList *mark, *l;
- Type *t;
- int lno, haslit, hasbyte;
-
- n = *np;
- if(n == N)
- return;
-
- lno = setlineno(n);
- orderinit(n, order);
-
- switch(n->op) {
- default:
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- orderexprlist(n->list, order);
- orderexprlist(n->rlist, order);
- break;
-
- case OADDSTR:
- // Addition of strings turns into a function call.
- // Allocate a temporary to hold the strings.
- // Fewer than 5 strings use direct runtime helpers.
- orderexprlist(n->list, order);
- if(count(n->list) > 5) {
- t = typ(TARRAY);
- t->bound = count(n->list);
- t->type = types[TSTRING];
- n->alloc = ordertemp(t, order, 0);
- }
-
- // Mark string(byteSlice) arguments to reuse byteSlice backing
- // buffer during conversion. String concatenation does not
- // memorize the strings for later use, so it is safe.
- // However, we can do it only if there is at least one non-empty string literal.
- // Otherwise if all other arguments are empty strings,
- // concatstrings will return the reference to the temp string
- // to the caller.
- hasbyte = 0;
- haslit = 0;
- for(l=n->list; l != nil; l=l->next) {
- hasbyte |= l->n->op == OARRAYBYTESTR;
- haslit |= l->n->op == OLITERAL && l->n->val.u.sval->len != 0;
- }
- if(haslit && hasbyte) {
- for(l=n->list; l != nil; l=l->next) {
- if(l->n->op == OARRAYBYTESTR)
- l->n->op = OARRAYBYTESTRTMP;
- }
- }
- break;
-
- case OCMPSTR:
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- // Mark string(byteSlice) arguments to reuse byteSlice backing
- // buffer during conversion. String comparison does not
- // memorize the strings for later use, so it is safe.
- if(n->left->op == OARRAYBYTESTR)
- n->left->op = OARRAYBYTESTRTMP;
- if(n->right->op == OARRAYBYTESTR)
- n->right->op = OARRAYBYTESTRTMP;
- break;
-
- case OINDEXMAP:
- // key must be addressable
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
-
- // For x = m[string(k)] where k is []byte, the allocation of
- // backing bytes for the string can be avoided by reusing
- // the []byte backing array. This is a special case that it
- // would be nice to handle more generally, but because
- // there are no []byte-keyed maps, this specific case comes
- // up in important cases in practice. See issue 3512.
- // Nothing can change the []byte we are not copying before
- // the map index, because the map access is going to
- // be forced to happen immediately following this
- // conversion (by the ordercopyexpr a few lines below).
- if(n->etype == 0 && n->right->op == OARRAYBYTESTR)
- n->right->op = OARRAYBYTESTRTMP;
-
- orderaddrtemp(&n->right, order);
- if(n->etype == 0) {
- // use of value (not being assigned);
- // make copy in temporary.
- n = ordercopyexpr(n, n->type, order, 0);
- }
- break;
-
- case OCONVIFACE:
- // concrete type (not interface) argument must be addressable
- // temporary to pass to runtime.
- orderexpr(&n->left, order);
- if(!isinter(n->left->type))
- orderaddrtemp(&n->left, order);
- break;
-
- case OANDAND:
- case OOROR:
- mark = marktemp(order);
- orderexpr(&n->left, order);
- // Clean temporaries from first branch at beginning of second.
- // Leave them on the stack so that they can be killed in the outer
- // context in case the short circuit is taken.
- l = nil;
- cleantempnopop(mark, order, &l);
- n->right->ninit = concat(l, n->right->ninit);
- orderexprinplace(&n->right, order);
- break;
-
- case OAPPEND:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- case OCAP:
- case OCOMPLEX:
- case OCOPY:
- case OIMAG:
- case OLEN:
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case ONEW:
- case OREAL:
- case ORECOVER:
- ordercall(n, order);
- n = ordercopyexpr(n, n->type, order, 0);
- break;
-
- case OCLOSURE:
- if(n->noescape && n->cvars != nil)
- n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
- break;
-
- case OARRAYLIT:
- case OCALLPART:
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- orderexprlist(n->list, order);
- orderexprlist(n->rlist, order);
- if(n->noescape)
- n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
- break;
-
- case ODDDARG:
- if(n->noescape) {
- // The ddd argument does not live beyond the call it is created for.
- // Allocate a temporary that will be cleaned up when this statement
- // completes. We could be more aggressive and try to arrange for it
- // to be cleaned up when the call completes.
- n->alloc = ordertemp(n->type->type, order, 0);
- }
- break;
-
- case ORECV:
- case ODOTTYPE:
- orderexpr(&n->left, order);
- n = ordercopyexpr(n, n->type, order, 1);
- break;
-
- case OEQ:
- case ONE:
- orderexpr(&n->left, order);
- orderexpr(&n->right, order);
- t = n->left->type;
- if(t->etype == TSTRUCT || isfixedarray(t)) {
- // for complex comparisons, we need both args to be
- // addressable so we can pass them to the runtime.
- orderaddrtemp(&n->left, order);
- orderaddrtemp(&n->right, order);
- }
- break;
- }
-
- lineno = lno;
-
- *np = n;
-}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
deleted file mode 100644
index 16a869181d..0000000000
--- a/src/cmd/gc/pgen.c
+++ /dev/null
@@ -1,547 +0,0 @@
-// 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.
-
-// "Portable" code generation.
-// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
-// Must code to the intersection of the three back ends.
-
-#include <u.h>
-#include <libc.h>
-#include "md5.h"
-#include "go.h"
-//#include "opt.h"
-#include "../../runtime/funcdata.h"
-#include "../ld/textflag.h"
-
-static void allocauto(Prog* p);
-static void emitptrargsmap(void);
-
-static Sym*
-makefuncdatasym(char *namefmt, int64 funcdatakind)
-{
- Node nod;
- Node *pnod;
- Sym *sym;
- static int32 nsym;
-
- snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
- sym = lookup(namebuf);
- pnod = newname(sym);
- pnod->class = PEXTERN;
- nodconst(&nod, types[TINT32], funcdatakind);
- thearch.gins(AFUNCDATA, &nod, pnod);
- return sym;
-}
-
-// gvardef inserts a VARDEF for n into the instruction stream.
-// VARDEF is an annotation for the liveness analysis, marking a place
-// where a complete initialization (definition) of a variable begins.
-// Since the liveness analysis can see initialization of single-word
-// variables quite easy, gvardef is usually only called for multi-word
-// or 'fat' variables, those satisfying isfat(n->type).
-// However, gvardef is also called when a non-fat variable is initialized
-// via a block move; the only time this happens is when you have
-// return f()
-// for a function with multiple return values exactly matching the return
-// types of the current function.
-//
-// A 'VARDEF x' annotation in the instruction stream tells the liveness
-// analysis to behave as though the variable x is being initialized at that
-// point in the instruction stream. The VARDEF must appear before the
-// actual (multi-instruction) initialization, and it must also appear after
-// any uses of the previous value, if any. For example, if compiling:
-//
-// x = x[1:]
-//
-// it is important to generate code like:
-//
-// base, len, cap = pieces of x[1:]
-// VARDEF x
-// x = {base, len, cap}
-//
-// If instead the generated code looked like:
-//
-// VARDEF x
-// base, len, cap = pieces of x[1:]
-// x = {base, len, cap}
-//
-// then the liveness analysis would decide the previous value of x was
-// unnecessary even though it is about to be used by the x[1:] computation.
-// Similarly, if the generated code looked like:
-//
-// base, len, cap = pieces of x[1:]
-// x = {base, len, cap}
-// VARDEF x
-//
-// then the liveness analysis will not preserve the new value of x, because
-// the VARDEF appears to have "overwritten" it.
-//
-// VARDEF is a bit of a kludge to work around the fact that the instruction
-// stream is working on single-word values but the liveness analysis
-// wants to work on individual variables, which might be multi-word
-// aggregates. It might make sense at some point to look into letting
-// the liveness analysis work on single-word values as well, although
-// there are complications around interface values, slices, and strings,
-// all of which cannot be treated as individual words.
-//
-// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
-// even if its address has been taken. That is, a VARKILL annotation asserts
-// that its argument is certainly dead, for use when the liveness analysis
-// would not otherwise be able to deduce that fact.
-
-static void
-gvardefx(Node *n, int as)
-{
- if(n == N)
- fatal("gvardef nil");
- if(n->op != ONAME) {
- yyerror("gvardef %#O; %N", n->op, n);
- return;
- }
- switch(n->class) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- thearch.gins(as, N, n);
- }
-}
-
-void
-gvardef(Node *n)
-{
- gvardefx(n, AVARDEF);
-}
-
-void
-gvarkill(Node *n)
-{
- gvardefx(n, AVARKILL);
-}
-
-static void
-removevardef(Prog *firstp)
-{
- Prog *p;
-
- for(p = firstp; p != P; p = p->link) {
- while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
- p->to.u.branch = p->to.u.branch->link;
- }
-}
-
-static void
-gcsymdup(Sym *s)
-{
- LSym *ls;
- uint64 lo, hi;
-
- ls = linksym(s);
- if(ls->nr > 0)
- fatal("cannot rosymdup %s with relocations", ls->name);
- MD5 d;
- md5reset(&d);
- md5write(&d, ls->p, ls->np);
- lo = md5sum(&d, &hi);
- ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
- ls->dupok = 1;
-}
-
-void
-compile(Node *fn)
-{
- Plist *pl;
- Node nod1, *n;
- Prog *ptxt, *p;
- int32 lno;
- Type *t;
- Iter save;
- vlong oldstksize;
- NodeList *l;
- Node *nam;
- Sym *gcargs;
- Sym *gclocals;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(fn->nbody == nil) {
- if(pure_go || strncmp(fn->nname->sym->name, "init.", 5) == 0) {
- yyerror("missing function body", fn);
- goto ret;
- }
- if(debug['A'])
- goto ret;
- emitptrargsmap();
- goto ret;
- }
-
- saveerrors();
-
- // set up domain for labels
- clearlabels();
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N) {
- n = nod(OAS, t->nname, N);
- typecheck(&n, Etop);
- curfn->nbody = concat(list1(n), curfn->nbody);
- }
- t = structnext(&save);
- }
- }
-
- order(curfn);
- if(nerrors != 0)
- goto ret;
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0)
- goto ret;
- if(flag_race)
- racewalk(curfn);
- if(nerrors != 0)
- goto ret;
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = linksym(curfn->nname->sym);
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- nam = curfn->nname;
- if(isblank(nam))
- nam = N;
- ptxt = thearch.gins(ATEXT, nam, &nod1);
- if(fn->dupok)
- ptxt->from3.offset |= DUPOK;
- if(fn->wrapper)
- ptxt->from3.offset |= WRAPPER;
- if(fn->needctxt)
- ptxt->from3.offset |= NEEDCTXT;
- if(fn->nosplit)
- ptxt->from3.offset |= NOSPLIT;
-
- // Clumsy but important.
- // See test/recover.go for test cases and src/reflect/value.go
- // for the actual functions being considered.
- if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
- if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
- ptxt->from3.offset |= WRAPPER;
- }
-
- afunclit(&ptxt->from, curfn->nname);
-
- thearch.ginit();
-
- gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
- gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
-
- for(t=curfn->paramfld; t; t=t->down)
- gtrack(tracksym(t->type));
-
- for(l=fn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME) // might be OTYPE or OLITERAL
- continue;
- switch(n->class) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- nodconst(&nod1, types[TUINTPTR], l->n->type->width);
- p = thearch.gins(ATYPE, l->n, &nod1);
- p->from.gotype = linksym(ngotype(l->n));
- break;
- }
- }
-
- genlist(curfn->enter);
- genlist(curfn->nbody);
- thearch.gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
-
- if(curfn->type->outtuple != 0)
- thearch.ginscall(throwreturn, 0);
-
- thearch.ginit();
- // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
- thearch.cgen_ret(nil);
- if(hasdefer) {
- // deferreturn pretends to have one uintptr argument.
- // Reserve space for it so stack scanner is happy.
- if(maxarg < widthptr)
- maxarg = widthptr;
- }
- thearch.gclean();
- if(nerrors != 0)
- goto ret;
-
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- fixjmp(ptxt);
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- nilopt(ptxt);
- }
- thearch.expandchecks(ptxt);
-
- oldstksize = stksize;
- allocauto(ptxt);
-
- if(0)
- print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
- USED(oldstksize);
-
- setlineno(curfn);
- if((int64)stksize+maxarg > (1ULL<<31)) {
- yyerror("stack frame too large (>2GB)");
- goto ret;
- }
-
- // Emit garbage collection symbols.
- liveness(curfn, ptxt, gcargs, gclocals);
- gcsymdup(gcargs);
- gcsymdup(gclocals);
-
- thearch.defframe(ptxt);
-
- if(debug['f'])
- frame(0);
-
- // Remove leftover instrumentation from the instruction stream.
- removevardef(ptxt);
-ret:
- lineno = lno;
-}
-
-static void
-emitptrargsmap(void)
-{
- int nptr, nbitmap, j, off;
- vlong xoffset;
- Bvec *bv;
- Sym *sym;
-
- sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
-
- nptr = curfn->type->argwid / widthptr;
- bv = bvalloc(nptr*2);
- nbitmap = 1;
- if(curfn->type->outtuple > 0)
- nbitmap = 2;
- off = duint32(sym, 0, nbitmap);
- off = duint32(sym, off, bv->n);
- if(curfn->type->thistuple > 0) {
- xoffset = 0;
- twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
- }
- if(curfn->type->intuple > 0) {
- xoffset = 0;
- twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
- }
- for(j = 0; j < bv->n; j += 32)
- off = duint32(sym, off, bv->b[j/32]);
- if(curfn->type->outtuple > 0) {
- xoffset = 0;
- twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
- for(j = 0; j < bv->n; j += 32)
- off = duint32(sym, off, bv->b[j/32]);
- }
- ggloblsym(sym, off, RODATA);
- free(bv);
-}
-
-// Sort the list of stack variables. Autos after anything else,
-// within autos, unused after used, within used, things with
-// pointers first, zeroed things first, and then decreasing size.
-// Because autos are laid out in decreasing addresses
-// on the stack, pointers first, zeroed things first and decreasing size
-// really means, in memory, things with pointers needing zeroing at
-// the top of the stack and increasing in size.
-// Non-autos sort on offset.
-static int
-cmpstackvar(Node *a, Node *b)
-{
- int ap, bp;
-
- if (a->class != b->class) {
- if(a->class == PAUTO)
- return +1;
- return -1;
- }
- if (a->class != PAUTO) {
- if (a->xoffset < b->xoffset)
- return -1;
- if (a->xoffset > b->xoffset)
- return +1;
- return 0;
- }
- if ((a->used == 0) != (b->used == 0))
- return b->used - a->used;
-
- ap = haspointers(a->type);
- bp = haspointers(b->type);
- if(ap != bp)
- return bp - ap;
-
- ap = a->needzero;
- bp = b->needzero;
- if(ap != bp)
- return bp - ap;
-
- if(a->type->width < b->type->width)
- return +1;
- if(a->type->width > b->type->width)
- return -1;
-
- return strcmp(a->sym->name, b->sym->name);
-}
-
-// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
-static void
-allocauto(Prog* ptxt)
-{
- NodeList *ll;
- Node* n;
- vlong w;
-
- stksize = 0;
- stkptrsize = 0;
-
- if(curfn->dcl == nil)
- return;
-
- // Mark the PAUTO's unused.
- for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if (ll->n->class == PAUTO)
- ll->n->used = 0;
-
- markautoused(ptxt);
-
- listsort(&curfn->dcl, cmpstackvar);
-
- // Unused autos are at the end, chop 'em off.
- ll = curfn->dcl;
- n = ll->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- // No locals used at all
- curfn->dcl = nil;
- fixautoused(ptxt);
- return;
- }
-
- for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
- n = ll->next->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- ll->next = nil;
- curfn->dcl->end = ll;
- break;
- }
- }
-
- // Reassign stack offsets of the locals that are still there.
- for(ll = curfn->dcl; ll != nil; ll=ll->next) {
- n = ll->n;
- if (n->class != PAUTO || n->op != ONAME)
- continue;
-
- dowidth(n->type);
- w = n->type->width;
- if(w >= thearch.MAXWIDTH || w < 0)
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(haspointers(n->type))
- stkptrsize = stksize;
- if(thearch.thechar == '5' || thearch.thechar == '9')
- stksize = rnd(stksize, widthptr);
- if(stksize >= (1ULL<<31)) {
- setlineno(curfn);
- yyerror("stack frame too large (>2GB)");
- }
- n->stkdelta = -stksize - n->xoffset;
- }
- stksize = rnd(stksize, widthreg);
- stkptrsize = rnd(stkptrsize, widthreg);
-
- fixautoused(ptxt);
-
- // The debug information needs accurate offsets on the symbols.
- for(ll = curfn->dcl; ll != nil; ll=ll->next) {
- if (ll->n->class != PAUTO || ll->n->op != ONAME)
- continue;
- ll->n->xoffset += ll->n->stkdelta;
- ll->n->stkdelta = 0;
- }
-}
-
-static void movelargefn(Node*);
-
-void
-movelarge(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- movelargefn(l->n);
-}
-
-static void
-movelargefn(Node *fn)
-{
- NodeList *l;
- Node *n;
-
- for(l=fn->dcl; l != nil; l=l->next) {
- n = l->n;
- if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
- addrescapes(n);
- }
-}
-
-void
-cgen_checknil(Node *n)
-{
- Node reg;
-
- if(disable_checknil)
- return;
- // Ideally we wouldn't see any integer types here, but we do.
- if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
- dump("checknil", n);
- fatal("bad checknil");
- }
- if(((thearch.thechar == '5' || thearch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
- thearch.regalloc(&reg, types[tptr], n);
- thearch.cgen(n, &reg);
- thearch.gins(ACHECKNIL, &reg, N);
- thearch.regfree(&reg);
- return;
- }
- thearch.gins(ACHECKNIL, n, N);
-}
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
deleted file mode 100644
index c0d1e57932..0000000000
--- a/src/cmd/gc/plive.c
+++ /dev/null
@@ -1,2005 +0,0 @@
-// 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.
-
-// Garbage collector liveness bitmap generation.
-
-// The command line flag -live causes this code to print debug information.
-// The levels are:
-//
-// -live (aka -live=1): print liveness lists as code warnings at safe points
-// -live=2: print an assembly listing with liveness annotations
-// -live=3: print information during each computation phase (much chattier)
-//
-// Each level includes the earlier output as well.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-#include "../../runtime/funcdata.h"
-#include "../../runtime/mgc0.h"
-
-enum {
- UNVISITED = 0,
- VISITED = 1,
-};
-
-// An ordinary basic block.
-//
-// Instructions are threaded together in a doubly-linked list. To iterate in
-// program order follow the link pointer from the first node and stop after the
-// last node has been visited
-//
-// for(p = bb->first;; p = p->link) {
-// ...
-// if(p == bb->last)
-// break;
-// }
-//
-// To iterate in reverse program order by following the opt pointer from the
-// last node
-//
-// for(p = bb->last; p != nil; p = p->opt) {
-// ...
-// }
-typedef struct BasicBlock BasicBlock;
-struct BasicBlock {
- // An array of preceding blocks. If the length of this array is 0 the
- // block is probably the start block of the CFG.
- Array *pred;
-
- // An array out succeeding blocks. If the length of this array is zero,
- // the block probably ends in a return instruction.
- Array *succ;
-
- // First instruction in the block. When part of a fully initialized
- // control flow graph, the opt member will be nil.
- Prog *first;
-
- // Last instruction in the basic block.
- Prog *last;
-
- // The reverse post order number. This value is initialized to -1 and
- // will be replaced by a non-negative value when the CFG is constructed.
- // After CFG construction, if rpo is -1 this block is unreachable.
- int rpo;
-
- // State to denote whether the block has been visited during a
- // traversal.
- int mark;
-
- // For use during livenessepilogue.
- int lastbitmapindex;
-};
-
-// A collection of global state used by liveness analysis.
-typedef struct Liveness Liveness;
-struct Liveness {
- // A pointer to the node corresponding to the function being analyzed.
- Node *fn;
-
- // A linked list of instructions for this function.
- Prog *ptxt;
-
- // A list of arguments and local variables in this function.
- Array *vars;
-
- // A list of basic blocks that are overlayed on the instruction list.
- // The blocks are roughly in the same order as the instructions
- // in the function (first block has TEXT instruction, and so on).
- Array *cfg;
-
- // Summary sets of block effects.
- // The Bvec** is indexed by bb->rpo to yield a single Bvec*.
- // That bit vector is indexed by variable number (same as lv->vars).
- //
- // Computed during livenessprologue using only the content of
- // individual blocks:
- //
- // uevar: upward exposed variables (used before set in block)
- // varkill: killed variables (set in block)
- // avarinit: addrtaken variables set or used (proof of initialization)
- //
- // Computed during livenesssolve using control flow information:
- //
- // livein: variables live at block entry
- // liveout: variables live at block exit
- // avarinitany: addrtaken variables possibly initialized at block exit
- // (initialized in block or at exit from any predecessor block)
- // avarinitall: addrtaken variables certainly initialized at block exit
- // (initialized in block or at exit from all predecessor blocks)
- Bvec **uevar;
- Bvec **varkill;
- Bvec **livein;
- Bvec **liveout;
- Bvec **avarinit;
- Bvec **avarinitany;
- Bvec **avarinitall;
-
- // An array with a bit vector for each safe point tracking live pointers
- // in the arguments and locals area, indexed by bb->rpo.
- Array *argslivepointers;
- Array *livepointers;
-};
-
-static void*
-xmalloc(uintptr size)
-{
- void *result;
-
- result = malloc(size);
- if(result == nil)
- fatal("malloc failed");
- return result;
-}
-
-// Constructs a new basic block containing a single instruction.
-static BasicBlock*
-newblock(Prog *prog)
-{
- BasicBlock *result;
-
- if(prog == nil)
- fatal("newblock: prog cannot be nil");
- result = xmalloc(sizeof(*result));
- result->rpo = -1;
- result->mark = UNVISITED;
- result->first = prog;
- result->last = prog;
- result->pred = arraynew(2, sizeof(BasicBlock*));
- result->succ = arraynew(2, sizeof(BasicBlock*));
- return result;
-}
-
-// Frees a basic block and all of its leaf data structures.
-static void
-freeblock(BasicBlock *bb)
-{
- if(bb == nil)
- fatal("freeblock: cannot free nil");
- arrayfree(bb->pred);
- arrayfree(bb->succ);
- free(bb);
-}
-
-// Adds an edge between two basic blocks by making from a predecessor of to and
-// to a successor of from.
-static void
-addedge(BasicBlock *from, BasicBlock *to)
-{
- if(from == nil)
- fatal("addedge: from is nil");
- if(to == nil)
- fatal("addedge: to is nil");
- arrayadd(from->succ, &to);
- arrayadd(to->pred, &from);
-}
-
-// Inserts prev before curr in the instruction
-// stream. Any control flow, such as branches or fall throughs, that target the
-// existing instruction are adjusted to target the new instruction.
-static void
-splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr)
-{
- Prog *next, tmp;
-
- USED(lv);
-
- // There may be other instructions pointing at curr,
- // and we want them to now point at prev. Instead of
- // trying to find all such instructions, swap the contents
- // so that the problem becomes inserting next after curr.
- // The "opt" field is the backward link in the linked list.
-
- // Overwrite curr's data with prev, but keep the list links.
- tmp = *curr;
- *curr = *prev;
- curr->opt = tmp.opt;
- curr->link = tmp.link;
-
- // Overwrite prev (now next) with curr's old data.
- next = prev;
- *next = tmp;
- next->opt = nil;
- next->link = nil;
-
- // Now insert next after curr.
- next->link = curr->link;
- next->opt = curr;
- curr->link = next;
- if(next->link && next->link->opt == curr)
- next->link->opt = next;
-
- if(bb->last == curr)
- bb->last = next;
-}
-
-// A pretty printer for basic blocks.
-static void
-printblock(BasicBlock *bb)
-{
- BasicBlock *pred;
- BasicBlock *succ;
- Prog *prog;
- int i;
-
- print("basic block %d\n", bb->rpo);
- print("\tpred:");
- for(i = 0; i < arraylength(bb->pred); i++) {
- pred = *(BasicBlock**)arrayget(bb->pred, i);
- print(" %d", pred->rpo);
- }
- print("\n");
- print("\tsucc:");
- for(i = 0; i < arraylength(bb->succ); i++) {
- succ = *(BasicBlock**)arrayget(bb->succ, i);
- print(" %d", succ->rpo);
- }
- print("\n");
- print("\tprog:\n");
- for(prog = bb->first;; prog=prog->link) {
- print("\t\t%P\n", prog);
- if(prog == bb->last)
- break;
- }
-}
-
-
-// Iterates over a basic block applying a callback to each instruction. There
-// are two criteria for termination. If the end of basic block is reached a
-// value of zero is returned. If the callback returns a non-zero value, the
-// iteration is stopped and the value of the callback is returned.
-static int
-blockany(BasicBlock *bb, int (*callback)(Prog*))
-{
- Prog *p;
- int result;
-
- for(p = bb->last; p != nil; p = p->opt) {
- result = (*callback)(p);
- if(result != 0)
- return result;
- }
- return 0;
-}
-
-// Collects and returns and array of Node*s for functions arguments and local
-// variables.
-static Array*
-getvariables(Node *fn)
-{
- Array *result;
- NodeList *ll;
-
- result = arraynew(0, sizeof(Node*));
- for(ll = fn->dcl; ll != nil; ll = ll->next) {
- if(ll->n->op == ONAME) {
- // In order for GODEBUG=gcdead=1 to work, each bitmap needs
- // to contain information about all variables covered by the bitmap.
- // For local variables, the bitmap only covers the stkptrsize
- // bytes in the frame where variables containing pointers live.
- // For arguments and results, the bitmap covers all variables,
- // so we must include all the variables, even the ones without
- // pointers.
- //
- // The Node.opt field is available for use by optimization passes.
- // We use it to hold the index of the node in the variables array, plus 1
- // (so that 0 means the Node is not in the variables array).
- // Each pass should clear opt when done, but you never know,
- // so clear them all ourselves too.
- // The Node.curfn field is supposed to be set to the current function
- // already, but for some compiler-introduced names it seems not to be,
- // so fix that here.
- // Later, when we want to find the index of a node in the variables list,
- // we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
- // is the index in the variables list.
- ll->n->opt = nil;
- ll->n->curfn = curfn;
- switch(ll->n->class) {
- case PAUTO:
- if(haspointers(ll->n->type)) {
- ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
- arrayadd(result, &ll->n);
- }
- break;
- case PPARAM:
- case PPARAMOUT:
- ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
- arrayadd(result, &ll->n);
- break;
- }
- }
- }
- return result;
-}
-
-// A pretty printer for control flow graphs. Takes an array of BasicBlock*s.
-static void
-printcfg(Array *cfg)
-{
- BasicBlock *bb;
- int32 i;
-
- for(i = 0; i < arraylength(cfg); i++) {
- bb = *(BasicBlock**)arrayget(cfg, i);
- printblock(bb);
- }
-}
-
-// Assigns a reverse post order number to each connected basic block using the
-// standard algorithm. Unconnected blocks will not be affected.
-static void
-reversepostorder(BasicBlock *root, int32 *rpo)
-{
- BasicBlock *bb;
- int i;
-
- root->mark = VISITED;
- for(i = 0; i < arraylength(root->succ); i++) {
- bb = *(BasicBlock**)arrayget(root->succ, i);
- if(bb->mark == UNVISITED)
- reversepostorder(bb, rpo);
- }
- *rpo -= 1;
- root->rpo = *rpo;
-}
-
-// Comparison predicate used for sorting basic blocks by their rpo in ascending
-// order.
-static int
-blockrpocmp(const void *p1, const void *p2)
-{
- BasicBlock *bb1;
- BasicBlock *bb2;
-
- bb1 = *(BasicBlock**)p1;
- bb2 = *(BasicBlock**)p2;
- if(bb1->rpo < bb2->rpo)
- return -1;
- if(bb1->rpo > bb2->rpo)
- return 1;
- return 0;
-}
-
-// A pattern matcher for call instructions. Returns true when the instruction
-// is a call to a specific package qualified function name.
-static int
-iscall(Prog *prog, LSym *name)
-{
- if(prog == nil)
- fatal("iscall: prog is nil");
- if(name == nil)
- fatal("iscall: function name is nil");
- if(prog->as != ACALL)
- return 0;
- return name == prog->to.sym;
-}
-
-// Returns true for instructions that call a runtime function implementing a
-// select communication clause.
-static int
-isselectcommcasecall(Prog *prog)
-{
- static LSym* names[5];
- int32 i;
-
- if(names[0] == nil) {
- names[0] = linksym(pkglookup("selectsend", runtimepkg));
- names[1] = linksym(pkglookup("selectrecv", runtimepkg));
- names[2] = linksym(pkglookup("selectrecv2", runtimepkg));
- names[3] = linksym(pkglookup("selectdefault", runtimepkg));
- }
- for(i = 0; names[i] != nil; i++)
- if(iscall(prog, names[i]))
- return 1;
- return 0;
-}
-
-// Returns true for call instructions that target runtime·newselect.
-static int
-isnewselect(Prog *prog)
-{
- static LSym *sym;
-
- if(sym == nil)
- sym = linksym(pkglookup("newselect", runtimepkg));
- return iscall(prog, sym);
-}
-
-// Returns true for call instructions that target runtime·selectgo.
-static int
-isselectgocall(Prog *prog)
-{
- static LSym *sym;
-
- if(sym == nil)
- sym = linksym(pkglookup("selectgo", runtimepkg));
- return iscall(prog, sym);
-}
-
-static int
-isdeferreturn(Prog *prog)
-{
- static LSym *sym;
-
- if(sym == nil)
- sym = linksym(pkglookup("deferreturn", runtimepkg));
- return iscall(prog, sym);
-}
-
-// Walk backwards from a runtime·selectgo call up to its immediately dominating
-// runtime·newselect call. Any successor nodes of communication clause nodes
-// are implicit successors of the runtime·selectgo call node. The goal of this
-// analysis is to add these missing edges to complete the control flow graph.
-static void
-addselectgosucc(BasicBlock *selectgo)
-{
- BasicBlock *pred;
- BasicBlock *succ;
-
- pred = selectgo;
- for(;;) {
- if(arraylength(pred->pred) == 0)
- fatal("selectgo does not have a newselect");
- pred = *(BasicBlock**)arrayget(pred->pred, 0);
- if(blockany(pred, isselectcommcasecall)) {
- // A select comm case block should have exactly one
- // successor.
- if(arraylength(pred->succ) != 1)
- fatal("select comm case has too many successors");
- succ = *(BasicBlock**)arrayget(pred->succ, 0);
- // Its successor should have exactly two successors.
- // The drop through should flow to the selectgo block
- // and the branch should lead to the select case
- // statements block.
- if(arraylength(succ->succ) != 2)
- fatal("select comm case successor has too many successors");
- // Add the block as a successor of the selectgo block.
- addedge(selectgo, succ);
- }
- if(blockany(pred, isnewselect)) {
- // Reached the matching newselect.
- break;
- }
- }
-}
-
-// The entry point for the missing selectgo control flow algorithm. Takes an
-// array of BasicBlock*s containing selectgo calls.
-static void
-fixselectgo(Array *selectgo)
-{
- BasicBlock *bb;
- int32 i;
-
- for(i = 0; i < arraylength(selectgo); i++) {
- bb = *(BasicBlock**)arrayget(selectgo, i);
- addselectgosucc(bb);
- }
-}
-
-// Constructs a control flow graph from a sequence of instructions. This
-// procedure is complicated by various sources of implicit control flow that are
-// not accounted for using the standard cfg construction algorithm. Returns an
-// array of BasicBlock*s in control flow graph form (basic blocks ordered by
-// their RPO number).
-static Array*
-newcfg(Prog *firstp)
-{
- Prog *p;
- Prog *prev;
- BasicBlock *bb;
- Array *cfg;
- Array *selectgo;
- int32 i;
- int32 rpo;
-
- // Reset the opt field of each prog to nil. In the first and second
- // passes, instructions that are labels temporarily use the opt field to
- // point to their basic block. In the third pass, the opt field reset
- // to point to the predecessor of an instruction in its basic block.
- for(p = firstp; p != P; p = p->link)
- p->opt = nil;
-
- // Allocate an array to remember where we have seen selectgo calls.
- // These blocks will be revisited to add successor control flow edges.
- selectgo = arraynew(0, sizeof(BasicBlock*));
-
- // Loop through all instructions identifying branch targets
- // and fall-throughs and allocate basic blocks.
- cfg = arraynew(0, sizeof(BasicBlock*));
- bb = newblock(firstp);
- arrayadd(cfg, &bb);
- for(p = firstp; p != P; p = p->link) {
- if(p->to.type == TYPE_BRANCH) {
- if(p->to.u.branch == nil)
- fatal("prog branch to nil");
- if(p->to.u.branch->opt == nil) {
- p->to.u.branch->opt = newblock(p->to.u.branch);
- arrayadd(cfg, &p->to.u.branch->opt);
- }
- if(p->as != AJMP && p->link != nil && p->link->opt == nil) {
- p->link->opt = newblock(p->link);
- arrayadd(cfg, &p->link->opt);
- }
- } else if(isselectcommcasecall(p) || isselectgocall(p)) {
- // Accommodate implicit selectgo control flow.
- if(p->link->opt == nil) {
- p->link->opt = newblock(p->link);
- arrayadd(cfg, &p->link->opt);
- }
- }
- }
-
- // Loop through all basic blocks maximally growing the list of
- // contained instructions until a label is reached. Add edges
- // for branches and fall-through instructions.
- for(i = 0; i < arraylength(cfg); i++) {
- bb = *(BasicBlock**)arrayget(cfg, i);
- for(p = bb->last; p != nil; p = p->link) {
- if(p->opt != nil && p != bb->last)
- break;
- bb->last = p;
-
- // Stop before an unreachable RET, to avoid creating
- // unreachable control flow nodes.
- if(p->link != nil && p->link->as == ARET && p->link->mode == 1)
- break;
-
- // Collect basic blocks with selectgo calls.
- if(isselectgocall(p))
- arrayadd(selectgo, &bb);
- }
- if(bb->last->to.type == TYPE_BRANCH)
- addedge(bb, bb->last->to.u.branch->opt);
- if(bb->last->link != nil) {
- // Add a fall-through when the instruction is
- // not an unconditional control transfer.
- if(bb->last->as != AJMP && bb->last->as != ARET && bb->last->as != AUNDEF)
- addedge(bb, bb->last->link->opt);
- }
- }
-
- // Add back links so the instructions in a basic block can be traversed
- // backward. This is the final state of the instruction opt field.
- for(i = 0; i < arraylength(cfg); i++) {
- bb = *(BasicBlock**)arrayget(cfg, i);
- p = bb->first;
- prev = nil;
- for(;;) {
- p->opt = prev;
- if(p == bb->last)
- break;
- prev = p;
- p = p->link;
- }
- }
-
- // Add missing successor edges to the selectgo blocks.
- if(arraylength(selectgo))
- fixselectgo(selectgo);
- arrayfree(selectgo);
-
- // Find a depth-first order and assign a depth-first number to
- // all basic blocks.
- for(i = 0; i < arraylength(cfg); i++) {
- bb = *(BasicBlock**)arrayget(cfg, i);
- bb->mark = UNVISITED;
- }
- bb = *(BasicBlock**)arrayget(cfg, 0);
- rpo = arraylength(cfg);
- reversepostorder(bb, &rpo);
-
- // Sort the basic blocks by their depth first number. The
- // array is now a depth-first spanning tree with the first
- // node being the root.
- arraysort(cfg, blockrpocmp);
- bb = *(BasicBlock**)arrayget(cfg, 0);
-
- // Unreachable control flow nodes are indicated by a -1 in the rpo
- // field. If we see these nodes something must have gone wrong in an
- // upstream compilation phase.
- if(bb->rpo == -1) {
- print("newcfg: unreachable basic block for %P\n", bb->last);
- printcfg(cfg);
- fatal("newcfg: invalid control flow graph");
- }
-
- return cfg;
-}
-
-// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
-// data structures.
-static void
-freecfg(Array *cfg)
-{
- BasicBlock *bb;
- BasicBlock *bb0;
- Prog *p;
- int32 i;
- int32 n;
-
- n = arraylength(cfg);
- if(n > 0) {
- bb0 = *(BasicBlock**)arrayget(cfg, 0);
- for(p = bb0->first; p != P; p = p->link) {
- p->opt = nil;
- }
- for(i = 0; i < n; i++) {
- bb = *(BasicBlock**)arrayget(cfg, i);
- freeblock(bb);
- }
- }
- arrayfree(cfg);
-}
-
-// Returns true if the node names a variable that is otherwise uninteresting to
-// the liveness computation.
-static int
-isfunny(Node *node)
-{
- char *names[] = { ".fp", ".args", nil };
- int i;
-
- if(node->sym != nil && node->sym->name != nil)
- for(i = 0; names[i] != nil; i++)
- if(strcmp(node->sym->name, names[i]) == 0)
- return 1;
- return 0;
-}
-
-// Computes the effects of an instruction on a set of
-// variables. The vars argument is an array of Node*s.
-//
-// The output vectors give bits for variables:
-// uevar - used by this instruction
-// varkill - killed by this instruction
-// for variables without address taken, means variable was set
-// for variables with address taken, means variable was marked dead
-// avarinit - initialized or referred to by this instruction,
-// only for variables with address taken but not escaping to heap
-//
-// The avarinit output serves as a signal that the data has been
-// initialized, because any use of a variable must come after its
-// initialization.
-static void
-progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
-{
- ProgInfo info;
- Addr *from;
- Addr *to;
- Node *node;
- int32 i;
- int32 pos;
-
- bvresetall(uevar);
- bvresetall(varkill);
- bvresetall(avarinit);
-
- thearch.proginfo(&info, prog);
- if(prog->as == ARET) {
- // Return instructions implicitly read all the arguments. For
- // the sake of correctness, out arguments must be read. For the
- // sake of backtrace quality, we read in arguments as well.
- //
- // A return instruction with a p->to is a tail return, which brings
- // the stack pointer back up (if it ever went down) and then jumps
- // to a new function entirely. That form of instruction must read
- // all the parameters for correctness, and similarly it must not
- // read the out arguments - they won't be set until the new
- // function runs.
- for(i = 0; i < arraylength(vars); i++) {
- node = *(Node**)arrayget(vars, i);
- switch(node->class & ~PHEAP) {
- case PPARAM:
- bvset(uevar, i);
- break;
- case PPARAMOUT:
- // If the result had its address taken, it is being tracked
- // by the avarinit code, which does not use uevar.
- // If we added it to uevar too, we'd not see any kill
- // and decide that the varible was live entry, which it is not.
- // So only use uevar in the non-addrtaken case.
- // The p->to.type == thearch.D_NONE limits the bvset to
- // non-tail-call return instructions; see note above
- // the for loop for details.
- if(!node->addrtaken && prog->to.type == TYPE_NONE)
- bvset(uevar, i);
- break;
- }
- }
- return;
- }
- if(prog->as == ATEXT) {
- // A text instruction marks the entry point to a function and
- // the definition point of all in arguments.
- for(i = 0; i < arraylength(vars); i++) {
- node = *(Node**)arrayget(vars, i);
- switch(node->class & ~PHEAP) {
- case PPARAM:
- if(node->addrtaken)
- bvset(avarinit, i);
- bvset(varkill, i);
- break;
- }
- }
- return;
- }
- if(info.flags & (LeftRead | LeftWrite | LeftAddr)) {
- from = &prog->from;
- if (from->node != nil && from->sym != nil && ((Node*)(from->node))->curfn == curfn) {
- switch(((Node*)(from->node))->class & ~PHEAP) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- pos = (int)(uintptr)((Node*)(from->node))->opt - 1; // index in vars
- if(pos == -1)
- goto Next;
- if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != from->node)
- fatal("bad bookkeeping in liveness %N %d", from->node, pos);
- if(((Node*)(from->node))->addrtaken) {
- bvset(avarinit, pos);
- } else {
- if(info.flags & (LeftRead | LeftAddr))
- bvset(uevar, pos);
- if(info.flags & LeftWrite)
- if(from->node != nil && !isfat(((Node*)(from->node))->type))
- bvset(varkill, pos);
- }
- }
- }
- }
-Next:
- if(info.flags & (RightRead | RightWrite | RightAddr)) {
- to = &prog->to;
- if (to->node != nil && to->sym != nil && ((Node*)(to->node))->curfn == curfn) {
- switch(((Node*)(to->node))->class & ~PHEAP) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- pos = (int)(uintptr)((Node*)(to->node))->opt - 1; // index in vars
- if(pos == -1)
- goto Next1;
- if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node)
- fatal("bad bookkeeping in liveness %N %d", to->node, pos);
- if(((Node*)(to->node))->addrtaken) {
- if(prog->as != AVARKILL)
- bvset(avarinit, pos);
- if(prog->as == AVARDEF || prog->as == AVARKILL)
- bvset(varkill, pos);
- } else {
- // RightRead is a read, obviously.
- // RightAddr by itself is also implicitly a read.
- //
- // RightAddr|RightWrite means that the address is being taken
- // but only so that the instruction can write to the value.
- // It is not a read. It is equivalent to RightWrite except that
- // having the RightAddr bit set keeps the registerizer from
- // trying to substitute a register for the memory location.
- if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
- bvset(uevar, pos);
- if(info.flags & RightWrite)
- if(to->node != nil && (!isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
- bvset(varkill, pos);
- }
- }
- }
- }
-Next1:;
-}
-
-// Constructs a new liveness structure used to hold the global state of the
-// liveness computation. The cfg argument is an array of BasicBlock*s and the
-// vars argument is an array of Node*s.
-static Liveness*
-newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars)
-{
- Liveness *result;
- int32 i;
- int32 nblocks;
- int32 nvars;
-
- result = xmalloc(sizeof(*result));
- result->fn = fn;
- result->ptxt = ptxt;
- result->cfg = cfg;
- result->vars = vars;
-
- nblocks = arraylength(cfg);
- result->uevar = xmalloc(sizeof(Bvec*) * nblocks);
- result->varkill = xmalloc(sizeof(Bvec*) * nblocks);
- result->livein = xmalloc(sizeof(Bvec*) * nblocks);
- result->liveout = xmalloc(sizeof(Bvec*) * nblocks);
- result->avarinit = xmalloc(sizeof(Bvec*) * nblocks);
- result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks);
- result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks);
-
- nvars = arraylength(vars);
- for(i = 0; i < nblocks; i++) {
- result->uevar[i] = bvalloc(nvars);
- result->varkill[i] = bvalloc(nvars);
- result->livein[i] = bvalloc(nvars);
- result->liveout[i] = bvalloc(nvars);
- result->avarinit[i] = bvalloc(nvars);
- result->avarinitany[i] = bvalloc(nvars);
- result->avarinitall[i] = bvalloc(nvars);
- }
-
- result->livepointers = arraynew(0, sizeof(Bvec*));
- result->argslivepointers = arraynew(0, sizeof(Bvec*));
- return result;
-}
-
-// Frees the liveness structure and all of its leaf data structures.
-static void
-freeliveness(Liveness *lv)
-{
- int32 i;
-
- if(lv == nil)
- fatal("freeliveness: cannot free nil");
-
- for(i = 0; i < arraylength(lv->livepointers); i++)
- free(*(Bvec**)arrayget(lv->livepointers, i));
- arrayfree(lv->livepointers);
-
- for(i = 0; i < arraylength(lv->argslivepointers); i++)
- free(*(Bvec**)arrayget(lv->argslivepointers, i));
- arrayfree(lv->argslivepointers);
-
- for(i = 0; i < arraylength(lv->cfg); i++) {
- free(lv->uevar[i]);
- free(lv->varkill[i]);
- free(lv->livein[i]);
- free(lv->liveout[i]);
- free(lv->avarinit[i]);
- free(lv->avarinitany[i]);
- free(lv->avarinitall[i]);
- }
-
- free(lv->uevar);
- free(lv->varkill);
- free(lv->livein);
- free(lv->liveout);
- free(lv->avarinit);
- free(lv->avarinitany);
- free(lv->avarinitall);
-
- free(lv);
-}
-
-static void
-printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
-{
- print("effects of %P", p);
- print("\nuevar: ");
- bvprint(uevar);
- print("\nvarkill: ");
- bvprint(varkill);
- print("\navarinit: ");
- bvprint(avarinit);
- print("\n");
-}
-
-// Pretty print a variable node. Uses Pascal like conventions for pointers and
-// addresses to avoid confusing the C like conventions used in the node variable
-// names.
-static void
-printnode(Node *node)
-{
- char *p;
- char *a;
-
- p = "";
- if(haspointers(node->type))
- p = "^";
- a = "";
- if(node->addrtaken)
- a = "@";
- print(" %N%s%s", node, p, a);
-}
-
-// Pretty print a list of variables. The vars argument is an array of Node*s.
-static void
-printvars(char *name, Bvec *bv, Array *vars)
-{
- int32 i;
-
- print("%s:", name);
- for(i = 0; i < arraylength(vars); i++)
- if(bvget(bv, i))
- printnode(*(Node**)arrayget(vars, i));
- print("\n");
-}
-
-// Prints a basic block annotated with the information computed by liveness
-// analysis.
-static void
-livenessprintblock(Liveness *lv, BasicBlock *bb)
-{
- BasicBlock *pred;
- BasicBlock *succ;
- Prog *prog;
- Bvec *live;
- int i;
- int32 pos;
-
- print("basic block %d\n", bb->rpo);
-
- print("\tpred:");
- for(i = 0; i < arraylength(bb->pred); i++) {
- pred = *(BasicBlock**)arrayget(bb->pred, i);
- print(" %d", pred->rpo);
- }
- print("\n");
-
- print("\tsucc:");
- for(i = 0; i < arraylength(bb->succ); i++) {
- succ = *(BasicBlock**)arrayget(bb->succ, i);
- print(" %d", succ->rpo);
- }
- print("\n");
-
- printvars("\tuevar", lv->uevar[bb->rpo], lv->vars);
- printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars);
- printvars("\tlivein", lv->livein[bb->rpo], lv->vars);
- printvars("\tliveout", lv->liveout[bb->rpo], lv->vars);
- printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars);
- printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars);
- printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars);
-
- print("\tprog:\n");
- for(prog = bb->first;; prog = prog->link) {
- print("\t\t%P", prog);
- if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
- pos = prog->to.offset;
- live = *(Bvec**)arrayget(lv->livepointers, pos);
- print(" ");
- bvprint(live);
- }
- print("\n");
- if(prog == bb->last)
- break;
- }
-}
-
-// Prints a control flow graph annotated with any information computed by
-// liveness analysis.
-static void
-livenessprintcfg(Liveness *lv)
-{
- BasicBlock *bb;
- int32 i;
-
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
- livenessprintblock(lv, bb);
- }
-}
-
-static void
-checkauto(Node *fn, Prog *p, Node *n)
-{
- NodeList *l;
-
- for(l = fn->dcl; l != nil; l = l->next)
- if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n)
- return;
-
- if(n == nil) {
- print("%L: checkauto %N: nil node in %P\n", p->lineno, curfn, p);
- return;
- }
- print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
- for(l = fn->dcl; l != nil; l = l->next)
- print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
- yyerror("checkauto: invariant lost");
-}
-
-static void
-checkparam(Node *fn, Prog *p, Node *n)
-{
- NodeList *l;
- Node *a;
- int class;
-
- if(isfunny(n))
- return;
- for(l = fn->dcl; l != nil; l = l->next) {
- a = l->n;
- class = a->class & ~PHEAP;
- if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n)
- return;
- }
-
- print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
- for(l = fn->dcl; l != nil; l = l->next)
- print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
- yyerror("checkparam: invariant lost");
-}
-
-static void
-checkprog(Node *fn, Prog *p)
-{
- if(p->from.name == NAME_AUTO)
- checkauto(fn, p, p->from.node);
- if(p->from.name == NAME_PARAM)
- checkparam(fn, p, p->from.node);
- if(p->to.name == NAME_AUTO)
- checkauto(fn, p, p->to.node);
- if(p->to.name == NAME_PARAM)
- checkparam(fn, p, p->to.node);
-}
-
-// Check instruction invariants. We assume that the nodes corresponding to the
-// sources and destinations of memory operations will be declared in the
-// function. This is not strictly true, as is the case for the so-called funny
-// nodes and there are special cases to skip over that stuff. The analysis will
-// fail if this invariant blindly changes.
-static void
-checkptxt(Node *fn, Prog *firstp)
-{
- Prog *p;
-
- if(debuglive == 0)
- return;
-
- for(p = firstp; p != P; p = p->link) {
- if(0)
- print("analyzing '%P'\n", p);
- if(p->as != ADATA && p->as != AGLOBL && p->as != ATYPE)
- checkprog(fn, p);
- }
-}
-
-// NOTE: The bitmap for a specific type t should be cached in t after the first run
-// and then simply copied into bv at the correct offset on future calls with
-// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
-// accounts for 40% of the 6g execution time.
-void
-twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
-{
- vlong fieldoffset;
- vlong i;
- vlong o;
- Type *t1;
-
- if(t->align > 0 && (*xoffset & (t->align - 1)) != 0)
- fatal("twobitwalktype1: invalid initial alignment, %T", t);
-
- switch(t->etype) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- for(i = 0; i < t->width; i++) {
- bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar (BitsScalar)
- }
- *xoffset += t->width;
- break;
-
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TFUNC:
- case TCHAN:
- case TMAP:
- if((*xoffset & (widthptr-1)) != 0)
- fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr (BitsPointer)
- *xoffset += t->width;
- break;
-
- case TSTRING:
- // struct { byte *str; intgo len; }
- if((*xoffset & (widthptr-1)) != 0)
- fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
- *xoffset += t->width;
- break;
-
- case TINTER:
- // struct { Itab *tab; union { void *ptr, uintptr val } data; }
- // or, when isnilinter(t)==true:
- // struct { Type *type; union { void *ptr, uintptr val } data; }
- if((*xoffset & (widthptr-1)) != 0)
- fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 3); // 2 = live ptr in second slot (BitsPointer)
- *xoffset += t->width;
- break;
-
- case TARRAY:
- // The value of t->bound is -1 for slices types and >0 for
- // for fixed array types. All other values are invalid.
- if(t->bound < -1)
- fatal("twobitwalktype1: invalid bound, %T", t);
- if(isslice(t)) {
- // struct { byte *array; uintgo len; uintgo cap; }
- if((*xoffset & (widthptr-1)) != 0)
- fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer)
- *xoffset += t->width;
- } else
- for(i = 0; i < t->bound; i++)
- twobitwalktype1(t->type, xoffset, bv);
- break;
-
- case TSTRUCT:
- o = 0;
- for(t1 = t->type; t1 != T; t1 = t1->down) {
- fieldoffset = t1->width;
- *xoffset += fieldoffset - o;
- twobitwalktype1(t1->type, xoffset, bv);
- o = fieldoffset + t1->type->width;
- }
- *xoffset += t->width - o;
- break;
-
- default:
- fatal("twobitwalktype1: unexpected type, %T", t);
- }
-}
-
-// Returns the number of words of local variables.
-static int32
-localswords(void)
-{
- return stkptrsize / widthptr;
-}
-
-// Returns the number of words of in and out arguments.
-static int32
-argswords(void)
-{
- return curfn->type->argwid / widthptr;
-}
-
-// Generates live pointer value maps for arguments and local variables. The
-// this argument and the in arguments are always assumed live. The vars
-// argument is an array of Node*s.
-static void
-twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals)
-{
- Node *node;
- Type *thisargtype;
- Type *inargtype;
- vlong xoffset;
- int32 i;
-
- for(i = 0; (i = bvnext(liveout, i)) >= 0; i++) {
- node = *(Node**)arrayget(vars, i);
- switch(node->class) {
- case PAUTO:
- xoffset = node->xoffset + stkptrsize;
- twobitwalktype1(node->type, &xoffset, locals);
- break;
- case PPARAM:
- case PPARAMOUT:
- xoffset = node->xoffset;
- twobitwalktype1(node->type, &xoffset, args);
- break;
- }
- }
-
- // The node list only contains declared names.
- // If the receiver or arguments are unnamed, they will be omitted
- // from the list above. Preserve those values - even though they are unused -
- // in order to keep their addresses live for use in stack traces.
- thisargtype = getthisx(lv->fn->type);
- if(thisargtype != nil) {
- xoffset = 0;
- twobitwalktype1(thisargtype, &xoffset, args);
- }
- inargtype = getinargx(lv->fn->type);
- if(inargtype != nil) {
- xoffset = 0;
- twobitwalktype1(inargtype, &xoffset, args);
- }
-}
-
-// Construct a disembodied instruction.
-static Prog*
-unlinkedprog(int as)
-{
- Prog *p;
-
- p = mal(sizeof(*p));
- clearp(p);
- p->as = as;
- return p;
-}
-
-// Construct a new PCDATA instruction associated with and for the purposes of
-// covering an existing instruction.
-static Prog*
-newpcdataprog(Prog *prog, int32 index)
-{
- Node from, to;
- Prog *pcdata;
-
- nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
- nodconst(&to, types[TINT32], index);
- pcdata = unlinkedprog(APCDATA);
- pcdata->lineno = prog->lineno;
- naddr(&from, &pcdata->from, 0);
- naddr(&to, &pcdata->to, 0);
- return pcdata;
-}
-
-// Returns true for instructions that are safe points that must be annotated
-// with liveness information.
-static int
-issafepoint(Prog *prog)
-{
- return prog->as == ATEXT || prog->as == ACALL;
-}
-
-// Initializes the sets for solving the live variables. Visits all the
-// instructions in each basic block to summarizes the information at each basic
-// block
-static void
-livenessprologue(Liveness *lv)
-{
- BasicBlock *bb;
- Bvec *uevar, *varkill, *avarinit;
- Prog *p;
- int32 i;
- int32 nvars;
-
- nvars = arraylength(lv->vars);
- uevar = bvalloc(nvars);
- varkill = bvalloc(nvars);
- avarinit = bvalloc(nvars);
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
- // Walk the block instructions backward and update the block
- // effects with the each prog effects.
- for(p = bb->last; p != nil; p = p->opt) {
- progeffects(p, lv->vars, uevar, varkill, avarinit);
- if(debuglive >= 3)
- printeffects(p, uevar, varkill, avarinit);
- bvor(lv->varkill[i], lv->varkill[i], varkill);
- bvandnot(lv->uevar[i], lv->uevar[i], varkill);
- bvor(lv->uevar[i], lv->uevar[i], uevar);
- }
- // Walk the block instructions forward to update avarinit bits.
- // avarinit describes the effect at the end of the block, not the beginning.
- bvresetall(varkill);
- for(p = bb->first;; p = p->link) {
- progeffects(p, lv->vars, uevar, varkill, avarinit);
- if(debuglive >= 3)
- printeffects(p, uevar, varkill, avarinit);
- bvandnot(lv->avarinit[i], lv->avarinit[i], varkill);
- bvor(lv->avarinit[i], lv->avarinit[i], avarinit);
- if(p == bb->last)
- break;
- }
- }
- free(uevar);
- free(varkill);
- free(avarinit);
-}
-
-// Solve the liveness dataflow equations.
-static void
-livenesssolve(Liveness *lv)
-{
- BasicBlock *bb, *succ, *pred;
- Bvec *newlivein, *newliveout, *any, *all;
- int32 rpo, i, j, change;
-
- // These temporary bitvectors exist to avoid successive allocations and
- // frees within the loop.
- newlivein = bvalloc(arraylength(lv->vars));
- newliveout = bvalloc(arraylength(lv->vars));
- any = bvalloc(arraylength(lv->vars));
- all = bvalloc(arraylength(lv->vars));
-
- // Push avarinitall, avarinitany forward.
- // avarinitall says the addressed var is initialized along all paths reaching the block exit.
- // avarinitany says the addressed var is initialized along some path reaching the block exit.
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
- rpo = bb->rpo;
- if(i == 0)
- bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]);
- else {
- bvresetall(lv->avarinitall[rpo]);
- bvnot(lv->avarinitall[rpo]);
- }
- bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]);
- }
-
- change = 1;
- while(change != 0) {
- change = 0;
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
- rpo = bb->rpo;
- bvresetall(any);
- bvresetall(all);
- for(j = 0; j < arraylength(bb->pred); j++) {
- pred = *(BasicBlock**)arrayget(bb->pred, j);
- if(j == 0) {
- bvcopy(any, lv->avarinitany[pred->rpo]);
- bvcopy(all, lv->avarinitall[pred->rpo]);
- } else {
- bvor(any, any, lv->avarinitany[pred->rpo]);
- bvand(all, all, lv->avarinitall[pred->rpo]);
- }
- }
- bvandnot(any, any, lv->varkill[rpo]);
- bvandnot(all, all, lv->varkill[rpo]);
- bvor(any, any, lv->avarinit[rpo]);
- bvor(all, all, lv->avarinit[rpo]);
- if(bvcmp(any, lv->avarinitany[rpo])) {
- change = 1;
- bvcopy(lv->avarinitany[rpo], any);
- }
- if(bvcmp(all, lv->avarinitall[rpo])) {
- change = 1;
- bvcopy(lv->avarinitall[rpo], all);
- }
- }
- }
-
- // Iterate through the blocks in reverse round-robin fashion. A work
- // queue might be slightly faster. As is, the number of iterations is
- // so low that it hardly seems to be worth the complexity.
- change = 1;
- while(change != 0) {
- change = 0;
- // Walk blocks in the general direction of propagation. This
- // improves convergence.
- for(i = arraylength(lv->cfg) - 1; i >= 0; i--) {
- // A variable is live on output from this block
- // if it is live on input to some successor.
- //
- // out[b] = \bigcup_{s \in succ[b]} in[s]
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
- rpo = bb->rpo;
- bvresetall(newliveout);
- for(j = 0; j < arraylength(bb->succ); j++) {
- succ = *(BasicBlock**)arrayget(bb->succ, j);
- bvor(newliveout, newliveout, lv->livein[succ->rpo]);
- }
- if(bvcmp(lv->liveout[rpo], newliveout)) {
- change = 1;
- bvcopy(lv->liveout[rpo], newliveout);
- }
-
- // A variable is live on input to this block
- // if it is live on output from this block and
- // not set by the code in this block.
- //
- // in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
- bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]);
- bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]);
- }
- }
-
- free(newlivein);
- free(newliveout);
- free(any);
- free(all);
-}
-
-// This function is slow but it is only used for generating debug prints.
-// Check whether n is marked live in args/locals.
-static int
-islive(Node *n, Bvec *args, Bvec *locals)
-{
- int i;
-
- switch(n->class) {
- case PPARAM:
- case PPARAMOUT:
- for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
- if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i))
- return 1;
- break;
- case PAUTO:
- for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
- if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i))
- return 1;
- break;
- }
- return 0;
-}
-
-// Visits all instructions in a basic block and computes a bit vector of live
-// variables at each safe point locations.
-static void
-livenessepilogue(Liveness *lv)
-{
- BasicBlock *bb, *pred;
- Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all;
- Node *n;
- Prog *p, *next;
- int32 i, j, numlive, startmsg, nmsg, nvars, pos;
- vlong xoffset;
- char **msg;
- Fmt fmt;
-
- nvars = arraylength(lv->vars);
- livein = bvalloc(nvars);
- liveout = bvalloc(nvars);
- uevar = bvalloc(nvars);
- varkill = bvalloc(nvars);
- avarinit = bvalloc(nvars);
- any = bvalloc(nvars);
- all = bvalloc(nvars);
- ambig = bvalloc(localswords() * BitsPerPointer);
- msg = nil;
- nmsg = 0;
- startmsg = 0;
-
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
-
- // Compute avarinitany and avarinitall for entry to block.
- // This duplicates information known during livenesssolve
- // but avoids storing two more vectors for each block.
- bvresetall(any);
- bvresetall(all);
- for(j = 0; j < arraylength(bb->pred); j++) {
- pred = *(BasicBlock**)arrayget(bb->pred, j);
- if(j == 0) {
- bvcopy(any, lv->avarinitany[pred->rpo]);
- bvcopy(all, lv->avarinitall[pred->rpo]);
- } else {
- bvor(any, any, lv->avarinitany[pred->rpo]);
- bvand(all, all, lv->avarinitall[pred->rpo]);
- }
- }
-
- // Walk forward through the basic block instructions and
- // allocate liveness maps for those instructions that need them.
- // Seed the maps with information about the addrtaken variables.
- for(p = bb->first;; p = p->link) {
- progeffects(p, lv->vars, uevar, varkill, avarinit);
- bvandnot(any, any, varkill);
- bvandnot(all, all, varkill);
- bvor(any, any, avarinit);
- bvor(all, all, avarinit);
-
- if(issafepoint(p)) {
- // Annotate ambiguously live variables so that they can
- // be zeroed at function entry.
- // livein and liveout are dead here and used as temporaries.
- bvresetall(livein);
- bvandnot(liveout, any, all);
- if(!bvisempty(liveout)) {
- for(pos = 0; pos < liveout->n; pos++) {
- if(!bvget(liveout, pos))
- continue;
- bvset(all, pos); // silence future warnings in this block
- n = *(Node**)arrayget(lv->vars, pos);
- if(!n->needzero) {
- n->needzero = 1;
- if(debuglive >= 1)
- warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
- // Record in 'ambiguous' bitmap.
- xoffset = n->xoffset + stkptrsize;
- twobitwalktype1(n->type, &xoffset, ambig);
- }
- }
- }
-
- // Allocate a bit vector for each class and facet of
- // value we are tracking.
-
- // Live stuff first.
- args = bvalloc(argswords() * BitsPerPointer);
- arrayadd(lv->argslivepointers, &args);
- locals = bvalloc(localswords() * BitsPerPointer);
- arrayadd(lv->livepointers, &locals);
-
- if(debuglive >= 3) {
- print("%P\n", p);
- printvars("avarinitany", any, lv->vars);
- }
-
- // Record any values with an "address taken" reaching
- // this code position as live. Must do now instead of below
- // because the any/all calculation requires walking forward
- // over the block (as this loop does), while the liveout
- // requires walking backward (as the next loop does).
- twobitlivepointermap(lv, any, lv->vars, args, locals);
- }
-
- if(p == bb->last)
- break;
- }
- bb->lastbitmapindex = arraylength(lv->livepointers) - 1;
- }
-
- for(i = 0; i < arraylength(lv->cfg); i++) {
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
-
- if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') {
- nmsg = arraylength(lv->livepointers);
- startmsg = nmsg;
- msg = xmalloc(nmsg*sizeof msg[0]);
- for(j=0; j<nmsg; j++)
- msg[j] = nil;
- }
-
- // walk backward, emit pcdata and populate the maps
- pos = bb->lastbitmapindex;
- if(pos < 0) {
- // the first block we encounter should have the ATEXT so
- // at no point should pos ever be less than zero.
- fatal("livenessepilogue");
- }
-
- bvcopy(livein, lv->liveout[bb->rpo]);
- for(p = bb->last; p != nil; p = next) {
- next = p->opt; // splicebefore modifies p->opt
- // Propagate liveness information
- progeffects(p, lv->vars, uevar, varkill, avarinit);
- bvcopy(liveout, livein);
- bvandnot(livein, liveout, varkill);
- bvor(livein, livein, uevar);
- if(debuglive >= 3 && issafepoint(p)){
- print("%P\n", p);
- printvars("uevar", uevar, lv->vars);
- printvars("varkill", varkill, lv->vars);
- printvars("livein", livein, lv->vars);
- printvars("liveout", liveout, lv->vars);
- }
- if(issafepoint(p)) {
- // Found an interesting instruction, record the
- // corresponding liveness information.
-
- // Useful sanity check: on entry to the function,
- // the only things that can possibly be live are the
- // input parameters.
- if(p->as == ATEXT) {
- for(j = 0; j < liveout->n; j++) {
- if(!bvget(liveout, j))
- continue;
- n = *(Node**)arrayget(lv->vars, j);
- if(n->class != PPARAM)
- yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n);
- }
- }
-
- // Record live pointers.
- args = *(Bvec**)arrayget(lv->argslivepointers, pos);
- locals = *(Bvec**)arrayget(lv->livepointers, pos);
- twobitlivepointermap(lv, liveout, lv->vars, args, locals);
-
- // Ambiguously live variables are zeroed immediately after
- // function entry. Mark them live for all the non-entry bitmaps
- // so that GODEBUG=gcdead=1 mode does not poison them.
- if(p->as == ACALL)
- bvor(locals, locals, ambig);
-
- // Show live pointer bitmaps.
- // We're interpreting the args and locals bitmap instead of liveout so that we
- // include the bits added by the avarinit logic in the
- // previous loop.
- if(msg != nil) {
- fmtstrinit(&fmt);
- fmtprint(&fmt, "%L: live at ", p->lineno);
- if(p->as == ACALL && p->to.node)
- fmtprint(&fmt, "call to %s:", ((Node*)(p->to.node))->sym->name);
- else if(p->as == ACALL)
- fmtprint(&fmt, "indirect call:");
- else
- fmtprint(&fmt, "entry to %s:", ((Node*)(p->from.node))->sym->name);
- numlive = 0;
- for(j = 0; j < arraylength(lv->vars); j++) {
- n = *(Node**)arrayget(lv->vars, j);
- if(islive(n, args, locals)) {
- fmtprint(&fmt, " %N", n);
- numlive++;
- }
- }
- fmtprint(&fmt, "\n");
- if(numlive == 0) // squelch message
- free(fmtstrflush(&fmt));
- else
- msg[--startmsg] = fmtstrflush(&fmt);
- }
-
- // Only CALL instructions need a PCDATA annotation.
- // The TEXT instruction annotation is implicit.
- if(p->as == ACALL) {
- if(isdeferreturn(p)) {
- // runtime.deferreturn modifies its return address to return
- // back to the CALL, not to the subsequent instruction.
- // Because the return comes back one instruction early,
- // the PCDATA must begin one instruction early too.
- // The instruction before a call to deferreturn is always a
- // no-op, to keep PC-specific data unambiguous.
- splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt);
- } else {
- splicebefore(lv, bb, newpcdataprog(p, pos), p);
- }
- }
-
- pos--;
- }
- }
- if(msg != nil) {
- for(j=startmsg; j<nmsg; j++)
- if(msg[j] != nil)
- print("%s", msg[j]);
- free(msg);
- msg = nil;
- nmsg = 0;
- startmsg = 0;
- }
- }
-
- free(livein);
- free(liveout);
- free(uevar);
- free(varkill);
- free(avarinit);
- free(any);
- free(all);
- free(ambig);
-
- flusherrors();
-}
-
-// FNV-1 hash function constants.
-#define H0 2166136261UL
-#define Hp 16777619UL
-/*c2go
-enum
-{
- H0 = 2166136261,
- Hp = 16777619,
-};
-*/
-
-static uint32
-hashbitmap(uint32 h, Bvec *bv)
-{
- int i, n;
- uint32 w;
-
- n = (bv->n+31)/32;
- for(i=0; i<n; i++) {
- w = bv->b[i];
- h = (h*Hp) ^ (w&0xff);
- h = (h*Hp) ^ ((w>>8)&0xff);
- h = (h*Hp) ^ ((w>>16)&0xff);
- h = (h*Hp) ^ ((w>>24)&0xff);
- }
- return h;
-}
-
-// Compact liveness information by coalescing identical per-call-site bitmaps.
-// The merging only happens for a single function, not across the entire binary.
-//
-// There are actually two lists of bitmaps, one list for the local variables and one
-// list for the function arguments. Both lists are indexed by the same PCDATA
-// index, so the corresponding pairs must be considered together when
-// merging duplicates. The argument bitmaps change much less often during
-// function execution than the local variable bitmaps, so it is possible that
-// we could introduce a separate PCDATA index for arguments vs locals and
-// then compact the set of argument bitmaps separately from the set of
-// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
-// is actually a net loss: we save about 50k of argument bitmaps but the new
-// PCDATA tables cost about 100k. So for now we keep using a single index for
-// both bitmap lists.
-static void
-livenesscompact(Liveness *lv)
-{
- int *table, *remap, i, j, n, tablesize, uniq;
- uint32 h;
- Bvec *local, *arg, *jlocal, *jarg;
- Prog *p;
-
- // Linear probing hash table of bitmaps seen so far.
- // The hash table has 4n entries to keep the linear
- // scan short. An entry of -1 indicates an empty slot.
- n = arraylength(lv->livepointers);
- tablesize = 4*n;
- table = xmalloc(tablesize*sizeof table[0]);
- memset(table, 0xff, tablesize*sizeof table[0]);
-
- // remap[i] = the new index of the old bit vector #i.
- remap = xmalloc(n*sizeof remap[0]);
- memset(remap, 0xff, n*sizeof remap[0]);
- uniq = 0; // unique tables found so far
-
- // Consider bit vectors in turn.
- // If new, assign next number using uniq,
- // record in remap, record in lv->livepointers and lv->argslivepointers
- // under the new index, and add entry to hash table.
- // If already seen, record earlier index in remap and free bitmaps.
- for(i=0; i<n; i++) {
- local = *(Bvec**)arrayget(lv->livepointers, i);
- arg = *(Bvec**)arrayget(lv->argslivepointers, i);
- h = hashbitmap(hashbitmap(H0, local), arg) % tablesize;
-
- for(;;) {
- j = table[h];
- if(j < 0)
- break;
- jlocal = *(Bvec**)arrayget(lv->livepointers, j);
- jarg = *(Bvec**)arrayget(lv->argslivepointers, j);
- if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) {
- free(local);
- free(arg);
- remap[i] = j;
- goto Next;
- }
- if(++h == tablesize)
- h = 0;
- }
- table[h] = uniq;
- remap[i] = uniq;
- *(Bvec**)arrayget(lv->livepointers, uniq) = local;
- *(Bvec**)arrayget(lv->argslivepointers, uniq) = arg;
- uniq++;
- Next:;
- }
-
- // We've already reordered lv->livepointers[0:uniq]
- // and lv->argslivepointers[0:uniq] and freed the bitmaps
- // we don't need anymore. Clear the pointers later in the
- // array so that we can tell where the coalesced bitmaps stop
- // and so that we don't double-free when cleaning up.
- for(j=uniq; j<n; j++) {
- *(Bvec**)arrayget(lv->livepointers, j) = nil;
- *(Bvec**)arrayget(lv->argslivepointers, j) = nil;
- }
-
- // Rewrite PCDATA instructions to use new numbering.
- for(p=lv->ptxt; p != P; p=p->link) {
- if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) {
- i = p->to.offset;
- if(i >= 0)
- p->to.offset = remap[i];
- }
- }
-
- free(table);
- free(remap);
-}
-
-static int
-printbitset(int printed, char *name, Array *vars, Bvec *bits)
-{
- int i, started;
- Node *n;
-
- started = 0;
- for(i=0; i<arraylength(vars); i++) {
- if(!bvget(bits, i))
- continue;
- if(!started) {
- if(!printed)
- print("\t");
- else
- print(" ");
- started = 1;
- printed = 1;
- print("%s=", name);
- } else {
- print(",");
- }
- n = *(Node**)arrayget(vars, i);
- print("%s", n->sym->name);
- }
- return printed;
-}
-
-// Prints the computed liveness information and inputs, for debugging.
-// This format synthesizes the information used during the multiple passes
-// into a single presentation.
-static void
-livenessprintdebug(Liveness *lv)
-{
- int i, j, pcdata, printed;
- BasicBlock *bb;
- Prog *p;
- Bvec *uevar, *varkill, *avarinit, *args, *locals;
- Node *n;
-
- print("liveness: %s\n", curfn->nname->sym->name);
-
- uevar = bvalloc(arraylength(lv->vars));
- varkill = bvalloc(arraylength(lv->vars));
- avarinit = bvalloc(arraylength(lv->vars));
-
- pcdata = 0;
- for(i = 0; i < arraylength(lv->cfg); i++) {
- if(i > 0)
- print("\n");
- bb = *(BasicBlock**)arrayget(lv->cfg, i);
-
- // bb#0 pred=1,2 succ=3,4
- print("bb#%d pred=", i);
- for(j = 0; j < arraylength(bb->pred); j++) {
- if(j > 0)
- print(",");
- print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo);
- }
- print(" succ=");
- for(j = 0; j < arraylength(bb->succ); j++) {
- if(j > 0)
- print(",");
- print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo);
- }
- print("\n");
-
- // initial settings
- printed = 0;
- printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]);
- printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]);
- if(printed)
- print("\n");
-
- // program listing, with individual effects listed
- for(p = bb->first;; p = p->link) {
- print("%P\n", p);
- if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex)
- pcdata = p->to.offset;
- progeffects(p, lv->vars, uevar, varkill, avarinit);
- printed = 0;
- printed = printbitset(printed, "uevar", lv->vars, uevar);
- printed = printbitset(printed, "varkill", lv->vars, varkill);
- printed = printbitset(printed, "avarinit", lv->vars, avarinit);
- if(printed)
- print("\n");
- if(issafepoint(p)) {
- args = *(Bvec**)arrayget(lv->argslivepointers, pcdata);
- locals = *(Bvec**)arrayget(lv->livepointers, pcdata);
- print("\tlive=");
- printed = 0;
- for(j = 0; j < arraylength(lv->vars); j++) {
- n = *(Node**)arrayget(lv->vars, j);
- if(islive(n, args, locals)) {
- if(printed++)
- print(",");
- print("%N", n);
- }
- }
- print("\n");
- }
- if(p == bb->last)
- break;
- }
-
- // bb bitsets
- print("end\n");
- printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]);
- printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]);
- printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]);
- printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]);
- printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]);
- if(printed)
- print("\n");
- }
- print("\n");
-
- free(uevar);
- free(varkill);
- free(avarinit);
-}
-
-// Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The
-// first word dumped is the total number of bitmaps. The second word is the
-// length of the bitmaps. All bitmaps are assumed to be of equal length. The
-// words that are followed are the raw bitmap words. The arr argument is an
-// array of Node*s.
-static void
-twobitwritesymbol(Array *arr, Sym *sym)
-{
- Bvec *bv;
- int off, i, j, n;
- uint32 word;
-
- n = arraylength(arr);
- off = 0;
- off += 4; // number of bitmaps, to fill in later
- bv = *(Bvec**)arrayget(arr, 0);
- off = duint32(sym, off, bv->n); // number of bits in each bitmap
- for(i = 0; i < n; i++) {
- // bitmap words
- bv = *(Bvec**)arrayget(arr, i);
- if(bv == nil)
- break;
- for(j = 0; j < bv->n; j += 32) {
- word = bv->b[j/32];
- // Runtime reads the bitmaps as byte arrays. Oblige.
- off = duint8(sym, off, word);
- off = duint8(sym, off, word>>8);
- off = duint8(sym, off, word>>16);
- off = duint8(sym, off, word>>24);
- }
- }
- duint32(sym, 0, i); // number of bitmaps
- ggloblsym(sym, off, RODATA);
-}
-
-static void
-printprog(Prog *p)
-{
- while(p != nil) {
- print("%P\n", p);
- p = p->link;
- }
-}
-
-// Entry pointer for liveness analysis. Constructs a complete CFG, solves for
-// the liveness of pointer variables in the function, and emits a runtime data
-// structure read by the garbage collector.
-void
-liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym)
-{
- Array *cfg, *vars;
- Liveness *lv;
- int debugdelta;
- NodeList *l;
-
- // Change name to dump debugging information only for a specific function.
- debugdelta = 0;
- if(strcmp(curfn->nname->sym->name, "!") == 0)
- debugdelta = 2;
-
- debuglive += debugdelta;
- if(debuglive >= 3) {
- print("liveness: %s\n", curfn->nname->sym->name);
- printprog(firstp);
- }
- checkptxt(fn, firstp);
-
- // Construct the global liveness state.
- cfg = newcfg(firstp);
- if(debuglive >= 3)
- printcfg(cfg);
- vars = getvariables(fn);
- lv = newliveness(fn, firstp, cfg, vars);
-
- // Run the dataflow framework.
- livenessprologue(lv);
- if(debuglive >= 3)
- livenessprintcfg(lv);
- livenesssolve(lv);
- if(debuglive >= 3)
- livenessprintcfg(lv);
- livenessepilogue(lv);
- if(debuglive >= 3)
- livenessprintcfg(lv);
- livenesscompact(lv);
-
- if(debuglive >= 2)
- livenessprintdebug(lv);
-
- // Emit the live pointer map data structures
- twobitwritesymbol(lv->livepointers, livesym);
- twobitwritesymbol(lv->argslivepointers, argssym);
-
- // Free everything.
- for(l=fn->dcl; l != nil; l = l->next)
- if(l->n != N)
- l->n->opt = nil;
- freeliveness(lv);
- arrayfree(vars);
- freecfg(cfg);
-
- debuglive -= debugdelta;
-}
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
deleted file mode 100644
index b02d58e663..0000000000
--- a/src/cmd/gc/popt.c
+++ /dev/null
@@ -1,1022 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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.
-
-// "Portable" optimizations.
-// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
-// Must code to the intersection of the three back ends.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "popt.h"
-
-// p is a call instruction. Does the call fail to return?
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
- static Sym* symlist[10];
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("gopanic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- symlist[5] = pkglookup("throwreturn", runtimepkg);
- symlist[6] = pkglookup("selectgo", runtimepkg);
- symlist[7] = pkglookup("block", runtimepkg);
- }
-
- if(p->to.node == nil)
- return 0;
- s = ((Node*)(p->to.node))->sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
-// JMP chasing and removal.
-//
-// The code generator depends on being able to write out jump
-// instructions that it can jump to now but fill in later.
-// the linker will resolve them nicely, but they make the code
-// longer and more difficult to follow during debugging.
-// Remove them.
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
- int n;
-
- n = 0;
- while(p != P && p->as == AJMP && p->to.type == TYPE_BRANCH) {
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- p = p->to.u.branch;
- }
- return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-/*c2go
-extern void *alive;
-extern void *dead;
-*/
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
- Prog *p;
-
- for(p=firstp; p; p=p->link) {
- if(p->opt != dead)
- break;
- p->opt = alive;
- if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch)
- mark(p->to.u.branch);
- if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
- break;
- }
-}
-
-void
-fixjmp(Prog *firstp)
-{
- int jmploop;
- Prog *p, *last;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to jump, mark all code as dead.
- jmploop = 0;
- for(p=firstp; p; p=p->link) {
- if(debug['R'] && debug['v'])
- print("%P\n", p);
- if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
- p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- p->opt = dead;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstp);
-
- // pass 3: delete dead code (mostly JMPs).
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->opt == dead) {
- if(p->link == P && p->as == ARET && last && last->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay. The register allocator assumes that all live code in
- // the function can be traversed by starting at all the RET instructions
- // and following predecessor links. If we remove the final RET,
- // this assumption will not hold in the case of an infinite loop
- // at the end of a function.
- // Keep the RET but mark it dead for the liveness analysis.
- p->mode = 1;
- } else {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->as == AJMP && p->to.type == TYPE_BRANCH && p->to.u.branch == p->link) {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(p=firstp; p; p=p->link)
- print("%P\n", p);
- print("\n");
- }
-}
-
-#undef alive
-#undef dead
-
-// Control flow analysis. The Flow structures hold predecessor and successor
-// information as well as basic loop analysis.
-//
-// graph = flowstart(firstp, 0);
-// ... use flow graph ...
-// flowend(graph); // free graph
-//
-// Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
-//
-// for(f = graph->start; f != nil; f = f->link)
-//
-// or, given an instruction f, to iterate over all the predecessors, which is
-// f->p1 and this list:
-//
-// for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
-//
-// The size argument to flowstart specifies an amount of zeroed memory
-// to allocate in every f->data field, for use by the client.
-// If size == 0, f->data will be nil.
-
-Graph*
-flowstart(Prog *firstp, int size)
-{
- int id, nf;
- Flow *f, *f1, *start, *last;
- Graph *graph;
- Prog *p;
- ProgInfo info;
- char *data;
-
- // Count and mark instructions to annotate.
- nf = 0;
- for(p = firstp; p != P; p = p->link) {
- p->opt = nil; // should be already, but just in case
- thearch.proginfo(&info, p);
- if(info.flags & Skip)
- continue;
- p->opt = (void*)1;
- nf++;
- }
-
- if(nf == 0)
- return nil;
-
- if(nf >= 20000) {
- // fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
- return nil;
- }
-
- // Allocate annotations and assign to instructions.
- graph = calloc(sizeof *graph + sizeof(Flow)*nf + size*nf, 1);
- if(graph == nil)
- fatal("out of memory");
- start = (Flow*)(graph+1);
- last = nil;
- f = start;
- data = (char*)(f+nf);
- if(size == 0)
- data = nil;
- id = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->opt == nil)
- continue;
- p->opt = f;
- f->prog = p;
- if(last)
- last->link = f;
- last = f;
- f->data = data;
- f->id = id;
- f++;
- id++;
- data += size;
- }
-
- // Fill in pred/succ information.
- for(f = start; f != nil; f = f->link) {
- p = f->prog;
- thearch.proginfo(&info, p);
- if(!(info.flags & Break)) {
- f1 = f->link;
- f->s1 = f1;
- f1->p1 = f;
- }
- if(p->to.type == TYPE_BRANCH) {
- if(p->to.u.branch == P)
- fatal("pnil %P", p);
- f1 = p->to.u.branch->opt;
- if(f1 == nil)
- fatal("fnil %P / %P", p, p->to.u.branch);
- if(f1 == f) {
- //fatal("self loop %P", p);
- continue;
- }
- f->s2 = f1;
- f->p2link = f1->p2;
- f1->p2 = f;
- }
- }
-
- graph->start = start;
- graph->num = nf;
- return graph;
-}
-
-void
-flowend(Graph *graph)
-{
- Flow *f;
-
- for(f = graph->start; f != nil; f = f->link)
- f->prog->opt = nil;
- free(graph);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-static int32
-postorder(Flow *r, Flow **rpo2r, int32 n)
-{
- Flow *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-static int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal("bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-static int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-static int
-loophead(int32 *idom, Flow *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != nil && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != nil; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-static void
-loopmark(Flow **rpo2r, int32 head, Flow *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != nil)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != nil; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-flowrpo(Graph *g)
-{
- Flow *r1;
- int32 i, d, me, nr, *idom;
- Flow **rpo2r;
-
- free(g->rpo);
- g->rpo = calloc(g->num*sizeof g->rpo[0], 1);
- idom = calloc(g->num*sizeof idom[0], 1);
- if(g->rpo == nil || idom == nil)
- fatal("out of memory");
-
- for(r1 = g->start; r1 != nil; r1 = r1->link)
- r1->active = 0;
-
- rpo2r = g->rpo;
- d = postorder(g->start, rpo2r, 0);
- nr = g->num;
- if(d > nr)
- fatal("too many reg nodes %d %d", d, nr);
- nr = d;
- for(i = 0; i < nr / 2; i++) {
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++) {
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- // rpo2r[r->rpo] == r protects against considering dead code,
- // which has r->rpo == 0.
- if(r1->p1 != nil && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++) {
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != nil && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
- free(idom);
-
- for(r1 = g->start; r1 != nil; r1 = r1->link)
- r1->active = 0;
-}
-
-Flow*
-uniqp(Flow *r)
-{
- Flow *r1;
-
- r1 = r->p1;
- if(r1 == nil) {
- r1 = r->p2;
- if(r1 == nil || r1->p2link != nil)
- return nil;
- } else
- if(r->p2 != nil)
- return nil;
- return r1;
-}
-
-Flow*
-uniqs(Flow *r)
-{
- Flow *r1;
-
- r1 = r->s1;
- if(r1 == nil) {
- r1 = r->s2;
- if(r1 == nil)
- return nil;
- } else
- if(r->s2 != nil)
- return nil;
- return r1;
-}
-
-// The compilers assume they can generate temporary variables
-// as needed to preserve the right semantics or simplify code
-// generation and the back end will still generate good code.
-// This results in a large number of ephemeral temporary variables.
-// Merge temps with non-overlapping lifetimes and equal types using the
-// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
-// ACM TOPLAS 1999.
-
-typedef struct TempVar TempVar;
-
-struct TempVar
-{
- Node *node;
- Flow *def; // definition of temp var
- Flow *use; // use list, chained through Flow.data
- TempVar *freelink; // next free temp in Type.opt list
- TempVar *merge; // merge var with this one
- vlong start; // smallest Prog.pc in live range
- vlong end; // largest Prog.pc in live range
- uchar addr; // address taken - no accurate end
- uchar removed; // removed from program
-};
-
-static int
-startcmp(const void *va, const void *vb)
-{
- TempVar *a, *b;
-
- a = *(TempVar**)va;
- b = *(TempVar**)vb;
-
- if(a->start < b->start)
- return -1;
- if(a->start > b->start)
- return +1;
- // Order what's left by id or symbol name,
- // just so that sort is forced into a specific ordering,
- // so that the result of the sort does not depend on
- // the sort implementation.
- if(a->def != b->def)
- return a->def->id - b->def->id;
- if(a->node != b->node)
- return strcmp(a->node->sym->name, b->node->sym->name);
- return 0;
-}
-
-// Is n available for merging?
-static int
-canmerge(Node *n)
-{
- return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
-}
-
-static void mergewalk(TempVar*, Flow*, uint32);
-static void varkillwalk(TempVar*, Flow*, uint32);
-
-void
-mergetemp(Prog *firstp)
-{
- int i, j, nvar, ninuse, nfree, nkill;
- TempVar *var, *v, *v1, **bystart, **inuse;
- Flow *f;
- NodeList *l, **lp;
- Node *n;
- Prog *p, *p1;
- Type *t;
- ProgInfo info, info1;
- int32 gen;
- Graph *g;
-
- enum { debugmerge = 1 };
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
-
- // Build list of all mergeable variables.
- nvar = 0;
- for(l = curfn->dcl; l != nil; l = l->next)
- if(canmerge(l->n))
- nvar++;
-
- var = calloc(nvar*sizeof var[0], 1);
- nvar = 0;
- for(l = curfn->dcl; l != nil; l = l->next) {
- n = l->n;
- if(canmerge(n)) {
- v = &var[nvar++];
- n->opt = v;
- v->node = n;
- }
- }
-
- // Build list of uses.
- // We assume that the earliest reference to a temporary is its definition.
- // This is not true of variables in general but our temporaries are all
- // single-use (that's why we have so many!).
- for(f = g->start; f != nil; f = f->link) {
- p = f->prog;
- thearch.proginfo(&info, p);
-
- if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt)
- fatal("double node %P", p);
- v = nil;
- if((n = p->from.node) != N)
- v = n->opt;
- if(v == nil && (n = p->to.node) != N)
- v = n->opt;
- if(v != nil) {
- if(v->def == nil)
- v->def = f;
- f->data = v->use;
- v->use = f;
- if(n == p->from.node && (info.flags & LeftAddr))
- v->addr = 1;
- }
- }
-
- if(debugmerge > 1 && debug['v'])
- dumpit("before", g->start, 0);
-
- nkill = 0;
-
- // Special case.
- for(i = 0; i < nvar; i++) {
- v = &var[i];
- if(v->addr)
- continue;
- // Used in only one instruction, which had better be a write.
- if((f = v->use) != nil && (Flow*)f->data == nil) {
- p = f->prog;
- thearch.proginfo(&info, p);
- if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
- p->as = ANOP;
- p->to = zprog.to;
- v->removed = 1;
- if(debugmerge > 0 && debug['v'])
- print("drop write-only %S\n", v->node->sym);
- } else
- fatal("temp used and not set: %P", p);
- nkill++;
- continue;
- }
-
- // Written in one instruction, read in the next, otherwise unused,
- // no jumps to the next instruction. Happens mainly in 386 compiler.
- if((f = v->use) != nil && f->link == (Flow*)f->data && (Flow*)((Flow*)f->data)->data == nil && uniqp(f->link) == f) {
- p = f->prog;
- thearch.proginfo(&info, p);
- p1 = f->link->prog;
- thearch.proginfo(&info1, p1);
- enum {
- SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
- };
- if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) &&
- !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
- (info.flags & SizeAny) == (info1.flags & SizeAny)) {
- p1->from = p->from;
- thearch.excise(f);
- v->removed = 1;
- if(debugmerge > 0 && debug['v'])
- print("drop immediate-use %S\n", v->node->sym);
- }
- nkill++;
- continue;
- }
- }
-
- // Traverse live range of each variable to set start, end.
- // Each flood uses a new value of gen so that we don't have
- // to clear all the r->active words after each variable.
- gen = 0;
- for(i = 0; i < nvar; i++) {
- v = &var[i];
- gen++;
- for(f = v->use; f != nil; f = (Flow*)f->data)
- mergewalk(v, f, gen);
- if(v->addr) {
- gen++;
- for(f = v->use; f != nil; f = (Flow*)f->data)
- varkillwalk(v, f, gen);
- }
- }
-
- // Sort variables by start.
- bystart = malloc(nvar*sizeof bystart[0]);
- for(i=0; i<nvar; i++)
- bystart[i] = &var[i];
- qsort(bystart, nvar, sizeof bystart[0], startcmp);
-
- // List of in-use variables, sorted by end, so that the ones that
- // will last the longest are the earliest ones in the array.
- // The tail inuse[nfree:] holds no-longer-used variables.
- // In theory we should use a sorted tree so that insertions are
- // guaranteed O(log n) and then the loop is guaranteed O(n log n).
- // In practice, it doesn't really matter.
- inuse = malloc(nvar*sizeof inuse[0]);
- ninuse = 0;
- nfree = nvar;
- for(i=0; i<nvar; i++) {
- v = bystart[i];
- if(debugmerge > 0 && debug['v'])
- print("consider %#N: removed=%d\n", v->node, v->removed);
-
- if(v->removed)
- continue;
-
- // Expire no longer in use.
- while(ninuse > 0 && inuse[ninuse-1]->end < v->start) {
- v1 = inuse[--ninuse];
- inuse[--nfree] = v1;
- }
-
- if(debugmerge > 0 && debug['v'])
- print("consider %#N: removed=%d nfree=%d nvar=%d\n", v->node, v->removed, nfree, nvar);
- // Find old temp to reuse if possible.
- t = v->node->type;
- for(j=nfree; j<nvar; j++) {
- v1 = inuse[j];
- if(debugmerge > 0 && debug['v'])
- print("consider %#N: maybe %#N: type=%T,%T addrtaken=%d,%d\n", v->node, v1->node, t, v1->node->type, v->node->addrtaken, v1->node->addrtaken);
- // Require the types to match but also require the addrtaken bits to match.
- // If a variable's address is taken, that disables registerization for the individual
- // words of the variable (for example, the base,len,cap of a slice).
- // We don't want to merge a non-addressed var with an addressed one and
- // inhibit registerization of the former.
- if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) {
- inuse[j] = inuse[nfree++];
- if(v1->merge)
- v->merge = v1->merge;
- else
- v->merge = v1;
- nkill++;
- break;
- }
- }
-
- // Sort v into inuse.
- j = ninuse++;
- while(j > 0 && inuse[j-1]->end < v->end) {
- inuse[j] = inuse[j-1];
- j--;
- }
- inuse[j] = v;
- }
-
- if(debugmerge > 0 && debug['v']) {
- print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
- for(i = 0; i < nvar; i++) {
- v = &var[i];
- print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
- if(v->addr)
- print(" addr=1");
- if(v->removed)
- print(" dead=1");
- if(v->merge)
- print(" merge %#N", v->merge->node);
- if(v->start == v->end && v->def != nil)
- print(" %P", v->def->prog);
- print("\n");
- }
-
- if(debugmerge > 1 && debug['v'])
- dumpit("after", g->start, 0);
- }
-
- // Update node references to use merged temporaries.
- for(f = g->start; f != nil; f = f->link) {
- p = f->prog;
- if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
- p->from.node = v->merge->node;
- if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
- p->to.node = v->merge->node;
- }
-
- // Delete merged nodes from declaration list.
- for(lp = &curfn->dcl; (l = *lp); ) {
- curfn->dcl->end = l;
- n = l->n;
- v = n->opt;
- if(v && (v->merge || v->removed)) {
- *lp = l->next;
- continue;
- }
- lp = &l->next;
- }
-
- // Clear aux structures.
- for(i = 0; i < nvar; i++)
- var[i].node->opt = nil;
-
- free(var);
- free(bystart);
- free(inuse);
- flowend(g);
-}
-
-static void
-mergewalk(TempVar *v, Flow *f0, uint32 gen)
-{
- Prog *p;
- Flow *f1, *f, *f2;
-
- for(f1 = f0; f1 != nil; f1 = f1->p1) {
- if(f1->active == gen)
- break;
- f1->active = gen;
- p = f1->prog;
- if(v->end < p->pc)
- v->end = p->pc;
- if(f1 == v->def) {
- v->start = p->pc;
- break;
- }
- }
-
- for(f = f0; f != f1; f = f->p1)
- for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
- mergewalk(v, f2, gen);
-}
-
-static void
-varkillwalk(TempVar *v, Flow *f0, uint32 gen)
-{
- Prog *p;
- Flow *f1, *f;
-
- for(f1 = f0; f1 != nil; f1 = f1->s1) {
- if(f1->active == gen)
- break;
- f1->active = gen;
- p = f1->prog;
- if(v->end < p->pc)
- v->end = p->pc;
- if(v->start > p->pc)
- v->start = p->pc;
- if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node))
- break;
- }
-
- for(f = f0; f != f1; f = f->s1)
- varkillwalk(v, f->s2, gen);
-}
-
-// Eliminate redundant nil pointer checks.
-//
-// The code generation pass emits a CHECKNIL for every possibly nil pointer.
-// This pass removes a CHECKNIL if every predecessor path has already
-// checked this value for nil.
-//
-// Simple backwards flood from check to definition.
-// Run prog loop backward from end of program to beginning to avoid quadratic
-// behavior removing a run of checks.
-//
-// Assume that stack variables with address not taken can be loaded multiple times
-// from memory without being rechecked. Other variables need to be checked on
-// each load.
-
-typedef struct NilVar NilVar;
-
-static void nilwalkback(Flow *rcheck);
-static void nilwalkfwd(Flow *rcheck);
-
-static int killed; // f->data is either nil or &killed
-
-void
-nilopt(Prog *firstp)
-{
- Flow *f;
- Prog *p;
- Graph *g;
- int ncheck, nkill;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
-
- if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */)
- dumpit("nilopt", g->start, 0);
-
- ncheck = 0;
- nkill = 0;
- for(f = g->start; f != nil; f = f->link) {
- p = f->prog;
- if(p->as != ACHECKNIL || !thearch.regtyp(&p->from))
- continue;
- ncheck++;
- if(thearch.stackaddr(&p->from)) {
- if(debug_checknil && p->lineno > 1)
- warnl(p->lineno, "removed nil check of SP address");
- f->data = &killed;
- continue;
- }
- nilwalkfwd(f);
- if(f->data != nil) {
- if(debug_checknil && p->lineno > 1)
- warnl(p->lineno, "removed nil check before indirect");
- continue;
- }
- nilwalkback(f);
- if(f->data != nil) {
- if(debug_checknil && p->lineno > 1)
- warnl(p->lineno, "removed repeated nil check");
- continue;
- }
- }
-
- for(f = g->start; f != nil; f = f->link) {
- if(f->data != nil) {
- nkill++;
- thearch.excise(f);
- }
- }
-
- flowend(g);
-
- if(debug_checknil > 1)
- print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck);
-}
-
-static void
-nilwalkback(Flow *fcheck)
-{
- Prog *p;
- ProgInfo info;
- Flow *f;
-
- for(f = fcheck; f != nil; f = uniqp(f)) {
- p = f->prog;
- thearch.proginfo(&info, p);
- if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
- // Found initialization of value we're checking for nil.
- // without first finding the check, so this one is unchecked.
- return;
- }
- if(f != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from)) {
- fcheck->data = &killed;
- return;
- }
- }
-
- // Here is a more complex version that scans backward across branches.
- // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
- // to keep the check (setting fcheck->kill = 0).
- // It doesn't handle copying of aggregates as well as I would like,
- // nor variables with their address taken,
- // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
- /*
- for(f1 = f0; f1 != nil; f1 = f1->p1) {
- if(f1->active == gen)
- break;
- f1->active = gen;
- p = f1->prog;
-
- // If same check, stop this loop but still check
- // alternate predecessors up to this point.
- if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
- break;
-
- thearch.proginfo(&info, p);
- if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
- // Found initialization of value we're checking for nil.
- // without first finding the check, so this one is unchecked.
- fcheck->kill = 0;
- return;
- }
-
- if(f1->p1 == nil && f1->p2 == nil) {
- print("lost pred for %P\n", fcheck->prog);
- for(f1=f0; f1!=nil; f1=f1->p1) {
- thearch.proginfo(&info, f1->prog);
- print("\t%P %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
- }
- fatal("lost pred trail");
- }
- }
-
- for(f = f0; f != f1; f = f->p1)
- for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
- nilwalkback(fcheck, f2, gen);
- */
-}
-
-static void
-nilwalkfwd(Flow *fcheck)
-{
- Flow *f, *last;
- Prog *p;
- ProgInfo info;
-
- // If the path down from rcheck dereferences the address
- // (possibly with a small offset) before writing to memory
- // and before any subsequent checks, it's okay to wait for
- // that implicit check. Only consider this basic block to
- // avoid problems like:
- // _ = *x // should panic
- // for {} // no writes but infinite loop may be considered visible
- last = nil;
- for(f = uniqs(fcheck); f != nil; f = uniqs(f)) {
- p = f->prog;
- thearch.proginfo(&info, p);
-
- if((info.flags & LeftRead) && thearch.smallindir(&p->from, &fcheck->prog->from)) {
- fcheck->data = &killed;
- return;
- }
- if((info.flags & (RightRead|RightWrite)) && thearch.smallindir(&p->to, &fcheck->prog->from)) {
- fcheck->data = &killed;
- return;
- }
-
- // Stop if another nil check happens.
- if(p->as == ACHECKNIL)
- return;
- // Stop if value is lost.
- if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from))
- return;
- // Stop if memory write.
- if((info.flags & RightWrite) && !thearch.regtyp(&p->to))
- return;
- // Stop if we jump backward.
- if(last != nil && f->id <= last->id)
- return;
- last = f;
- }
-}
diff --git a/src/cmd/gc/popt.h b/src/cmd/gc/popt.h
deleted file mode 100644
index 4e89dbd678..0000000000
--- a/src/cmd/gc/popt.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-// 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.
-
-#define Z N
-#define Adr Addr
-
-#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])
-
-enum
-{
- CLOAD = 5,
- CREF = 5,
- CINF = 1000,
- LOOP = 3,
-};
-
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-/*c2go
-extern Node *Z;
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint64 LOAD(Reg*);
-uint64 STORE(Reg*);
-*/
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-struct Reg
-{
- Bits set; // regopt variables written by this instruction.
- Bits use1; // regopt variables read by prog->from.
- Bits use2; // regopt variables read by prog->to.
-
- // refahead/refbehind are the regopt variables whose current
- // value may be used in the following/preceding instructions
- // up to a CALL (or the value is clobbered).
- Bits refbehind;
- Bits refahead;
- // calahead/calbehind are similar, but for variables in
- // instructions that are reachable after hitting at least one
- // CALL.
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- uint64 regu; // register used bitmap
-};
-#define R ((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define NRGN 600
-/*c2go enum { NRGN = 600 }; */
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches. A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-struct Rgn
-{
- Flow* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN Reg zreg;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN uint64 regbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ivar;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-
-typedef struct OptStats OptStats;
-struct OptStats
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-};
-
-EXTERN OptStats ostats;
-
-/*
- * reg.c
- */
-void regopt(Prog*);
-void dumpone(Flow*, int);
-void dumpit(char*, Flow*, int);
-
-/*
- * peep.c
-void peep(Prog*);
-void excise(Flow*);
-int copyu(Prog*, Adr*, Adr*);
- */
-
-/*
- * prog.c
-
-void proginfo(ProgInfo*, Prog*);
- */
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
deleted file mode 100644
index 3aa7e36386..0000000000
--- a/src/cmd/gc/racewalk.c
+++ /dev/null
@@ -1,653 +0,0 @@
-// 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.
-
-// The racewalk pass modifies the code tree for the function as follows:
-//
-// 1. It inserts a call to racefuncenter at the beginning of each function.
-// 2. It inserts a call to racefuncexit at the end of each function.
-// 3. It inserts a call to raceread before each memory read.
-// 4. It inserts a call to racewrite before each memory write.
-//
-// The rewriting is not yet complete. Certain nodes are not rewritten
-// but should be.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// TODO(dvyukov): do not instrument initialization as writes:
-// a := make([]int, 10)
-
-static void racewalklist(NodeList *l, NodeList **init);
-static void racewalknode(Node **np, NodeList **init, int wr, int skip);
-static int callinstr(Node **n, NodeList **init, int wr, int skip);
-static Node* uintptraddr(Node *n);
-static void makeaddable(Node *n);
-static void foreach(Node *n, void(*f)(Node*, void*), void *c);
-static void hascallspred(Node *n, void *c);
-static void appendinit(Node **np, NodeList *init);
-static Node* detachexpr(Node *n, NodeList **init);
-
-// Do not instrument the following packages at all,
-// at best instrumentation would cause infinite recursion.
-static const char *omit_pkgs[] = {"runtime", "runtime/race"};
-// Only insert racefuncenter/racefuncexit into the following packages.
-// Memory accesses in the packages are either uninteresting or will cause false positives.
-static const char *noinst_pkgs[] = {"sync", "sync/atomic"};
-
-static int
-ispkgin(const char **pkgs, int n)
-{
- int i;
-
- if(myimportpath) {
- for(i=0; i<n; i++) {
- if(strcmp(myimportpath, pkgs[i]) == 0)
- return 1;
- }
- }
- return 0;
-}
-
-static int
-isforkfunc(Node *fn)
-{
- // Special case for syscall.forkAndExecInChild.
- // In the child, this function must not acquire any locks, because
- // they might have been locked at the time of the fork. This means
- // no rescheduling, no malloc calls, and no new stack segments.
- // Race instrumentation does all of the above.
- return myimportpath != nil && strcmp(myimportpath, "syscall") == 0 &&
- strcmp(fn->nname->sym->name, "forkAndExecInChild") == 0;
-}
-
-void
-racewalk(Node *fn)
-{
- Node *nd;
- Node *nodpc;
- char s[1024];
-
- if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn))
- return;
-
- if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) {
- racewalklist(fn->nbody, nil);
- // nothing interesting for race detector in fn->enter
- racewalklist(fn->exit, nil);
- }
-
- // nodpc is the PC of the caller as extracted by
- // getcallerpc. We use -widthptr(FP) for x86.
- // BUG: this will not work on arm.
- nodpc = nod(OXXX, nil, nil);
- *nodpc = *nodfp;
- nodpc->type = types[TUINTPTR];
- nodpc->xoffset = -widthptr;
- nd = mkcall("racefuncenter", T, nil, nodpc);
- fn->enter = concat(list1(nd), fn->enter);
- nd = mkcall("racefuncexit", T, nil);
- fn->exit = list(fn->exit, nd);
-
- if(debug['W']) {
- snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym);
- dumplist(s, fn->nbody);
- snprint(s, sizeof(s), "enter %S", fn->nname->sym);
- dumplist(s, fn->enter);
- snprint(s, sizeof(s), "exit %S", fn->nname->sym);
- dumplist(s, fn->exit);
- }
-}
-
-static void
-racewalklist(NodeList *l, NodeList **init)
-{
- NodeList *instr;
-
- for(; l; l = l->next) {
- instr = nil;
- racewalknode(&l->n, &instr, 0, 0);
- if(init == nil)
- l->n->ninit = concat(l->n->ninit, instr);
- else
- *init = concat(*init, instr);
- }
-}
-
-// walkexpr and walkstmt combined
-// walks the tree and adds calls to the
-// instrumentation code to top-level (statement) nodes' init
-static void
-racewalknode(Node **np, NodeList **init, int wr, int skip)
-{
- Node *n, *n1;
- NodeList *l;
- NodeList *fini;
-
- n = *np;
-
- if(n == N)
- return;
-
- if(debug['w'] > 1)
- dump("racewalk-before", n);
- setlineno(n);
- if(init == nil)
- fatal("racewalk: bad init list");
- if(init == &n->ninit) {
- // If init == &n->ninit and n->ninit is non-nil,
- // racewalknode might append it to itself.
- // nil it out and handle it separately before putting it back.
- l = n->ninit;
- n->ninit = nil;
- racewalklist(l, nil);
- racewalknode(&n, &l, wr, skip); // recurse with nil n->ninit
- appendinit(&n, l);
- *np = n;
- return;
- }
-
- racewalklist(n->ninit, nil);
-
- switch(n->op) {
- default:
- fatal("racewalk: unknown node type %O", n->op);
-
- case OAS:
- case OAS2FUNC:
- racewalknode(&n->left, init, 1, 0);
- racewalknode(&n->right, init, 0, 0);
- goto ret;
-
- case OCFUNC:
- case OVARKILL:
- // can't matter
- goto ret;
-
- case OBLOCK:
- if(n->list == nil)
- goto ret;
-
- switch(n->list->n->op) {
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- // Blocks are used for multiple return function calls.
- // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
- // We don't want to instrument between the statements because it will
- // smash the results.
- racewalknode(&n->list->n, &n->list->n->ninit, 0, 0);
- fini = nil;
- racewalklist(n->list->next, &fini);
- n->list = concat(n->list, fini);
- break;
-
- default:
- // Ordinary block, for loop initialization or inlined bodies.
- racewalklist(n->list, nil);
- break;
- }
- goto ret;
-
- case ODEFER:
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case OPROC:
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case OCALLINTER:
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case OCALLFUNC:
- // Instrument dst argument of runtime.writebarrier* calls
- // as we do not instrument runtime code.
- // typedslicecopy is instrumented in runtime.
- if(n->left->sym != S && n->left->sym->pkg == runtimepkg &&
- (strncmp(n->left->sym->name, "writebarrier", 12) == 0 || strcmp(n->left->sym->name, "typedmemmove") == 0)) {
- // Find the dst argument.
- // The list can be reordered, so it's not necessary just the first or the second element.
- for(l = n->list; l; l = l->next) {
- if(strcmp(n->left->sym->name, "typedmemmove") == 0) {
- if(l->n->left->xoffset == widthptr)
- break;
- } else {
- if(l->n->left->xoffset == 0)
- break;
- }
- }
- if(l == nil)
- fatal("racewalk: writebarrier no arg");
- if(l->n->right->op != OADDR)
- fatal("racewalk: writebarrier bad arg");
- callinstr(&l->n->right->left, init, 1, 0);
- }
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case ONOT:
- case OMINUS:
- case OPLUS:
- case OREAL:
- case OIMAG:
- case OCOM:
- racewalknode(&n->left, init, wr, 0);
- goto ret;
-
- case ODOTINTER:
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case ODOT:
- racewalknode(&n->left, init, 0, 1);
- callinstr(&n, init, wr, skip);
- goto ret;
-
- case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
- racewalknode(&n->left, init, 0, 0);
- callinstr(&n, init, wr, skip);
- goto ret;
-
- case OIND: // *p
- racewalknode(&n->left, init, 0, 0);
- callinstr(&n, init, wr, skip);
- goto ret;
-
- case OSPTR:
- case OLEN:
- case OCAP:
- racewalknode(&n->left, init, 0, 0);
- if(istype(n->left->type, TMAP)) {
- n1 = nod(OCONVNOP, n->left, N);
- n1->type = ptrto(types[TUINT8]);
- n1 = nod(OIND, n1, N);
- typecheck(&n1, Erv);
- callinstr(&n1, init, 0, skip);
- }
- goto ret;
-
- case OLSH:
- case ORSH:
- case OLROT:
- case OAND:
- case OANDNOT:
- case OOR:
- case OXOR:
- case OSUB:
- case OMUL:
- case OHMUL:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OADD:
- case OCOMPLEX:
- racewalknode(&n->left, init, wr, 0);
- racewalknode(&n->right, init, wr, 0);
- goto ret;
-
- case OANDAND:
- case OOROR:
- racewalknode(&n->left, init, wr, 0);
- // walk has ensured the node has moved to a location where
- // side effects are safe.
- // n->right may not be executed,
- // so instrumentation goes to n->right->ninit, not init.
- racewalknode(&n->right, &n->right->ninit, wr, 0);
- goto ret;
-
- case ONAME:
- callinstr(&n, init, wr, skip);
- goto ret;
-
- case OCONV:
- racewalknode(&n->left, init, wr, 0);
- goto ret;
-
- case OCONVNOP:
- racewalknode(&n->left, init, wr, 0);
- goto ret;
-
- case ODIV:
- case OMOD:
- racewalknode(&n->left, init, wr, 0);
- racewalknode(&n->right, init, wr, 0);
- goto ret;
-
- case OINDEX:
- if(!isfixedarray(n->left->type))
- racewalknode(&n->left, init, 0, 0);
- else if(!islvalue(n->left)) {
- // index of unaddressable array, like Map[k][i].
- racewalknode(&n->left, init, wr, 0);
- racewalknode(&n->right, init, 0, 0);
- goto ret;
- }
- racewalknode(&n->right, init, 0, 0);
- if(n->left->type->etype != TSTRING)
- callinstr(&n, init, wr, skip);
- goto ret;
-
- case OSLICE:
- case OSLICEARR:
- case OSLICE3:
- case OSLICE3ARR:
- // Seems to only lead to double instrumentation.
- //racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- case OADDR:
- racewalknode(&n->left, init, 0, 1);
- goto ret;
-
- case OEFACE:
- // n->left is Type* which is not interesting.
- racewalknode(&n->right, init, 0, 0);
- goto ret;
-
- case OITAB:
- racewalknode(&n->left, init, 0, 0);
- goto ret;
-
- // should not appear in AST by now
- case OSEND:
- case ORECV:
- case OCLOSE:
- case ONEW:
- case OXCASE:
- case OXFALL:
- case OCASE:
- case OPANIC:
- case ORECOVER:
- case OCONVIFACE:
- case OCMPIFACE:
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case OCALL:
- case OCOPY:
- case OAPPEND:
- case ORUNESTR:
- case OARRAYBYTESTR:
- case OARRAYRUNESTR:
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- case OINDEXMAP: // lowered to call
- case OCMPSTR:
- case OADDSTR:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OAS2DOTTYPE:
- case OCALLPART: // lowered to PTRLIT
- case OCLOSURE: // lowered to PTRLIT
- case ORANGE: // lowered to ordinary for loop
- case OARRAYLIT: // lowered to assignments
- case OMAPLIT:
- case OSTRUCTLIT:
- case OAS2:
- case OAS2RECV:
- case OAS2MAPR:
- case OASOP:
- yyerror("racewalk: %O must be lowered by now", n->op);
- goto ret;
-
- // impossible nodes: only appear in backend.
- case ORROTC:
- case OEXTEND:
- yyerror("racewalk: %O cannot exist now", n->op);
- goto ret;
-
- // just do generic traversal
- case OFOR:
- case OIF:
- case OCALLMETH:
- case ORETURN:
- case ORETJMP:
- case OSWITCH:
- case OSELECT:
- case OEMPTY:
- case OBREAK:
- case OCONTINUE:
- case OFALL:
- case OGOTO:
- case OLABEL:
- goto ret;
-
- // does not require instrumentation
- case OPRINT: // don't bother instrumenting it
- case OPRINTN: // don't bother instrumenting it
- case OCHECKNIL: // always followed by a read.
- case OPARAM: // it appears only in fn->exit to copy heap params back
- case OCLOSUREVAR:// immutable pointer to captured variable
- case ODOTMETH: // either part of CALLMETH or CALLPART (lowered to PTRLIT)
- case OINDREG: // at this stage, only n(SP) nodes from nodarg
- case ODCL: // declarations (without value) cannot be races
- case ODCLCONST:
- case ODCLTYPE:
- case OTYPE:
- case ONONAME:
- case OLITERAL:
- case OSLICESTR: // always preceded by bounds checking, avoid double instrumentation.
- case OTYPESW: // ignored by code generation, do not instrument.
- goto ret;
- }
-
-ret:
- if(n->op != OBLOCK) // OBLOCK is handled above in a special way.
- racewalklist(n->list, init);
- if(n->ntest != N)
- racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
- if(n->nincr != N)
- racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
- racewalklist(n->nbody, nil);
- racewalklist(n->nelse, nil);
- racewalklist(n->rlist, nil);
- *np = n;
-}
-
-static int
-isartificial(Node *n)
-{
- // compiler-emitted artificial things that we do not want to instrument,
- // cant' possibly participate in a data race.
- if(n->op == ONAME && n->sym != S && n->sym->name != nil) {
- if(strcmp(n->sym->name, "_") == 0)
- return 1;
- // autotmp's are always local
- if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0)
- return 1;
- // statictmp's are read-only
- if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0)
- return 1;
- // go.itab is accessed only by the compiler and runtime (assume safe)
- if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0)
- return 1;
- }
- return 0;
-}
-
-static int
-callinstr(Node **np, NodeList **init, int wr, int skip)
-{
- char *name;
- Node *f, *b, *n;
- Type *t;
- int class, hascalls;
-
- n = *np;
- //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
- // n, n->op, n->type ? n->type->etype : -1, n->class);
-
- if(skip || n->type == T || n->type->etype >= TIDEAL)
- return 0;
- t = n->type;
- if(isartificial(n))
- return 0;
-
- b = outervalue(n);
- // it skips e.g. stores to ... parameter array
- if(isartificial(b))
- return 0;
- class = b->class;
- // BUG: we _may_ want to instrument PAUTO sometimes
- // e.g. if we've got a local variable/method receiver
- // that has got a pointer inside. Whether it points to
- // the heap or not is impossible to know at compile time
- if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
- || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND) {
- hascalls = 0;
- foreach(n, hascallspred, &hascalls);
- if(hascalls) {
- n = detachexpr(n, init);
- *np = n;
- }
- n = treecopy(n);
- makeaddable(n);
- if(t->etype == TSTRUCT || isfixedarray(t)) {
- name = "racereadrange";
- if(wr)
- name = "racewriterange";
- f = mkcall(name, T, init, uintptraddr(n), nodintconst(t->width));
- } else {
- name = "raceread";
- if(wr)
- name = "racewrite";
- f = mkcall(name, T, init, uintptraddr(n));
- }
- *init = list(*init, f);
- return 1;
- }
- return 0;
-}
-
-// makeaddable returns a node whose memory location is the
-// same as n, but which is addressable in the Go language
-// sense.
-// This is different from functions like cheapexpr that may make
-// a copy of their argument.
-static void
-makeaddable(Node *n)
-{
- // The arguments to uintptraddr technically have an address but
- // may not be addressable in the Go sense: for example, in the case
- // of T(v).Field where T is a struct type and v is
- // an addressable value.
- switch(n->op) {
- case OINDEX:
- if(isfixedarray(n->left->type))
- makeaddable(n->left);
- break;
- case ODOT:
- case OXDOT:
- // Turn T(v).Field into v.Field
- if(n->left->op == OCONVNOP)
- n->left = n->left->left;
- makeaddable(n->left);
- break;
- case ODOTPTR:
- default:
- // nothing to do
- break;
- }
-}
-
-static Node*
-uintptraddr(Node *n)
-{
- Node *r;
-
- r = nod(OADDR, n, N);
- r->bounded = 1;
- r = conv(r, types[TUNSAFEPTR]);
- r = conv(r, types[TUINTPTR]);
- return r;
-}
-
-static Node*
-detachexpr(Node *n, NodeList **init)
-{
- Node *addr, *as, *ind, *l;
-
- addr = nod(OADDR, n, N);
- l = temp(ptrto(n->type));
- as = nod(OAS, l, addr);
- typecheck(&as, Etop);
- walkexpr(&as, init);
- *init = list(*init, as);
- ind = nod(OIND, l, N);
- typecheck(&ind, Erv);
- walkexpr(&ind, init);
- return ind;
-}
-
-static void
-foreachnode(Node *n, void(*f)(Node*, void*), void *c)
-{
- if(n)
- f(n, c);
-}
-
-static void
-foreachlist(NodeList *l, void(*f)(Node*, void*), void *c)
-{
- for(; l; l = l->next)
- foreachnode(l->n, f, c);
-}
-
-static void
-foreach(Node *n, void(*f)(Node*, void*), void *c)
-{
- foreachlist(n->ninit, f, c);
- foreachnode(n->left, f, c);
- foreachnode(n->right, f, c);
- foreachlist(n->list, f, c);
- foreachnode(n->ntest, f, c);
- foreachnode(n->nincr, f, c);
- foreachlist(n->nbody, f, c);
- foreachlist(n->nelse, f, c);
- foreachlist(n->rlist, f, c);
-}
-
-static void
-hascallspred(Node *n, void *c)
-{
- switch(n->op) {
- case OCALL:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- (*(int*)c)++;
- }
-}
-
-// appendinit is like addinit in subr.c
-// but appends rather than prepends.
-static void
-appendinit(Node **np, NodeList *init)
-{
- Node *n;
-
- if(init == nil)
- return;
-
- n = *np;
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- // There may be multiple refs to this node;
- // introduce OCONVNOP to hold init list.
- n = nod(OCONVNOP, n, N);
- n->type = n->left->type;
- n->typecheck = 1;
- *np = n;
- break;
- }
- n->ninit = concat(n->ninit, init);
- n->ullman = UINF;
-}
-
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
deleted file mode 100644
index ff9de6c349..0000000000
--- a/src/cmd/gc/range.c
+++ /dev/null
@@ -1,378 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * range
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-void
-typecheckrange(Node *n)
-{
- int toomany;
- char *why;
- Type *t, *t1, *t2;
- Node *v1, *v2;
- NodeList *ll;
-
- // Typechecking order is important here:
- // 0. first typecheck range expression (slice/map/chan),
- // it is evaluated only once and so logically it is not part of the loop.
- // 1. typcheck produced values,
- // this part can declare new vars and so it must be typechecked before body,
- // because body can contain a closure that captures the vars.
- // 2. decldepth++ to denote loop body.
- // 3. typecheck body.
- // 4. decldepth--.
-
- typecheck(&n->right, Erv);
- if((t = n->right->type) == T)
- goto out;
-
- // delicate little dance. see typecheckas2
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->defn != n)
- typecheck(&ll->n, Erv | Easgn);
-
- if(isptr[t->etype] && isfixedarray(t->type))
- t = t->type;
- n->type = t;
-
- toomany = 0;
- switch(t->etype) {
- default:
- yyerror("cannot range over %lN", n->right);
- goto out;
-
- case TARRAY:
- t1 = types[TINT];
- t2 = t->type;
- break;
-
- case TMAP:
- t1 = t->down;
- t2 = t->type;
- break;
-
- case TCHAN:
- if(!(t->chan & Crecv)) {
- yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type);
- goto out;
- }
- t1 = t->type;
- t2 = nil;
- if(count(n->list) == 2)
- toomany = 1;
- break;
-
- case TSTRING:
- t1 = types[TINT];
- t2 = runetype;
- break;
- }
-
- if(count(n->list) > 2 || toomany)
- yyerror("too many variables in range");
-
- v1 = N;
- if(n->list)
- v1 = n->list->n;
- v2 = N;
- if(n->list && n->list->next)
- v2 = n->list->next->n;
-
- // this is not only a optimization but also a requirement in the spec.
- // "if the second iteration variable is the blank identifier, the range
- // clause is equivalent to the same clause with only the first variable
- // present."
- if(isblank(v2)) {
- if(v1 != N)
- n->list = list1(v1);
- v2 = N;
- }
-
- if(v1) {
- if(v1->defn == n)
- v1->type = t1;
- else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
- yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
- checkassign(n, v1);
- }
- if(v2) {
- if(v2->defn == n)
- v2->type = t2;
- else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
- yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
- checkassign(n, v2);
- }
-
-out:
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-
- decldepth++;
- typechecklist(n->nbody, Etop);
- decldepth--;
-}
-
-void
-walkrange(Node *n)
-{
- Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
- Node *ha, *hit; // hidden aggregate, iterator
- Node *hn, *hp; // hidden len, pointer
- Node *hb; // hidden bool
- Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
- Node *fn, *tmp;
- Node *keyname, *valname;
- Node *key, *val;
- NodeList *body, *init;
- Type *th, *t;
- int lno;
-
- t = n->type;
- init = nil;
-
- a = n->right;
- lno = setlineno(a);
-
- v1 = N;
- if(n->list)
- v1 = n->list->n;
- v2 = N;
- if(n->list && n->list->next && !isblank(n->list->next->n))
- v2 = n->list->next->n;
- // n->list has no meaning anymore, clear it
- // to avoid erroneous processing by racewalk.
- n->list = nil;
- hv2 = N;
-
- switch(t->etype) {
- default:
- fatal("walkrange");
-
- case TARRAY:
- // Lower n into runtime·memclr if possible, for
- // fast zeroing of slices and arrays (issue 5373).
- // Look for instances of
- //
- // for i := range a {
- // a[i] = zero
- // }
- //
- // in which the evaluation of a is side-effect-free.
- if(!debug['N'])
- if(!flag_race)
- if(v1 != N)
- if(v2 == N)
- if(n->nbody != nil)
- if(n->nbody->n != N) // at least one statement in body
- if(n->nbody->next == nil) { // at most one statement in body
- tmp = n->nbody->n; // first statement of body
- if(tmp->op == OAS)
- if(tmp->left->op == OINDEX)
- if(samesafeexpr(tmp->left->left, a))
- if(samesafeexpr(tmp->left->right, v1))
- if(t->type->width > 0)
- if(iszero(tmp->right)) {
- // Convert to
- // if len(a) != 0 {
- // hp = &a[0]
- // hn = len(a)*sizeof(elem(a))
- // memclr(hp, hn)
- // i = len(a) - 1
- // }
- n->op = OIF;
- n->nbody = nil;
- n->ntest = nod(ONE, nod(OLEN, a, N), nodintconst(0));
- n->nincr = nil;
-
- // hp = &a[0]
- hp = temp(ptrto(types[TUINT8]));
- tmp = nod(OINDEX, a, nodintconst(0));
- tmp->bounded = 1;
- tmp = nod(OADDR, tmp, N);
- tmp = nod(OCONVNOP, tmp, N);
- tmp->type = ptrto(types[TUINT8]);
- n->nbody = list(n->nbody, nod(OAS, hp, tmp));
-
- // hn = len(a) * sizeof(elem(a))
- hn = temp(types[TUINTPTR]);
- tmp = nod(OLEN, a, N);
- tmp = nod(OMUL, tmp, nodintconst(t->type->width));
- tmp = conv(tmp, types[TUINTPTR]);
- n->nbody = list(n->nbody, nod(OAS, hn, tmp));
-
- // memclr(hp, hn)
- fn = mkcall("memclr", T, nil, hp, hn);
- n->nbody = list(n->nbody, fn);
-
- // i = len(a) - 1
- v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, N), nodintconst(1)));
- n->nbody = list(n->nbody, v1);
-
- typecheck(&n->ntest, Erv);
- typechecklist(n->nbody, Etop);
- walkstmt(&n);
- lineno = lno;
- return;
- }
- }
-
- // orderstmt arranged for a copy of the array/slice variable if needed.
- ha = a;
- hv1 = temp(types[TINT]);
- hn = temp(types[TINT]);
- hp = nil;
-
- init = list(init, nod(OAS, hv1, N));
- init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
- if(v2) {
- hp = temp(ptrto(n->type->type));
- tmp = nod(OINDEX, ha, nodintconst(0));
- tmp->bounded = 1;
- init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
- }
-
- n->ntest = nod(OLT, hv1, hn);
- n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
- if(v1 == N)
- body = nil;
- else if(v2 == N)
- body = list1(nod(OAS, v1, hv1));
- else {
- a = nod(OAS2, N, N);
- a->list = list(list1(v1), v2);
- a->rlist = list(list1(hv1), nod(OIND, hp, N));
- body = list1(a);
-
- // Advance pointer as part of increment.
- // We used to advance the pointer before executing the loop body,
- // but doing so would make the pointer point past the end of the
- // array during the final iteration, possibly causing another unrelated
- // piece of memory not to be garbage collected until the loop finished.
- // Advancing during the increment ensures that the pointer p only points
- // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
- // after which p is dead, so it cannot confuse the collector.
- tmp = nod(OADD, hp, nodintconst(t->type->width));
- tmp->type = hp->type;
- tmp->typecheck = 1;
- tmp->right->type = types[tptr];
- tmp->right->typecheck = 1;
- a = nod(OAS, hp, tmp);
- typecheck(&a, Etop);
- n->nincr->ninit = list1(a);
- }
- break;
-
- case TMAP:
- // orderstmt allocated the iterator for us.
- // we only use a once, so no copy needed.
- ha = a;
- th = hiter(t);
- hit = n->alloc;
- hit->type = th;
- n->left = N;
- keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter
- valname = newname(th->type->down->sym); // ditto
-
- fn = syslook("mapiterinit", 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, th);
- init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
- n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil());
-
- fn = syslook("mapiternext", 1);
- argtype(fn, th);
- n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
-
- key = nod(ODOT, hit, keyname);
- key = nod(OIND, key, N);
- if(v1 == N)
- body = nil;
- else if(v2 == N) {
- body = list1(nod(OAS, v1, key));
- } else {
- val = nod(ODOT, hit, valname);
- val = nod(OIND, val, N);
- a = nod(OAS2, N, N);
- a->list = list(list1(v1), v2);
- a->rlist = list(list1(key), val);
- body = list1(a);
- }
- break;
-
- case TCHAN:
- // orderstmt arranged for a copy of the channel variable.
- ha = a;
- n->ntest = N;
-
- hv1 = temp(t->type);
- hv1->typecheck = 1;
- if(haspointers(t->type))
- init = list(init, nod(OAS, hv1, N));
- hb = temp(types[TBOOL]);
-
- n->ntest = nod(ONE, hb, nodbool(0));
- a = nod(OAS2RECV, N, N);
- a->typecheck = 1;
- a->list = list(list1(hv1), hb);
- a->rlist = list1(nod(ORECV, ha, N));
- n->ntest->ninit = list1(a);
- if(v1 == N)
- body = nil;
- else
- body = list1(nod(OAS, v1, hv1));
- break;
-
- case TSTRING:
- // orderstmt arranged for a copy of the string variable.
- ha = a;
-
- ohv1 = temp(types[TINT]);
-
- hv1 = temp(types[TINT]);
- init = list(init, nod(OAS, hv1, N));
-
- if(v2 == N)
- a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
- else {
- hv2 = temp(runetype);
- a = nod(OAS2, N, N);
- a->list = list(list1(hv1), hv2);
- fn = syslook("stringiter2", 0);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
- }
- n->ntest = nod(ONE, hv1, nodintconst(0));
- n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
-
-
- body = nil;
- if(v1 != N)
- body = list1(nod(OAS, v1, ohv1));
- if(v2 != N)
- body = list(body, nod(OAS, v2, hv2));
- break;
- }
-
- n->op = OFOR;
- typechecklist(init, Etop);
- n->ninit = concat(n->ninit, init);
- typechecklist(n->ntest->ninit, Etop);
- typecheck(&n->ntest, Erv);
- typecheck(&n->nincr, Etop);
- typechecklist(body, Etop);
- n->nbody = concat(body, n->nbody);
- walkstmt(&n);
-
- lineno = lno;
-}
-
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
deleted file mode 100644
index 9390ab9a86..0000000000
--- a/src/cmd/gc/reflect.c
+++ /dev/null
@@ -1,1609 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-#include "../../runtime/mgc0.h"
-#include "../../runtime/typekind.h"
-
-/*
- * runtime interface and reflection data structures
- */
-
-static NodeList* signatlist;
-static Sym* dtypesym(Type*);
-static Sym* weaktypesym(Type*);
-static Sym* dalgsym(Type*);
-static int usegcprog(Type*);
-static void gengcprog(Type*, Sym**, Sym**);
-static void gengcmask(Type*, uint8[16]);
-
-static int
-sigcmp(Sig *a, Sig *b)
-{
- int i;
-
- i = strcmp(a->name, b->name);
- if(i != 0)
- return i;
- if(a->pkg == b->pkg)
- return 0;
- if(a->pkg == nil)
- return -1;
- if(b->pkg == nil)
- return +1;
- return strcmp(a->pkg->path->s, b->pkg->path->s);
-}
-
-static Sig*
-lsort(Sig *l, int(*f)(Sig*, Sig*))
-{
- Sig *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = lsort(l, f);
- l2 = lsort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-// Builds a type respresenting a Bucket structure for
-// the given map type. This type is not visible to users -
-// we include only enough information to generate a correct GC
-// program for it.
-// Make sure this stays in sync with ../../runtime/hashmap.c!
-enum {
- BUCKETSIZE = 8,
- MAXKEYSIZE = 128,
- MAXVALSIZE = 128,
-};
-
-static Type*
-makefield(char *name, Type *t)
-{
- Type *f;
-
- f = typ(TFIELD);
- f->type = t;
- f->sym = mal(sizeof(Sym));
- f->sym->name = name;
- return f;
-}
-
-Type*
-mapbucket(Type *t)
-{
- Type *keytype, *valtype;
- Type *bucket, *arr;
- Type *field[4];
- int32 n;
-
- if(t->bucket != T)
- return t->bucket;
-
- bucket = typ(TSTRUCT);
- keytype = t->down;
- valtype = t->type;
- dowidth(keytype);
- dowidth(valtype);
- if(keytype->width > MAXKEYSIZE)
- keytype = ptrto(keytype);
- if(valtype->width > MAXVALSIZE)
- valtype = ptrto(valtype);
-
- // The first field is: uint8 topbits[BUCKETSIZE].
- arr = typ(TARRAY);
- arr->type = types[TUINT8];
- arr->bound = BUCKETSIZE;
- field[0] = makefield("topbits", arr);
- arr = typ(TARRAY);
- arr->type = keytype;
- arr->bound = BUCKETSIZE;
- field[1] = makefield("keys", arr);
- arr = typ(TARRAY);
- arr->type = valtype;
- arr->bound = BUCKETSIZE;
- field[2] = makefield("values", arr);
- field[3] = makefield("overflow", ptrto(bucket));
-
- // link up fields
- bucket->noalg = 1;
- bucket->local = t->local;
- bucket->type = field[0];
- for(n = 0; n < nelem(field)-1; n++)
- field[n]->down = field[n+1];
- field[nelem(field)-1]->down = T;
- dowidth(bucket);
-
- // Pad to the native integer alignment.
- // This is usually the same as widthptr; the exception (as usual) is amd64p32.
- if(widthreg > widthptr)
- bucket->width += widthreg - widthptr;
-
- // See comment on hmap.overflow in ../../runtime/hashmap.go.
- if(!haspointers(t->type) && !haspointers(t->down) &&
- t->type->width <= MAXKEYSIZE && t->down->width <= MAXVALSIZE)
- bucket->haspointers = 1; // no pointers
-
- t->bucket = bucket;
- bucket->map = t;
- return bucket;
-}
-
-// Builds a type representing a Hmap structure for the given map type.
-// Make sure this stays in sync with ../../runtime/hashmap.go!
-Type*
-hmap(Type *t)
-{
- Type *h, *bucket;
- Type *field[8];
- int32 n;
-
- if(t->hmap != T)
- return t->hmap;
-
- bucket = mapbucket(t);
- field[0] = makefield("count", types[TINT]);
- field[1] = makefield("flags", types[TUINT8]);
- field[2] = makefield("B", types[TUINT8]);
- field[3] = makefield("hash0", types[TUINT32]);
- field[4] = makefield("buckets", ptrto(bucket));
- field[5] = makefield("oldbuckets", ptrto(bucket));
- field[6] = makefield("nevacuate", types[TUINTPTR]);
- field[7] = makefield("overflow", types[TUNSAFEPTR]);
-
- h = typ(TSTRUCT);
- h->noalg = 1;
- h->local = t->local;
- h->type = field[0];
- for(n = 0; n < nelem(field)-1; n++)
- field[n]->down = field[n+1];
- field[nelem(field)-1]->down = T;
- dowidth(h);
- t->hmap = h;
- h->map = t;
- return h;
-}
-
-Type*
-hiter(Type *t)
-{
- int32 n;
- Type *field[12];
- Type *i;
-
- if(t->hiter != T)
- return t->hiter;
-
- // build a struct:
- // hash_iter {
- // key *Key
- // val *Value
- // t *MapType
- // h *Hmap
- // buckets *Bucket
- // bptr *Bucket
- // overflow0 unsafe.Pointer
- // overflow1 unsafe.Pointer
- // startBucket uintptr
- // stuff uintptr
- // bucket uintptr
- // checkBucket uintptr
- // }
- // must match ../../runtime/hashmap.c:hash_iter.
- field[0] = makefield("key", ptrto(t->down));
- field[1] = makefield("val", ptrto(t->type));
- field[2] = makefield("t", ptrto(types[TUINT8]));
- field[3] = makefield("h", ptrto(hmap(t)));
- field[4] = makefield("buckets", ptrto(mapbucket(t)));
- field[5] = makefield("bptr", ptrto(mapbucket(t)));
- field[6] = makefield("overflow0", types[TUNSAFEPTR]);
- field[7] = makefield("overflow1", types[TUNSAFEPTR]);
- field[8] = makefield("startBucket", types[TUINTPTR]);
- field[9] = makefield("stuff", types[TUINTPTR]); // offset+wrapped+B+I
- field[10] = makefield("bucket", types[TUINTPTR]);
- field[11] = makefield("checkBucket", types[TUINTPTR]);
-
- // build iterator struct holding the above fields
- i = typ(TSTRUCT);
- i->noalg = 1;
- i->type = field[0];
- for(n = 0; n < nelem(field)-1; n++)
- field[n]->down = field[n+1];
- field[nelem(field)-1]->down = T;
- dowidth(i);
- if(i->width != 12 * widthptr)
- yyerror("hash_iter size not correct %d %d", i->width, 12 * widthptr);
- t->hiter = i;
- i->map = t;
- return i;
-}
-
-/*
- * f is method type, with receiver.
- * return function type, receiver as first argument (or not).
- */
-Type*
-methodfunc(Type *f, Type *receiver)
-{
- NodeList *in, *out;
- Node *d;
- Type *t;
-
- in = nil;
- if(receiver) {
- d = nod(ODCLFIELD, N, N);
- d->type = receiver;
- in = list(in, d);
- }
- for(t=getinargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- d->isddd = t->isddd;
- in = list(in, d);
- }
-
- out = nil;
- for(t=getoutargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- out = list(out, d);
- }
-
- t = functype(N, in, out);
- if(f->nname) {
- // Link to name of original method function.
- t->nname = f->nname;
- }
- return t;
-}
-
-/*
- * return methods of non-interface type t, sorted by name.
- * generates stub functions as needed.
- */
-static Sig*
-methods(Type *t)
-{
- Type *f, *mt, *it, *this;
- Sig *a, *b;
- Sym *method;
-
- // method type
- mt = methtype(t, 0);
- if(mt == T)
- return nil;
- expandmeth(mt);
-
- // type stored in interface word
- it = t;
- if(!isdirectiface(it))
- it = ptrto(t);
-
- // make list of methods for t,
- // generating code if necessary.
- a = nil;
- for(f=mt->xmethod; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("methods: not field %T", f);
- if (f->type->etype != TFUNC || f->type->thistuple == 0)
- fatal("non-method on %T method %S %T\n", mt, f->sym, f);
- if (!getthisx(f->type)->type)
- fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
- if(f->nointerface)
- continue;
-
- method = f->sym;
- if(method == nil)
- continue;
-
- // get receiver type for this particular method.
- // if pointer receiver but non-pointer t and
- // this is not an embedded pointer inside a struct,
- // method does not apply.
- this = getthisx(f->type)->type->type;
- if(isptr[this->etype] && this->type == t)
- continue;
- if(isptr[this->etype] && !isptr[t->etype]
- && f->embedded != 2 && !isifacemethod(f->type))
- continue;
-
- b = mal(sizeof(*b));
- b->link = a;
- a = b;
-
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("methods: missing package");
- a->pkg = method->pkg;
- }
- a->isym = methodsym(method, it, 1);
- a->tsym = methodsym(method, t, 0);
- a->type = methodfunc(f->type, t);
- a->mtype = methodfunc(f->type, nil);
-
- if(!(a->isym->flags & SymSiggen)) {
- a->isym->flags |= SymSiggen;
- if(!eqtype(this, it) || this->width < types[tptr]->width) {
- compiling_wrappers = 1;
- genwrapper(it, f, a->isym, 1);
- compiling_wrappers = 0;
- }
- }
-
- if(!(a->tsym->flags & SymSiggen)) {
- a->tsym->flags |= SymSiggen;
- if(!eqtype(this, t)) {
- compiling_wrappers = 1;
- genwrapper(t, f, a->tsym, 0);
- compiling_wrappers = 0;
- }
- }
- }
-
- return lsort(a, sigcmp);
-}
-
-/*
- * return methods of interface type t, sorted by name.
- */
-static Sig*
-imethods(Type *t)
-{
- Sig *a, *all, *last;
- Type *f;
- Sym *method, *isym;
-
- all = nil;
- last = nil;
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("imethods: not field");
- if(f->type->etype != TFUNC || f->sym == nil)
- continue;
- method = f->sym;
- a = mal(sizeof(*a));
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("imethods: missing package");
- a->pkg = method->pkg;
- }
- a->mtype = f->type;
- a->offset = 0;
- a->type = methodfunc(f->type, nil);
-
- if(last && sigcmp(last, a) >= 0)
- fatal("sigcmp vs sortinter %s %s", last->name, a->name);
- if(last == nil)
- all = a;
- else
- last->link = a;
- last = a;
-
- // Compiler can only refer to wrappers for non-blank methods.
- if(isblanksym(method))
- continue;
-
- // NOTE(rsc): Perhaps an oversight that
- // IfaceType.Method is not in the reflect data.
- // Generate the method body, so that compiled
- // code can refer to it.
- isym = methodsym(method, t, 0);
- if(!(isym->flags & SymSiggen)) {
- isym->flags |= SymSiggen;
- genwrapper(t, f, isym, 0);
- }
- }
- return all;
-}
-
-static void
-dimportpath(Pkg *p)
-{
- static Pkg *gopkg;
- char *nam;
- Node *n;
-
- if(p->pathsym != S)
- return;
-
- if(gopkg == nil) {
- gopkg = mkpkg(newstrlit("go"));
- gopkg->name = "go";
- }
- nam = smprint("importpath.%s.", p->prefix);
-
- n = nod(ONAME, N, N);
- n->sym = pkglookup(nam, gopkg);
- free(nam);
- n->class = PEXTERN;
- n->xoffset = 0;
- p->pathsym = n->sym;
-
- gdatastring(n, p->path);
- ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
-}
-
-static int
-dgopkgpath(Sym *s, int ot, Pkg *pkg)
-{
- if(pkg == nil)
- return dgostringptr(s, ot, nil);
-
- // Emit reference to go.importpath.""., which 6l will
- // rewrite using the correct import path. Every package
- // that imports this one directly defines the symbol.
- if(pkg == localpkg) {
- static Sym *ns;
-
- if(ns == nil)
- ns = pkglookup("importpath.\"\".", mkpkg(newstrlit("go")));
- return dsymptr(s, ot, ns, 0);
- }
-
- dimportpath(pkg);
- return dsymptr(s, ot, pkg->pathsym, 0);
-}
-
-/*
- * uncommonType
- * ../../runtime/type.go:/uncommonType
- */
-static int
-dextratype(Sym *sym, int off, Type *t, int ptroff)
-{
- int ot, n;
- Sym *s;
- Sig *a, *m;
-
- m = methods(t);
- if(t->sym == nil && m == nil)
- return off;
-
- // fill in *extraType pointer in header
- off = rnd(off, widthptr);
- dsymptr(sym, ptroff, sym, off);
-
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- ot = off;
- s = sym;
- if(t->sym) {
- ot = dgostringptr(s, ot, t->sym->name);
- if(t != types[t->etype] && t != errortype)
- ot = dgopkgpath(s, ot, t->sym->pkg);
- else
- ot = dgostringptr(s, ot, nil);
- } else {
- ot = dgostringptr(s, ot, nil);
- ot = dgostringptr(s, ot, nil);
- }
-
- // slice header
- ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
- ot = duintxx(s, ot, n, widthint);
- ot = duintxx(s, ot, n, widthint);
-
- // methods
- for(a=m; a; a=a->link) {
- // method
- // ../../runtime/type.go:/method
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- if(a->isym)
- ot = dsymptr(s, ot, a->isym, 0);
- else
- ot = duintptr(s, ot, 0);
- if(a->tsym)
- ot = dsymptr(s, ot, a->tsym, 0);
- else
- ot = duintptr(s, ot, 0);
- }
-
- return ot;
-}
-
-static int
-kinds[] =
-{
- [TINT] = KindInt,
- [TUINT] = KindUint,
- [TINT8] = KindInt8,
- [TUINT8] = KindUint8,
- [TINT16] = KindInt16,
- [TUINT16] = KindUint16,
- [TINT32] = KindInt32,
- [TUINT32] = KindUint32,
- [TINT64] = KindInt64,
- [TUINT64] = KindUint64,
- [TUINTPTR] = KindUintptr,
- [TFLOAT32] = KindFloat32,
- [TFLOAT64] = KindFloat64,
- [TBOOL] = KindBool,
- [TSTRING] = KindString,
- [TPTR32] = KindPtr,
- [TPTR64] = KindPtr,
- [TSTRUCT] = KindStruct,
- [TINTER] = KindInterface,
- [TCHAN] = KindChan,
- [TMAP] = KindMap,
- [TARRAY] = KindArray,
- [TFUNC] = KindFunc,
- [TCOMPLEX64] = KindComplex64,
- [TCOMPLEX128] = KindComplex128,
- [TUNSAFEPTR] = KindUnsafePointer,
-};
-
-int
-haspointers(Type *t)
-{
- Type *t1;
- int ret;
-
- if(t->haspointers != 0)
- return t->haspointers - 1;
-
- switch(t->etype) {
- case TINT:
- case TUINT:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TUINTPTR:
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- case TBOOL:
- ret = 0;
- break;
- case TARRAY:
- if(t->bound < 0) { // slice
- ret = 1;
- break;
- }
- if(t->bound == 0) { // empty array
- ret = 0;
- break;
- }
- ret = haspointers(t->type);
- break;
- case TSTRUCT:
- ret = 0;
- for(t1=t->type; t1!=T; t1=t1->down) {
- if(haspointers(t1->type)) {
- ret = 1;
- break;
- }
- }
- break;
- case TSTRING:
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TINTER:
- case TCHAN:
- case TMAP:
- case TFUNC:
- default:
- ret = 1;
- break;
- }
-
- t->haspointers = 1+ret;
- return ret;
-}
-
-/*
- * commonType
- * ../../runtime/type.go:/commonType
- */
-static int
-dcommontype(Sym *s, int ot, Type *t)
-{
- int i, alg, sizeofAlg, gcprog;
- Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
- uint8 gcmask[16];
- static Sym *algarray;
- uint64 x1, x2;
- char *p;
-
- if(ot != 0)
- fatal("dcommontype %d", ot);
-
- sizeofAlg = 2*widthptr;
- if(algarray == nil)
- algarray = pkglookup("algarray", runtimepkg);
- dowidth(t);
- alg = algtype(t);
- algsym = S;
- if(alg < 0 || alg == AMEM)
- algsym = dalgsym(t);
-
- if(t->sym != nil && !isptr[t->etype])
- sptr = dtypesym(ptrto(t));
- else
- sptr = weaktypesym(ptrto(t));
-
- // All (non-reflect-allocated) Types share the same zero object.
- // Each place in the compiler where a pointer to the zero object
- // might be returned by a runtime call (map access return value,
- // 2-arg type cast) declares the size of the zerovalue it needs.
- // The linker magically takes the max of all the sizes.
- zero = pkglookup("zerovalue", runtimepkg);
-
- // We use size 0 here so we get the pointer to the zero value,
- // but don't allocate space for the zero value unless we need it.
- // TODO: how do we get this symbol into bss? We really want
- // a read-only bss, but I don't think such a thing exists.
-
- // ../../pkg/reflect/type.go:/^type.commonType
- // actual type structure
- // type commonType struct {
- // size uintptr
- // hash uint32
- // _ uint8
- // align uint8
- // fieldAlign uint8
- // kind uint8
- // alg unsafe.Pointer
- // gc unsafe.Pointer
- // string *string
- // *extraType
- // ptrToThis *Type
- // zero unsafe.Pointer
- // }
- ot = duintptr(s, ot, t->width);
- ot = duint32(s, ot, typehash(t));
- ot = duint8(s, ot, 0); // unused
-
- // runtime (and common sense) expects alignment to be a power of two.
- i = t->align;
- if(i == 0)
- i = 1;
- if((i&(i-1)) != 0)
- fatal("invalid alignment %d for %T", t->align, t);
- ot = duint8(s, ot, t->align); // align
- ot = duint8(s, ot, t->align); // fieldAlign
-
- gcprog = usegcprog(t);
- i = kinds[t->etype];
- if(t->etype == TARRAY && t->bound < 0)
- i = KindSlice;
- if(!haspointers(t))
- i |= KindNoPointers;
- if(isdirectiface(t))
- i |= KindDirectIface;
- if(gcprog)
- i |= KindGCProg;
- ot = duint8(s, ot, i); // kind
- if(algsym == S)
- ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
- else
- ot = dsymptr(s, ot, algsym, 0);
- // gc
- if(gcprog) {
- gengcprog(t, &gcprog0, &gcprog1);
- if(gcprog0 != S)
- ot = dsymptr(s, ot, gcprog0, 0);
- else
- ot = duintptr(s, ot, 0);
- ot = dsymptr(s, ot, gcprog1, 0);
- } else {
- gengcmask(t, gcmask);
- x1 = 0;
- for(i=0; i<8; i++)
- x1 = x1<<8 | gcmask[i];
- if(widthptr == 4) {
- p = smprint("gcbits.0x%016llux", x1);
- } else {
- x2 = 0;
- for(i=0; i<8; i++)
- x2 = x2<<8 | gcmask[i+8];
- p = smprint("gcbits.0x%016llux%016llux", x1, x2);
- }
- sbits = pkglookup(p, runtimepkg);
- if((sbits->flags & SymUniq) == 0) {
- sbits->flags |= SymUniq;
- for(i = 0; i < 2*widthptr; i++)
- duint8(sbits, i, gcmask[i]);
- ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
- }
- ot = dsymptr(s, ot, sbits, 0);
- ot = duintptr(s, ot, 0);
- }
- p = smprint("%-uT", t);
- //print("dcommontype: %s\n", p);
- ot = dgostringptr(s, ot, p); // string
- free(p);
-
- // skip pointer to extraType,
- // which follows the rest of this type structure.
- // caller will fill in if needed.
- // otherwise linker will assume 0.
- ot += widthptr;
-
- ot = dsymptr(s, ot, sptr, 0); // ptrto type
- ot = dsymptr(s, ot, zero, 0); // ptr to zero value
- return ot;
-}
-
-Sym*
-typesym(Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%-T", t);
- s = pkglookup(p, typepkg);
- //print("typesym: %s -> %+S\n", p, s);
- free(p);
- return s;
-}
-
-Sym*
-tracksym(Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%-T.%s", t->outer, t->sym->name);
- s = pkglookup(p, trackpkg);
- free(p);
- return s;
-}
-
-Sym*
-typelinksym(Type *t)
-{
- char *p;
- Sym *s;
-
- // %-uT is what the generated Type's string field says.
- // It uses (ambiguous) package names instead of import paths.
- // %-T is the complete, unambiguous type name.
- // We want the types to end up sorted by string field,
- // so use that first in the name, and then add :%-T to
- // disambiguate. The names are a little long but they are
- // discarded by the linker and do not end up in the symbol
- // table of the final binary.
- p = smprint("%-uT/%-T", t, t);
- s = pkglookup(p, typelinkpkg);
- //print("typelinksym: %s -> %+S\n", p, s);
- free(p);
- return s;
-}
-
-Sym*
-typesymprefix(char *prefix, Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%s.%-T", prefix, t);
- s = pkglookup(p, typepkg);
- //print("algsym: %s -> %+S\n", p, s);
- free(p);
- return s;
-}
-
-Sym*
-typenamesym(Type *t)
-{
- Sym *s;
- Node *n;
-
- if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
- fatal("typename %T", t);
- s = typesym(t);
- if(s->def == N) {
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = types[TUINT8];
- n->addable = 1;
- n->ullman = 1;
- n->class = PEXTERN;
- n->xoffset = 0;
- n->typecheck = 1;
- s->def = n;
-
- signatlist = list(signatlist, typenod(t));
- }
- return s->def->sym;
-}
-
-Node*
-typename(Type *t)
-{
- Sym *s;
- Node *n;
-
- s = typenamesym(t);
- n = nod(OADDR, s->def, N);
- n->type = ptrto(s->def->type);
- n->addable = 1;
- n->ullman = 2;
- n->typecheck = 1;
- return n;
-}
-
-static Sym*
-weaktypesym(Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%-T", t);
- s = pkglookup(p, weaktypepkg);
- //print("weaktypesym: %s -> %+S\n", p, s);
- free(p);
- return s;
-}
-
-/*
- * Returns 1 if t has a reflexive equality operator.
- * That is, if x==x for all x of type t.
- */
-static int
-isreflexive(Type *t)
-{
- Type *t1;
- switch(t->etype) {
- case TBOOL:
- case TINT:
- case TUINT:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TUINTPTR:
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TSTRING:
- case TCHAN:
- return 1;
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- case TINTER:
- return 0;
- case TARRAY:
- if(isslice(t))
- fatal("slice can't be a map key: %T", t);
- return isreflexive(t->type);
- case TSTRUCT:
- for(t1=t->type; t1!=T; t1=t1->down) {
- if(!isreflexive(t1->type))
- return 0;
- }
- return 1;
- default:
- fatal("bad type for map key: %T", t);
- return 0;
- }
-}
-
-static Sym*
-dtypesym(Type *t)
-{
- int ot, xt, n, isddd, dupok;
- Sym *s, *s1, *s2, *s3, *s4, *slink;
- Sig *a, *m;
- Type *t1, *tbase, *t2;
-
- // Replace byte, rune aliases with real type.
- // They've been separate internally to make error messages
- // better, but we have to merge them in the reflect tables.
- if(t == bytetype || t == runetype)
- t = types[t->etype];
-
- if(isideal(t))
- fatal("dtypesym %T", t);
-
- s = typesym(t);
- if(s->flags & SymSiggen)
- return s;
- s->flags |= SymSiggen;
-
- // special case (look for runtime below):
- // when compiling package runtime,
- // emit the type structures for int, float, etc.
- tbase = t;
- if(isptr[t->etype] && t->sym == S && t->type->sym != S)
- tbase = t->type;
- dupok = 0;
- if(tbase->sym == S)
- dupok = DUPOK;
-
- if(compiling_runtime &&
- (tbase == types[tbase->etype] ||
- tbase == bytetype ||
- tbase == runetype ||
- tbase == errortype)) { // int, float, etc
- goto ok;
- }
-
- // named types from other files are defined only by those files
- if(tbase->sym && !tbase->local)
- return s;
- if(isforw[tbase->etype])
- return s;
-
-ok:
- ot = 0;
- xt = 0;
- switch(t->etype) {
- default:
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- break;
-
- case TARRAY:
- if(t->bound >= 0) {
- // ../../runtime/type.go:/ArrayType
- s1 = dtypesym(t->type);
- t2 = typ(TARRAY);
- t2->type = t->type;
- t2->bound = -1; // slice
- s2 = dtypesym(t2);
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- ot = duintptr(s, ot, t->bound);
- } else {
- // ../../runtime/type.go:/SliceType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- }
- break;
-
- case TCHAN:
- // ../../runtime/type.go:/ChanType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = duintptr(s, ot, t->chan);
- break;
-
- case TFUNC:
- for(t1=getthisx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
- isddd = 0;
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- isddd = t1->isddd;
- dtypesym(t1->type);
- }
- for(t1=getoutargx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
-
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = duint8(s, ot, isddd);
-
- // two slice headers: in and out.
- ot = rnd(ot, widthptr);
- ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
- n = t->thistuple + t->intuple;
- ot = duintxx(s, ot, n, widthint);
- ot = duintxx(s, ot, n, widthint);
- ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
- ot = duintxx(s, ot, t->outtuple, widthint);
- ot = duintxx(s, ot, t->outtuple, widthint);
-
- // slice data
- for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- break;
-
- case TINTER:
- m = imethods(t);
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- // ../../runtime/type.go:/InterfaceType
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
- ot = duintxx(s, ot, n, widthint);
- ot = duintxx(s, ot, n, widthint);
- for(a=m; a; a=a->link) {
- // ../../runtime/type.go:/imethod
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- }
- break;
-
- case TMAP:
- // ../../runtime/type.go:/MapType
- s1 = dtypesym(t->down);
- s2 = dtypesym(t->type);
- s3 = dtypesym(mapbucket(t));
- s4 = dtypesym(hmap(t));
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- ot = dsymptr(s, ot, s3, 0);
- ot = dsymptr(s, ot, s4, 0);
- if(t->down->width > MAXKEYSIZE) {
- ot = duint8(s, ot, widthptr);
- ot = duint8(s, ot, 1); // indirect
- } else {
- ot = duint8(s, ot, t->down->width);
- ot = duint8(s, ot, 0); // not indirect
- }
- if(t->type->width > MAXVALSIZE) {
- ot = duint8(s, ot, widthptr);
- ot = duint8(s, ot, 1); // indirect
- } else {
- ot = duint8(s, ot, t->type->width);
- ot = duint8(s, ot, 0); // not indirect
- }
- ot = duint16(s, ot, mapbucket(t)->width);
- ot = duint8(s, ot, isreflexive(t->down));
- break;
-
- case TPTR32:
- case TPTR64:
- if(t->type->etype == TANY) {
- // ../../runtime/type.go:/UnsafePointerType
- ot = dcommontype(s, ot, t);
- break;
- }
- // ../../runtime/type.go:/PtrType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- break;
-
- case TSTRUCT:
- // ../../runtime/type.go:/StructType
- // for security, only the exported fields.
- n = 0;
- for(t1=t->type; t1!=T; t1=t1->down) {
- dtypesym(t1->type);
- n++;
- }
- ot = dcommontype(s, ot, t);
- xt = ot - 3*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
- ot = duintxx(s, ot, n, widthint);
- ot = duintxx(s, ot, n, widthint);
- for(t1=t->type; t1!=T; t1=t1->down) {
- // ../../runtime/type.go:/structField
- if(t1->sym && !t1->embedded) {
- ot = dgostringptr(s, ot, t1->sym->name);
- if(exportname(t1->sym->name))
- ot = dgostringptr(s, ot, nil);
- else
- ot = dgopkgpath(s, ot, t1->sym->pkg);
- } else {
- ot = dgostringptr(s, ot, nil);
- if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
- ot = dgopkgpath(s, ot, localpkg);
- else
- ot = dgostringptr(s, ot, nil);
- }
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- ot = dgostrlitptr(s, ot, t1->note);
- ot = duintptr(s, ot, t1->width); // field offset
- }
- break;
- }
- ot = dextratype(s, ot, t, xt);
- ggloblsym(s, ot, dupok|RODATA);
-
- // generate typelink.foo pointing at s = type.foo.
- // The linker will leave a table of all the typelinks for
- // types in the binary, so reflect can find them.
- // We only need the link for unnamed composites that
- // we want be able to find.
- if(t->sym == S) {
- switch(t->etype) {
- case TARRAY:
- case TCHAN:
- case TMAP:
- slink = typelinksym(t);
- dsymptr(slink, 0, s, 0);
- ggloblsym(slink, widthptr, dupok|RODATA);
- }
- }
-
- return s;
-}
-
-void
-dumptypestructs(void)
-{
- int i;
- NodeList *l;
- Node *n;
- Type *t;
- Pkg *p;
-
- // copy types from externdcl list to signatlist
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- signatlist = list(signatlist, n);
- }
-
- // process signatlist
- for(l=signatlist; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- t = n->type;
- dtypesym(t);
- if(t->sym)
- dtypesym(ptrto(t));
- }
-
- // generate import strings for imported packages
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dimportpath(p);
-
- // do basic types if compiling package runtime.
- // they have to be in at least one package,
- // and runtime is always loaded implicitly,
- // so this is as good as any.
- // another possible choice would be package main,
- // but using runtime means fewer copies in .6 files.
- if(compiling_runtime) {
- for(i=1; i<=TBOOL; i++)
- dtypesym(ptrto(types[i]));
- dtypesym(ptrto(types[TSTRING]));
- dtypesym(ptrto(types[TUNSAFEPTR]));
-
- // emit type structs for error and func(error) string.
- // The latter is the type of an auto-generated wrapper.
- dtypesym(ptrto(errortype));
- dtypesym(functype(nil,
- list1(nod(ODCLFIELD, N, typenod(errortype))),
- list1(nod(ODCLFIELD, N, typenod(types[TSTRING])))));
-
- // add paths for runtime and main, which 6l imports implicitly.
- dimportpath(runtimepkg);
- if(flag_race)
- dimportpath(racepkg);
- dimportpath(mkpkg(newstrlit("main")));
- }
-}
-
-static Sym*
-dalgsym(Type *t)
-{
- int ot;
- Sym *s, *hash, *hashfunc, *eq, *eqfunc;
- char *p;
-
- // dalgsym is only called for a type that needs an algorithm table,
- // which implies that the type is comparable (or else it would use ANOEQ).
-
- if(algtype(t) == AMEM) {
- // we use one algorithm table for all AMEM types of a given size
- p = smprint(".alg%lld", t->width);
- s = pkglookup(p, typepkg);
- free(p);
- if(s->flags & SymAlgGen)
- return s;
- s->flags |= SymAlgGen;
-
- // make hash closure
- p = smprint(".hashfunc%lld", t->width);
- hashfunc = pkglookup(p, typepkg);
- free(p);
- ot = 0;
- ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
- ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
- ggloblsym(hashfunc, ot, DUPOK|RODATA);
-
- // make equality closure
- p = smprint(".eqfunc%lld", t->width);
- eqfunc = pkglookup(p, typepkg);
- free(p);
- ot = 0;
- ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
- ot = duintxx(eqfunc, ot, t->width, widthptr);
- ggloblsym(eqfunc, ot, DUPOK|RODATA);
- } else {
- // generate an alg table specific to this type
- s = typesymprefix(".alg", t);
- hash = typesymprefix(".hash", t);
- eq = typesymprefix(".eq", t);
- hashfunc = typesymprefix(".hashfunc", t);
- eqfunc = typesymprefix(".eqfunc", t);
-
- genhash(hash, t);
- geneq(eq, t);
-
- // make Go funcs (closures) for calling hash and equal from Go
- dsymptr(hashfunc, 0, hash, 0);
- ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
- dsymptr(eqfunc, 0, eq, 0);
- ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
- }
- // ../../runtime/alg.go:/typeAlg
- ot = 0;
- ot = dsymptr(s, ot, hashfunc, 0);
- ot = dsymptr(s, ot, eqfunc, 0);
- ggloblsym(s, ot, DUPOK|RODATA);
- return s;
-}
-
-static int
-usegcprog(Type *t)
-{
- vlong size, nptr;
-
- if(!haspointers(t))
- return 0;
- if(t->width == BADWIDTH)
- dowidth(t);
- // Calculate size of the unrolled GC mask.
- nptr = (t->width+widthptr-1)/widthptr;
- size = nptr;
- if(size%2)
- size *= 2; // repeated
- size = size*gcBits/8; // 4 bits per word
- // Decide whether to use unrolled GC mask or GC program.
- // We could use a more elaborate condition, but this seems to work well in practice.
- // For small objects GC program can't give significant reduction.
- // While large objects usually contain arrays; and even if it don't
- // the program uses 2-bits per word while mask uses 4-bits per word,
- // so the program is still smaller.
- return size > 2*widthptr;
-}
-
-// Generates sparse GC bitmask (4 bits per word).
-static void
-gengcmask(Type *t, uint8 *gcmask)
-{
- Bvec *vec;
- vlong xoffset, nptr, i, j;
- int half;
- uint8 bits, *pos;
-
- memset(gcmask, 0, 16);
- if(!haspointers(t))
- return;
-
- // Generate compact mask as stacks use.
- xoffset = 0;
- vec = bvalloc(2*widthptr*8);
- twobitwalktype1(t, &xoffset, vec);
-
- // Unfold the mask for the GC bitmap format:
- // 4 bits per word, 2 high bits encode pointer info.
- pos = gcmask;
- nptr = (t->width+widthptr-1)/widthptr;
- half = 0;
- // If number of words is odd, repeat the mask.
- // This makes simpler handling of arrays in runtime.
- for(j=0; j<=(nptr%2); j++) {
- for(i=0; i<nptr; i++) {
- bits = bvget(vec, i*BitsPerPointer) | bvget(vec, i*BitsPerPointer+1)<<1;
- // Some fake types (e.g. Hmap) has missing fileds.
- // twobitwalktype1 generates BitsDead for that holes,
- // replace BitsDead with BitsScalar.
- if(bits == BitsDead)
- bits = BitsScalar;
- bits <<= 2;
- if(half)
- bits <<= 4;
- *pos |= bits;
- half = !half;
- if(!half)
- pos++;
- }
- }
-}
-
-// Helper object for generation of GC programs.
-typedef struct ProgGen ProgGen;
-struct ProgGen
-{
- Sym* s;
- int32 datasize;
- uint8 data[256/PointersPerByte];
- vlong ot;
-};
-
-static void
-proggeninit(ProgGen *g, Sym *s)
-{
- g->s = s;
- g->datasize = 0;
- g->ot = 0;
- memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggenemit(ProgGen *g, uint8 v)
-{
- g->ot = duint8(g->s, g->ot, v);
-}
-
-// Emits insData block from g->data.
-static void
-proggendataflush(ProgGen *g)
-{
- int32 i, s;
-
- if(g->datasize == 0)
- return;
- proggenemit(g, insData);
- proggenemit(g, g->datasize);
- s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
- for(i = 0; i < s; i++)
- proggenemit(g, g->data[i]);
- g->datasize = 0;
- memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggendata(ProgGen *g, uint8 d)
-{
- g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
- g->datasize++;
- if(g->datasize == 255)
- proggendataflush(g);
-}
-
-// Skip v bytes due to alignment, etc.
-static void
-proggenskip(ProgGen *g, vlong off, vlong v)
-{
- vlong i;
-
- for(i = off; i < off+v; i++) {
- if((i%widthptr) == 0)
- proggendata(g, BitsScalar);
- }
-}
-
-// Emit insArray instruction.
-static void
-proggenarray(ProgGen *g, vlong len)
-{
- int32 i;
-
- proggendataflush(g);
- proggenemit(g, insArray);
- for(i = 0; i < widthptr; i++, len >>= 8)
- proggenemit(g, len);
-}
-
-static void
-proggenarrayend(ProgGen *g)
-{
- proggendataflush(g);
- proggenemit(g, insArrayEnd);
-}
-
-static vlong
-proggenfini(ProgGen *g)
-{
- proggendataflush(g);
- proggenemit(g, insEnd);
- return g->ot;
-}
-
-static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset);
-
-// Generates GC program for large types.
-static void
-gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
-{
- Sym *gc0, *gc1;
- vlong nptr, size, ot, xoffset;
- ProgGen g;
-
- nptr = (t->width+widthptr-1)/widthptr;
- size = nptr;
- if(size%2)
- size *= 2; // repeated twice
- size = size*PointersPerByte/8; // 4 bits per word
- size++; // unroll flag in the beginning, used by runtime (see runtime.markallocated)
- // emity space in BSS for unrolled program
- *pgc0 = S;
- // Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
- if(size <= MaxGCMask) {
- gc0 = typesymprefix(".gc", t);
- ggloblsym(gc0, size, DUPOK|NOPTR);
- *pgc0 = gc0;
- }
-
- // program in RODATA
- gc1 = typesymprefix(".gcprog", t);
- proggeninit(&g, gc1);
- xoffset = 0;
- gengcprog1(&g, t, &xoffset);
- ot = proggenfini(&g);
- ggloblsym(gc1, ot, DUPOK|RODATA);
- *pgc1 = gc1;
-}
-
-// Recursively walks type t and writes GC program into g.
-static void
-gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
-{
- vlong fieldoffset, i, o, n;
- Type *t1;
-
- switch(t->etype) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- proggenskip(g, *xoffset, t->width);
- *xoffset += t->width;
- break;
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TFUNC:
- case TCHAN:
- case TMAP:
- proggendata(g, BitsPointer);
- *xoffset += t->width;
- break;
- case TSTRING:
- proggendata(g, BitsPointer);
- proggendata(g, BitsScalar);
- *xoffset += t->width;
- break;
- case TINTER:
- // Assuming IfacePointerOnly=1.
- proggendata(g, BitsPointer);
- proggendata(g, BitsPointer);
- *xoffset += t->width;
- break;
- case TARRAY:
- if(isslice(t)) {
- proggendata(g, BitsPointer);
- proggendata(g, BitsScalar);
- proggendata(g, BitsScalar);
- } else {
- t1 = t->type;
- if(t1->width == 0) {
- // ignore
- } if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) {
- for(i = 0; i < t->bound; i++)
- gengcprog1(g, t1, xoffset);
- } else if(!haspointers(t1)) {
- n = t->width;
- n -= -*xoffset&(widthptr-1); // skip to next ptr boundary
- proggenarray(g, (n+widthptr-1)/widthptr);
- proggendata(g, BitsScalar);
- proggenarrayend(g);
- *xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width;
- } else {
- proggenarray(g, t->bound);
- gengcprog1(g, t1, xoffset);
- *xoffset += (t->bound-1)*t1->width;
- proggenarrayend(g);
- }
- }
- break;
- case TSTRUCT:
- o = 0;
- for(t1 = t->type; t1 != T; t1 = t1->down) {
- fieldoffset = t1->width;
- proggenskip(g, *xoffset, fieldoffset - o);
- *xoffset += fieldoffset - o;
- gengcprog1(g, t1->type, xoffset);
- o = fieldoffset + t1->type->width;
- }
- proggenskip(g, *xoffset, t->width - o);
- *xoffset += t->width - o;
- break;
- default:
- fatal("gengcprog1: unexpected type, %T", t);
- }
-}
diff --git a/src/cmd/gc/reg.c b/src/cmd/gc/reg.c
deleted file mode 100644
index 67409c2127..0000000000
--- a/src/cmd/gc/reg.c
+++ /dev/null
@@ -1,1233 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 "go.h"
-#include "popt.h"
-
-static Flow* firstf;
-static int first = 1;
-
-static void addmove(Flow*, int, int, int);
-static Bits mkvar(Flow*, Adr*);
-static void prop(Flow*, Bits, Bits);
-static void synch(Flow*, Bits);
-static uint64 allreg(uint64, Rgn*);
-static void paint1(Flow*, int);
-static uint64 paint2(Flow*, int, int);
-static void paint3(Flow*, int, uint64, int);
-static void addreg(Adr*, int);
-
-static int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- if(p1->cost != p2->cost)
- return p2->cost - p1->cost;
- if(p1->varno != p2->varno)
- return p2->varno - p1->varno;
- if(p1->enter != p2->enter)
- return p2->enter->id - p1->enter->id;
- return 0;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Node *node;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- node = var[i].node;
- n = var[i].name;
- biclr(&bit, i);
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n)
- v->addr = 2;
- }
- }
-}
-
-static Node* regnodes[64];
-
-static void walkvardef(Node *n, Flow *r, int active);
-
-void
-regopt(Prog *firstp)
-{
- Flow *f, *f1;
- Reg *r;
- Prog *p;
- Graph *g;
- ProgInfo info;
- int i, z, active;
- uint64 vreg, usedreg;
- uint64 mask;
- int nreg;
- char **regnames;
- Bits bit;
- Rgn *rgp;
-
- if(first) {
- fmtinstall('Q', Qconv);
- first = 0;
- }
-
- mergetemp(firstp);
-
- /*
- * control flow is more complicated in generated go code
- * than in generated c code. define pseudo-variables for
- * registers, so we have complete register usage information.
- */
- regnames = thearch.regnames(&nreg);
- nvar = nreg;
- memset(var, 0, nreg*sizeof var[0]);
- for(i=0; i<nreg; i++) {
- if(regnodes[i] == N)
- regnodes[i] = newname(lookup(regnames[i]));
- var[i].node = regnodes[i];
- }
-
- regbits = thearch.excludedregs();
- externs = zbits;
- params = zbits;
- consts = zbits;
- addrs = zbits;
- ivar = zbits;
- ovar = zbits;
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- g = flowstart(firstp, sizeof(Reg));
- if(g == nil) {
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- return;
- }
-
- firstf = g->start;
-
- for(f = firstf; f != nil; f = f->link) {
- p = f->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- thearch.proginfo(&info, p);
-
- // Avoid making variables for direct-called functions.
- if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
- continue;
-
- // from vs to doesn't matter for registers.
- r = (Reg*)f->data;
- r->use1.b[0] |= info.reguse | info.regindex;
- r->set.b[0] |= info.regset;
-
- bit = mkvar(f, &p->from);
- if(bany(&bit)) {
- if(info.flags & LeftAddr)
- setaddrs(bit);
- if(info.flags & LeftRead)
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- if(info.flags & LeftWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
-
- // Compute used register for reg
- if(info.flags & RegRead)
- r->use1.b[0] |= thearch.RtoB(p->reg);
-
- // Currently we never generate three register forms.
- // If we do, this will need to change.
- if(p->from3.type != TYPE_NONE)
- fatal("regopt not implemented for from3");
-
- bit = mkvar(f, &p->to);
- if(bany(&bit)) {
- if(info.flags & RightAddr)
- setaddrs(bit);
- if(info.flags & RightRead)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- if(info.flags & RightWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
- }
-
- for(i=0; i<nvar; i++) {
- Var *v;
- v = var+i;
- if(v->addr) {
- bit = blsh(i);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- }
-
- if(debug['R'] && debug['v'])
- print("bit=%2d addr=%d et=%E w=%-2d s=%N + %lld\n",
- i, v->addr, v->etype, v->width, v->node, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", firstf, 1);
-
- /*
- * pass 2
- * find looping structure
- */
- flowrpo(g);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", firstf, 1);
-
- /*
- * pass 2.5
- * iterate propagating fat vardef covering forward
- * r->act records vars with a VARDEF since the last CALL.
- * (r->act will be reused in pass 5 for something else,
- * but we'll be done with it by then.)
- */
- active = 0;
- for(f = firstf; f != nil; f = f->link) {
- f->active = 0;
- r = (Reg*)f->data;
- r->act = zbits;
- }
- for(f = firstf; f != nil; f = f->link) {
- p = f->prog;
- if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
- active++;
- walkvardef(p->to.node, f, active);
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(f = firstf; f != nil; f = f->link)
- f->active = 0;
- for(f = firstf; f != nil; f = f->link)
- if(f->prog->as == ARET)
- prop(f, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(f = firstf; f != nil; f = f1) {
- f1 = f->link;
- if(f1 && f1->active && !f->active) {
- prop(f, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", firstf, 1);
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(f = firstf; f != nil; f = f->link)
- f->active = 0;
- synch(firstf, zbits);
- if(change)
- goto loop2;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", firstf, 1);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- if(nreg == 64)
- mask = ~0ULL; // can't rely on C to shift by 64
- else
- mask = (1ULL<<nreg) - 1;
- for(f = firstf; f != nil; f = f->link) {
- r = (Reg*)f->data;
- r->regu = (r->refbehind.b[0] | r->set.b[0]) & mask;
- r->set.b[0] &= ~mask;
- r->use1.b[0] &= ~mask;
- r->use2.b[0] &= ~mask;
- r->refbehind.b[0] &= ~mask;
- r->refahead.b[0] &= ~mask;
- r->calbehind.b[0] &= ~mask;
- r->calahead.b[0] &= ~mask;
- r->regdiff.b[0] &= ~mask;
- r->act.b[0] &= ~mask;
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass4.5", firstf, 1);
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- f = firstf;
- if(f) {
- r = (Reg*)f->data;
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) && !f->refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", f->prog->lineno, bit);
- f->refset = 1;
- }
- }
- for(f = firstf; f != nil; f = f->link)
- ((Reg*)f->data)->act = zbits;
- nregion = 0;
- for(f = firstf; f != nil; f = f->link) {
- r = (Reg*)f->data;
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit) && !f->refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", f->prog->lineno, bit);
- f->refset = 1;
- thearch.excise(f);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- change = 0;
- paint1(f, i);
- biclr(&bit, i);
- if(change <= 0)
- continue;
- if(nregion >= NRGN) {
- if(debug['R'] && debug['v'])
- print("too many regions\n");
- goto brk;
- }
- rgp = &region[nregion];
- rgp->enter = f;
- rgp->varno = i;
- rgp->cost = change;
- nregion++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- if(debug['R'] && debug['v'])
- dumpit("pass5", firstf, 1);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- if(debug['R'] && debug['v'])
- print("\nregisterizing\n");
- for(i=0; i<nregion; i++) {
- rgp = &region[i];
- if(debug['R'] && debug['v'])
- print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->prog->pc);
- bit = blsh(rgp->varno);
- usedreg = paint2(rgp->enter, rgp->varno, 0);
- vreg = allreg(usedreg, rgp);
- if(rgp->regno != 0) {
- if(debug['R'] && debug['v']) {
- Var *v;
-
- v = var + rgp->varno;
- print("registerize %N+%lld (bit=%2d et=%E) in %R usedreg=%#llx vreg=%#llx\n",
- v->node, v->offset, rgp->varno, v->etype, rgp->regno, usedreg, vreg);
- }
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- }
- }
-
- /*
- * free aux structures. peep allocates new ones.
- */
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- flowend(g);
- firstf = nil;
-
- if(debug['R'] && debug['v']) {
- // Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, 0);
- firstf = g->start;
- dumpit("pass6", firstf, 0);
- flowend(g);
- firstf = nil;
- }
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- thearch.peep(firstp);
-
- /*
- * eliminate nops
- */
- for(p=firstp; p!=P; p=p->link) {
- while(p->link != P && p->link->as == ANOP)
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
- p->to.u.branch = p->to.u.branch->link;
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.nreload ||
- ostats.ndelmov ||
- ostats.nvar ||
- ostats.naddr ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.nreload)
- print(" %4d reload\n", ostats.nreload);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d var\n", ostats.nvar);
- if(ostats.naddr)
- print(" %4d addr\n", ostats.naddr);
-
- memset(&ostats, 0, sizeof(ostats));
- }
-}
-
-static void
-walkvardef(Node *n, Flow *f, int active)
-{
- Flow *f1, *f2;
- int bn;
- Var *v;
-
- for(f1=f; f1!=nil; f1=f1->s1) {
- if(f1->active == active)
- break;
- f1->active = active;
- if(f1->prog->as == AVARKILL && f1->prog->to.node == n)
- break;
- for(v=n->opt; v!=nil; v=v->nextinnode) {
- bn = v->id;
- biset(&((Reg*)f1->data)->act, bn);
- }
- if(f1->prog->as == ACALL)
- break;
- }
-
- for(f2=f; f2!=f1; f2=f2->s1)
- if(f2->s2 != nil)
- walkvardef(n, f2->s2, active);
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-static void
-addmove(Flow *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- clearp(p1);
- p1->pc = 9999;
-
- p = r->prog;
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = TYPE_MEM;
- a->name = v->name;
- a->node = v->node;
- a->sym = linksym(v->node->sym);
- /* NOTE(rsc): 9g did
- if(a->etype == TARRAY)
- a->type = TYPE_ADDR;
- else if(a->sym == nil)
- a->type = TYPE_CONST;
- */
-
- p1->as = thearch.optoas(OAS, types[(uchar)v->etype]);
- // TODO(rsc): Remove special case here.
- if((thearch.thechar == '9' || thearch.thechar == '5') && v->etype == TBOOL)
- p1->as = thearch.optoas(OAS, types[TUINT8]);
- p1->from.type = TYPE_REG;
- p1->from.reg = rn;
- p1->from.name = NAME_NONE;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = TYPE_REG;
- a->reg = rn;
- }
- if(debug['R'] && debug['v'])
- print("%P ===add=== %P\n", p, p1);
- ostats.nspill++;
-}
-
-static int
-overlap(int64 o1, int w1, int64 o2, int w2)
-{
- int64 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-static Bits
-mkvar(Flow *f, Adr *a)
-{
- Var *v;
- int i, n, et, z, flag;
- int64 w;
- uint64 regu;
- int64 o;
- Bits bit;
- Node *node;
- Reg *r;
-
-
- /*
- * mark registers used
- */
- if(a->type == TYPE_NONE)
- goto none;
-
- r = (Reg*)f->data;
- r->use1.b[0] |= thearch.doregbits(a->index); // TODO: Use RtoB
-
- switch(a->type) {
- default:
- regu = thearch.doregbits(a->reg) | thearch.RtoB(a->reg); // TODO: Use RtoB
- if(regu == 0)
- goto none;
- bit = zbits;
- bit.b[0] = regu;
- return bit;
-
- case TYPE_ADDR:
- // TODO(rsc): Remove special case here.
- if(thearch.thechar == '9' || thearch.thechar == '5')
- goto memcase;
- a->type = TYPE_MEM;
- bit = mkvar(f, a);
- setaddrs(bit);
- a->type = TYPE_ADDR;
- ostats.naddr++;
- goto none;
-
- case TYPE_MEM:
- memcase:
- if(r != R) {
- r->use1.b[0] |= thearch.RtoB(a->reg);
- /* NOTE: 5g did
- if(r->f.prog->scond & (C_PBIT|C_WBIT))
- r->set.b[0] |= RtoB(a->reg);
- */
- }
- switch(a->name) {
- default:
- goto none;
- case NAME_EXTERN:
- case NAME_STATIC:
- case NAME_PARAM:
- case NAME_AUTO:
- n = a->name;
- break;
- }
- }
-
- node = a->node;
- if(node == N || node->op != ONAME || node->orig == N)
- goto none;
- node = node->orig;
- if(node->orig != node)
- fatal("%D: bad node", a);
- if(node->sym == S || node->sym->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
- if(w < 0)
- fatal("bad width %lld for %D", w, a);
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w) {
- // TODO(rsc): Remove special case for arm here.
- if(!flag || thearch.thechar != '5')
- return blsh(i);
- }
-
- // if they overlap, disable both
- if(overlap(v->offset, v->width, o, w)) {
-// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && node != N)
- fatal("variable not optimized: %#N", node);
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node)
- v->addr = 1;
- }
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->id = i;
- v->offset = o;
- v->name = n;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = node;
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v->nextinnode = node->opt;
- node->opt = v;
-
- bit = blsh(i);
- if(n == NAME_EXTERN || n == NAME_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == NAME_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
-
- if(node->class == PPARAM)
- for(z=0; z<BITS; z++)
- ivar.b[z] |= bit.b[z];
- if(node->class == PPARAMOUT)
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in ../gc/plive.c does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.c:/^typecheckclosure and dcl.c:/^oldname.
- if(node->addrtaken)
- v->addr = 1;
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
- v->addr = 1;
-
- if(debug['R'])
- print("bit=%2d et=%E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
- ostats.nvar++;
-
- return bit;
-
-none:
- return zbits;
-}
-
-static void
-prop(Flow *f, Bits ref, Bits cal)
-{
- Flow *f1, *f2;
- Reg *r, *r1;
- int z, i;
- Var *v, *v1;
-
- for(f1 = f; f1 != nil; f1 = f1->p1) {
- r1 = (Reg*)f1->data;
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(f1->prog->as) {
- case ACALL:
- if(noreturn(f1->prog))
- break;
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
- ref.b[z] = 0;
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for(z=0; z<BITS; z++) {
- if(cal.b[z] == 0)
- continue;
- for(i=0; i<64; i++) {
- if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
- continue;
- v = var+z*64+i;
- if(v->node->opt == nil) // v represents fixed register, not Go variable
- continue;
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1 = v->node->opt;
- if(v == v1 || !btest(&cal, v1->id)) {
- for(; v1 != nil; v1 = v1->nextinnode) {
- biset(&cal, v1->id);
- }
- }
- }
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(f1->active)
- break;
- f1->active = 1;
- }
-
- for(; f != f1; f = f->p1) {
- r = (Reg*)f->data;
- for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
- prop(f2, r->refbehind, r->calbehind);
- }
-}
-
-static void
-synch(Flow *f, Bits dif)
-{
- Flow *f1;
- Reg *r1;
- int z;
-
- for(f1 = f; f1 != nil; f1 = f1->s1) {
- r1 = (Reg*)f1->data;
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(f1->active)
- break;
- f1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(f1->s2 != nil)
- synch(f1->s2, dif);
- }
-}
-
-static uint64
-allreg(uint64 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- case TPTR64:
- i = thearch.BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return thearch.RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- i = thearch.BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return thearch.FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-static void
-paint1(Flow *f, int bn)
-{
- Flow *f1;
- Reg *r, *r1;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL<<(bn%64);
- r = (Reg*)f->data;
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- f1 = f->p1;
- if(f1 == nil)
- break;
- r1 = (Reg*)f1->data;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- f = f1;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * f->loop;
- }
- for(;;) {
- r->act.b[z] |= bb;
-
- if(f->prog->as != ANOP) { // don't give credit for NOPs
- if(r->use1.b[z] & bb)
- change += CREF * f->loop;
- if((r->use2.b[z]|r->set.b[z]) & bb)
- change += CREF * f->loop;
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * f->loop;
- }
-
- if(r->refbehind.b[z] & bb)
- for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
- if(((Reg*)f1->data)->refahead.b[z] & bb)
- paint1(f1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- f1 = f->s2;
- if(f1 != nil)
- if(((Reg*)f1->data)->refbehind.b[z] & bb)
- paint1(f1, bn);
- f = f->s1;
- if(f == nil)
- break;
- r = (Reg*)f->data;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-static uint64
-paint2(Flow *f, int bn, int depth)
-{
- Flow *f1;
- Reg *r, *r1;
- int z;
- uint64 bb, vreg;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- vreg = regbits;
- r = (Reg*)f->data;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- f1 = f->p1;
- if(f1 == nil)
- break;
- r1 = (Reg*)f1->data;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- f = f1;
- r = r1;
- }
- for(;;) {
- if(debug['R'] && debug['v'])
- print(" paint2 %d %P\n", depth, f->prog);
-
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
- if(((Reg*)f1->data)->refahead.b[z] & bb)
- vreg |= paint2(f1, bn, depth+1);
-
- if(!(r->refahead.b[z] & bb))
- break;
- f1 = f->s2;
- if(f1 != nil)
- if(((Reg*)f1->data)->refbehind.b[z] & bb)
- vreg |= paint2(f1, bn, depth+1);
- f = f->s1;
- if(f == nil)
- break;
- r = (Reg*)f->data;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-
- return vreg;
-}
-
-static void
-paint3(Flow *f, int bn, uint64 rb, int rn)
-{
- Flow *f1;
- Reg *r, *r1;
- Prog *p;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- r = (Reg*)f->data;
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- f1 = f->p1;
- if(f1 == nil)
- break;
- r1 = (Reg*)f1->data;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- f = f1;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(f, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = f->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(f, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
- if(((Reg*)f1->data)->refahead.b[z] & bb)
- paint3(f1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- f1 = f->s2;
- if(f1 != nil)
- if(((Reg*)f1->data)->refbehind.b[z] & bb)
- paint3(f1, bn, rb, rn);
- f = f->s1;
- if(f == nil)
- break;
- r = (Reg*)f->data;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-static void
-addreg(Adr *a, int rn)
-{
- a->sym = nil;
- a->node = nil;
- a->offset = 0;
- a->type = TYPE_REG;
- a->reg = rn;
- a->name = 0;
-
- ostats.ncvtreg++;
-}
-
-void
-dumpone(Flow *f, int isreg)
-{
- int z;
- Bits bit;
- Reg *r;
-
- print("%d:%P", f->loop, f->prog);
- if(isreg) {
- r = (Reg*)f->data;
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print(" cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- }
- print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
- Flow *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != nil; r = r->link) {
- dumpone(r, isreg);
- r1 = r->p2;
- if(r1 != nil) {
- print(" pred:");
- for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", (int)r1->prog->pc);
- if(r->p1 != nil)
- print(" (and %.4ud)", (int)r->p1->prog->pc);
- else
- print(" (only)");
- print("\n");
- }
- // Print successors if it's not just the next one
- if(r->s1 != r->link || r->s2 != nil) {
- print(" succ:");
- if(r->s1 != nil)
- print(" %.4ud", (int)r->s1->prog->pc);
- if(r->s2 != nil)
- print(" %.4ud", (int)r->s2->prog->pc);
- print("\n");
- }
- }
-}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
deleted file mode 100644
index 0a4c1b8cbb..0000000000
--- a/src/cmd/gc/runtime.go
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-// +build ignore
-
-package PACKAGE
-
-// emitted by compiler, not referred to by go programs
-
-func newobject(typ *byte) *any
-func panicindex()
-func panicslice()
-func panicdivide()
-func throwreturn()
-func throwinit()
-func panicwrap(string, string, string)
-
-func gopanic(interface{})
-func gorecover(*int32) interface{}
-
-func printbool(bool)
-func printfloat(float64)
-func printint(int64)
-func printhex(uint64)
-func printuint(uint64)
-func printcomplex(complex128)
-func printstring(string)
-func printpointer(any)
-func printiface(any)
-func printeface(any)
-func printslice(any)
-func printnl()
-func printsp()
-func printlock()
-func printunlock()
-
-func concatstring2(*[32]byte, string, string) string
-func concatstring3(*[32]byte, string, string, string) string
-func concatstring4(*[32]byte, string, string, string, string) string
-func concatstring5(*[32]byte, string, string, string, string, string) string
-func concatstrings(*[32]byte, []string) string
-
-func cmpstring(string, string) int
-func eqstring(string, string) bool
-func intstring(*[4]byte, int64) string
-func slicebytetostring(*[32]byte, []byte) string
-func slicebytetostringtmp([]byte) string
-func slicerunetostring(*[32]byte, []rune) string
-func stringtoslicebyte(*[32]byte, string) []byte
-func stringtoslicebytetmp(string) []byte
-func stringtoslicerune(*[32]rune, string) []rune
-func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv rune)
-func slicecopy(to any, fr any, wid uintptr) int
-func slicestringcopy(to any, fr any) int
-
-// interface conversions
-func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
-func convI2E(elem any) (ret any)
-func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem *any) (ret any)
-func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
-
-// interface type assertions x.(T)
-func assertE2E(typ *byte, iface any, ret *any)
-func assertE2E2(typ *byte, iface any, ret *any) bool
-func assertE2I(typ *byte, iface any, ret *any)
-func assertE2I2(typ *byte, iface any, ret *any) bool
-func assertE2T(typ *byte, iface any, ret *any)
-func assertE2T2(typ *byte, iface any, ret *any) bool
-func assertI2E(typ *byte, iface any, ret *any)
-func assertI2E2(typ *byte, iface any, ret *any) bool
-func assertI2I(typ *byte, iface any, ret *any)
-func assertI2I2(typ *byte, iface any, ret *any) bool
-func assertI2T(typ *byte, iface any, ret *any)
-func assertI2T2(typ *byte, iface any, ret *any) bool
-
-func ifaceeq(i1 any, i2 any) (ret bool)
-func efaceeq(i1 any, i2 any) (ret bool)
-func ifacethash(i1 any) (ret uint32)
-func efacethash(i1 any) (ret uint32)
-
-// *byte is really *runtime.Type
-func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
-func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
-func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
-func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
-func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
-func mapdelete(mapType *byte, hmap map[any]any, key *any)
-func mapiternext(hiter *any)
-
-// *byte is really *runtime.Type
-func makechan(chanType *byte, hint int64) (hchan chan any)
-func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
-func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
-func chansend1(chanType *byte, hchan chan<- any, elem *any)
-func closechan(hchan any)
-
-// *byte is really *runtime.Type
-func writebarrierptr(dst *any, src any)
-func writebarrierstring(dst *any, src any)
-func writebarrierslice(dst *any, src any)
-func writebarrieriface(dst *any, src any)
-
-// The unused *byte argument makes sure that src is 2-pointer-aligned,
-// which is the maximum alignment on NaCl amd64p32
-// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
-// The bitmap in the name tells which words being copied are pointers.
-func writebarrierfat01(dst *any, _ *byte, src any)
-func writebarrierfat10(dst *any, _ *byte, src any)
-func writebarrierfat11(dst *any, _ *byte, src any)
-func writebarrierfat001(dst *any, _ *byte, src any)
-func writebarrierfat010(dst *any, _ *byte, src any)
-func writebarrierfat011(dst *any, _ *byte, src any)
-func writebarrierfat100(dst *any, _ *byte, src any)
-func writebarrierfat101(dst *any, _ *byte, src any)
-func writebarrierfat110(dst *any, _ *byte, src any)
-func writebarrierfat111(dst *any, _ *byte, src any)
-func writebarrierfat0001(dst *any, _ *byte, src any)
-func writebarrierfat0010(dst *any, _ *byte, src any)
-func writebarrierfat0011(dst *any, _ *byte, src any)
-func writebarrierfat0100(dst *any, _ *byte, src any)
-func writebarrierfat0101(dst *any, _ *byte, src any)
-func writebarrierfat0110(dst *any, _ *byte, src any)
-func writebarrierfat0111(dst *any, _ *byte, src any)
-func writebarrierfat1000(dst *any, _ *byte, src any)
-func writebarrierfat1001(dst *any, _ *byte, src any)
-func writebarrierfat1010(dst *any, _ *byte, src any)
-func writebarrierfat1011(dst *any, _ *byte, src any)
-func writebarrierfat1100(dst *any, _ *byte, src any)
-func writebarrierfat1101(dst *any, _ *byte, src any)
-func writebarrierfat1110(dst *any, _ *byte, src any)
-func writebarrierfat1111(dst *any, _ *byte, src any)
-
-func typedmemmove(typ *byte, dst *any, src *any)
-func typedslicecopy(typ *byte, dst any, src any) int
-
-func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
-func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
-func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
-
-func newselect(sel *byte, selsize int64, size int32)
-func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
-func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
-func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
-func selectdefault(sel *byte) (selected bool)
-func selectgo(sel *byte)
-func block()
-
-func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func growslice(typ *byte, old []any, n int64) (ary []any)
-func memmove(to *any, frm *any, length uintptr)
-func memclr(ptr *byte, length uintptr)
-
-func memequal(x, y *any, size uintptr) bool
-func memequal8(x, y *any) bool
-func memequal16(x, y *any) bool
-func memequal32(x, y *any) bool
-func memequal64(x, y *any) bool
-func memequal128(x, y *any) bool
-
-// only used on 32-bit
-func int64div(int64, int64) int64
-func uint64div(uint64, uint64) uint64
-func int64mod(int64, int64) int64
-func uint64mod(uint64, uint64) uint64
-func float64toint64(float64) int64
-func float64touint64(float64) uint64
-func int64tofloat64(int64) float64
-func uint64tofloat64(uint64) float64
-
-func complex128div(num complex128, den complex128) (quo complex128)
-
-// race detection
-func racefuncenter(uintptr)
-func racefuncexit()
-func raceread(uintptr)
-func racewrite(uintptr)
-func racereadrange(addr, size uintptr)
-func racewriterange(addr, size uintptr)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
deleted file mode 100644
index 537d0ca928..0000000000
--- a/src/cmd/gc/select.c
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * select
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static Type* selecttype(int32 size);
-
-void
-typecheckselect(Node *sel)
-{
- Node *ncase, *n, *def;
- NodeList *l;
- int lno, count;
-
- def = nil;
- lno = setlineno(sel);
- count = 0;
- typechecklist(sel->ninit, Etop);
- for(l=sel->list; l; l=l->next) {
- count++;
- ncase = l->n;
- setlineno(ncase);
- if(ncase->op != OXCASE)
- fatal("typecheckselect %O", ncase->op);
-
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in select (first at %L)", def->lineno);
- else
- def = ncase;
- } else if(ncase->list->next) {
- yyerror("select cases cannot be lists");
- } else {
- n = typecheck(&ncase->list->n, Etop);
- ncase->left = n;
- ncase->list = nil;
- setlineno(n);
- switch(n->op) {
- default:
- yyerror("select case must be receive, send or assign recv");
- break;
-
- case OAS:
- // convert x = <-c into OSELRECV(x, <-c).
- // remove implicit conversions; the eventual assignment
- // will reintroduce them.
- if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
- n->right = n->right->left;
-
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV;
- break;
-
- case OAS2RECV:
- // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
- if(n->rlist->n->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV2;
- n->left = n->list->n;
- n->ntest = n->list->next->n;
- n->list = nil;
- n->right = n->rlist->n;
- n->rlist = nil;
- break;
-
- case ORECV:
- // convert <-c into OSELRECV(N, <-c)
- n = nod(OSELRECV, N, n);
- n->typecheck = 1;
- ncase->left = n;
- break;
-
- case OSEND:
- break;
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
- sel->xoffset = count;
- lineno = lno;
-}
-
-void
-walkselect(Node *sel)
-{
- int lno, i;
- Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch;
- NodeList *l, *init;
-
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
- lno = setlineno(sel);
- i = count(sel->list);
-
- // optimization: zero-case select
- if(i == 0) {
- sel->nbody = list1(mkcall("block", nil, nil));
- goto out;
- }
-
- // optimization: one-case select: single op.
- // TODO(rsc): Reenable optimization once order.c can handle it.
- // golang.org/issue/7672.
- if(i == 1) {
- cas = sel->list->n;
- setlineno(cas);
- l = cas->ninit;
- if(cas->left != N) { // not default:
- n = cas->left;
- l = concat(l, n->ninit);
- n->ninit = nil;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // ok already
- ch = n->left;
- break;
-
- case OSELRECV:
- case OSELRECV2:
- ch = n->right->left;
- if(n->op == OSELRECV || n->ntest == N) {
- if(n->left == N)
- n = n->right;
- else
- n->op = OAS;
- break;
- }
-
- if(n->left == N) {
- typecheck(&nblank, Erv | Easgn);
- n->left = nblank;
- }
- n->op = OAS2;
- n->list = list(list1(n->left), n->ntest);
- n->rlist = list1(n->right);
- n->right = N;
- n->left = N;
- n->ntest = N;
- n->typecheck = 0;
- typecheck(&n, Etop);
- break;
- }
-
- // if ch == nil { block() }; n;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, ch, nodnil());
- a->nbody = list1(mkcall("block", nil, &l));
- typecheck(&a, Etop);
- l = list(l, a);
- l = list(l, n);
- }
- l = concat(l, cas->nbody);
- sel->nbody = l;
- goto out;
- }
-
- // convert case value arguments to addresses.
- // this rewrite is used by both the general code and the next optimization.
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- setlineno(cas);
- n = cas->left;
- if(n == N)
- continue;
- switch(n->op) {
- case OSEND:
- n->right = nod(OADDR, n->right, N);
- typecheck(&n->right, Erv);
- break;
- case OSELRECV:
- case OSELRECV2:
- if(n->op == OSELRECV2 && n->ntest == N)
- n->op = OSELRECV;
- if(n->op == OSELRECV2) {
- n->ntest = nod(OADDR, n->ntest, N);
- typecheck(&n->ntest, Erv);
- }
- if(n->left == N)
- n->left = nodnil();
- else {
- n->left = nod(OADDR, n->left, N);
- typecheck(&n->left, Erv);
- }
- break;
- }
- }
-
- // optimization: two-case select but one is default: single non-blocking op.
- if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
- if(sel->list->n->left == nil) {
- cas = sel->list->next->n;
- dflt = sel->list->n;
- } else {
- dflt = sel->list->next->n;
- cas = sel->list->n;
- }
-
- n = cas->left;
- setlineno(n);
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // if selectnbsend(c, v) { body } else { default body }
- ch = n->left;
- r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
- types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
- break;
-
- case OSELRECV:
- // if c != nil && selectnbrecv(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = n->right->left;
- r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
- types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
- break;
-
- case OSELRECV2:
- // if c != nil && selectnbrecv2(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = n->right->left;
- r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
- types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
- break;
- }
- typecheck(&r->ntest, Erv);
- r->nbody = cas->nbody;
- r->nelse = concat(dflt->ninit, dflt->nbody);
- sel->nbody = list1(r);
- goto out;
- }
-
- init = sel->ninit;
- sel->ninit = nil;
-
- // generate sel-struct
- setlineno(sel);
- selv = temp(selecttype(sel->xoffset));
- r = nod(OAS, selv, N);
- typecheck(&r, Etop);
- init = list(init, r);
- var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8]));
- r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset));
- typecheck(&r, Etop);
- init = list(init, r);
-
- // register cases
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- setlineno(cas);
- n = cas->left;
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- cas->ninit = nil;
- if(n != nil) {
- r->ninit = concat(r->ninit, n->ninit);
- n->ninit = nil;
- }
- if(n == nil) {
- // selectdefault(sel *byte);
- r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var);
- } else {
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
- &r->ninit, var, n->left, n->right);
- break;
-
- case OSELRECV:
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
- &r->ninit, var, n->right->left, n->left);
- break;
-
- case OSELRECV2:
- // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
- &r->ninit, var, n->right->left, n->left, n->ntest);
- break;
- }
- }
- // selv is no longer alive after use.
- r->nbody = list(r->nbody, nod(OVARKILL, selv, N));
- r->nbody = concat(r->nbody, cas->nbody);
- r->nbody = list(r->nbody, nod(OBREAK, N, N));
- init = list(init, r);
- }
-
- // run the select
- setlineno(sel);
- init = list(init, mkcall("selectgo", T, nil, var));
- sel->nbody = init;
-
-out:
- sel->list = nil;
- walkstmtlist(sel->nbody);
- lineno = lno;
-}
-
-// Keep in sync with src/runtime/chan.h.
-static Type*
-selecttype(int32 size)
-{
- Node *sel, *sudog, *scase, *arr;
-
- // TODO(dvyukov): it's possible to generate SudoG and Scase only once
- // and then cache; and also cache Select per size.
- sudog = nod(OTSTRUCT, N, N);
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("next")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32])));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8]))));
- typecheck(&sudog, Etype);
- sudog->type->noalg = 1;
- sudog->type->local = 1;
-
- scase = nod(OTSTRUCT, N, N);
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8]))));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR])));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16])));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16])));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8]))));
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
- typecheck(&scase, Etype);
- scase->type->noalg = 1;
- scase->type->local = 1;
-
- sel = nod(OTSTRUCT, N, N);
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16])));
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16])));
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8]))));
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8]))));
- arr = nod(OTARRAY, nodintconst(size), scase);
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr));
- arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8])));
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr));
- arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16]));
- sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr));
- typecheck(&sel, Etype);
- sel->type->noalg = 1;
- sel->type->local = 1;
-
- return sel->type;
-}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
deleted file mode 100644
index 1015950e41..0000000000
--- a/src/cmd/gc/sinit.c
+++ /dev/null
@@ -1,1502 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * static initialization
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum
-{
- InitNotStarted = 0,
- InitDone = 1,
- InitPending = 2,
-};
-
-static void initplan(Node*);
-static NodeList *initlist;
-static void init2(Node*, NodeList**);
-static void init2list(NodeList*, NodeList**);
-static int staticinit(Node*, NodeList**);
-static Node *staticname(Type*, int);
-
-// init1 walks the AST starting at n, and accumulates in out
-// the list of definitions needing init code in dependency order.
-static void
-init1(Node *n, NodeList **out)
-{
- NodeList *l;
- Node *nv;
-
- if(n == N)
- return;
- init1(n->left, out);
- init1(n->right, out);
- for(l=n->list; l; l=l->next)
- init1(l->n, out);
-
- if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) {
- // Methods called as Type.Method(receiver, ...).
- // Definitions for method expressions are stored in type->nname.
- init1(n->type->nname, out);
- }
-
- if(n->op != ONAME)
- return;
- switch(n->class) {
- case PEXTERN:
- case PFUNC:
- break;
- default:
- if(isblank(n) && n->curfn == N && n->defn != N && n->defn->initorder == InitNotStarted) {
- // blank names initialization is part of init() but not
- // when they are inside a function.
- break;
- }
- return;
- }
-
- if(n->initorder == InitDone)
- return;
- if(n->initorder == InitPending) {
- // Since mutually recursive sets of functions are allowed,
- // we don't necessarily raise an error if n depends on a node
- // which is already waiting for its dependencies to be visited.
- //
- // initlist contains a cycle of identifiers referring to each other.
- // If this cycle contains a variable, then this variable refers to itself.
- // Conversely, if there exists an initialization cycle involving
- // a variable in the program, the tree walk will reach a cycle
- // involving that variable.
- if(n->class != PFUNC) {
- nv = n;
- goto foundinitloop;
- }
- for(l=initlist; l->n!=n; l=l->next) {
- if(l->n->class != PFUNC) {
- nv = l->n;
- goto foundinitloop;
- }
- }
- // The loop involves only functions, ok.
- return;
-
- foundinitloop:
- // if there have already been errors printed,
- // those errors probably confused us and
- // there might not be a loop. let the user
- // fix those first.
- flusherrors();
- if(nerrors > 0)
- errorexit();
-
- // There is a loop involving nv. We know about
- // n and initlist = n1 <- ... <- nv <- ... <- n <- ...
- print("%L: initialization loop:\n", nv->lineno);
- // Build back pointers in initlist.
- for(l=initlist; l; l=l->next)
- if(l->next != nil)
- l->next->end = l;
- // Print nv -> ... -> n1 -> n.
- for(l=initlist; l->n!=nv; l=l->next);
- for(; l; l=l->end)
- print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
- // Print n -> ... -> nv.
- for(l=initlist; l->n!=n; l=l->next);
- for(; l->n != nv; l=l->end)
- print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
- print("\t%L %S\n", nv->lineno, nv->sym);
- errorexit();
- }
-
- // reached a new unvisited node.
- n->initorder = InitPending;
- l = malloc(sizeof *l);
- if(l == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- l->next = initlist;
- l->n = n;
- l->end = nil;
- initlist = l;
-
- // make sure that everything n depends on is initialized.
- // n->defn is an assignment to n
- if(n->defn != N) {
- switch(n->defn->op) {
- default:
- goto bad;
-
- case ODCLFUNC:
- init2list(n->defn->nbody, out);
- break;
-
- case OAS:
- if(n->defn->left != n)
- goto bad;
- if(isblank(n->defn->left) && candiscard(n->defn->right)) {
- n->defn->op = OEMPTY;
- n->defn->left = N;
- n->defn->right = N;
- break;
- }
-
- init2(n->defn->right, out);
- if(debug['j'])
- print("%S\n", n->sym);
- if(isblank(n) || !staticinit(n, out)) {
- if(debug['%'])
- dump("nonstatic", n->defn);
- *out = list(*out, n->defn);
- }
- break;
-
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2DOTTYPE:
- case OAS2RECV:
- if(n->defn->initorder != InitNotStarted)
- break;
- n->defn->initorder = InitDone;
- for(l=n->defn->rlist; l; l=l->next)
- init1(l->n, out);
- if(debug['%']) dump("nonstatic", n->defn);
- *out = list(*out, n->defn);
- break;
- }
- }
- l = initlist;
- initlist = l->next;
- if(l->n != n)
- fatal("bad initlist");
- free(l);
- n->initorder = InitDone;
- return;
-
-bad:
- dump("defn", n->defn);
- fatal("init1: bad defn");
-}
-
-// recurse over n, doing init1 everywhere.
-static void
-init2(Node *n, NodeList **out)
-{
- if(n == N || n->initorder == InitDone)
- return;
-
- if(n->op == ONAME && n->ninit)
- fatal("name %S with ninit: %+N\n", n->sym, n);
-
- init1(n, out);
- init2(n->left, out);
- init2(n->right, out);
- init2(n->ntest, out);
- init2list(n->ninit, out);
- init2list(n->list, out);
- init2list(n->rlist, out);
- init2list(n->nbody, out);
- init2list(n->nelse, out);
-
- if(n->op == OCLOSURE)
- init2list(n->closure->nbody, out);
- if(n->op == ODOTMETH || n->op == OCALLPART)
- init2(n->type->nname, out);
-}
-
-static void
-init2list(NodeList *l, NodeList **out)
-{
- for(; l; l=l->next)
- init2(l->n, out);
-}
-
-static void
-initreorder(NodeList *l, NodeList **out)
-{
- Node *n;
-
- for(; l; l=l->next) {
- n = l->n;
- switch(n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- continue;
- }
- initreorder(n->ninit, out);
- n->ninit = nil;
- init1(n, out);
- }
-}
-
-// initfix computes initialization order for a list l of top-level
-// declarations and outputs the corresponding list of statements
-// to include in the init() function body.
-NodeList*
-initfix(NodeList *l)
-{
- NodeList *lout;
- int lno;
-
- lout = nil;
- lno = lineno;
- initreorder(l, &lout);
- lineno = lno;
- return lout;
-}
-
-/*
- * compilation of top-level (static) assignments
- * into DATA statements if at all possible.
- */
-
-static int staticassign(Node*, Node*, NodeList**);
-
-static int
-staticinit(Node *n, NodeList **out)
-{
- Node *l, *r;
-
- if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS)
- fatal("staticinit");
-
- lineno = n->lineno;
- l = n->defn->left;
- r = n->defn->right;
- return staticassign(l, r, out);
-}
-
-// like staticassign but we are copying an already
-// initialized value r.
-static int
-staticcopy(Node *l, Node *r, NodeList **out)
-{
- int i;
- InitEntry *e;
- InitPlan *p;
- Node *a, *ll, *rr, *orig, n1;
-
- if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
- return 0;
- if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value
- return 0;
- if(r->defn->op != OAS)
- return 0;
- orig = r;
- r = r->defn->right;
-
- switch(r->op) {
- case ONAME:
- if(staticcopy(l, r, out))
- return 1;
- *out = list(*out, nod(OAS, l, r));
- return 1;
-
- case OLITERAL:
- if(iszero(r))
- return 1;
- gdata(l, r, l->type->width);
- return 1;
-
- case OADDR:
- switch(r->left->op) {
- case ONAME:
- gdata(l, r, l->type->width);
- return 1;
- }
- break;
-
- case OPTRLIT:
- switch(r->left->op) {
- default:
- //dump("not static addr", r);
- break;
- case OARRAYLIT:
- case OSTRUCTLIT:
- case OMAPLIT:
- // copy pointer
- gdata(l, nod(OADDR, r->nname, N), l->type->width);
- return 1;
- }
- break;
-
- case OARRAYLIT:
- if(isslice(r->type)) {
- // copy slice
- a = r->nname;
- n1 = *l;
- n1.xoffset = l->xoffset + Array_array;
- gdata(&n1, nod(OADDR, a, N), widthptr);
- n1.xoffset = l->xoffset + Array_nel;
- gdata(&n1, r->right, widthint);
- n1.xoffset = l->xoffset + Array_cap;
- gdata(&n1, r->right, widthint);
- return 1;
- }
- // fall through
- case OSTRUCTLIT:
- p = r->initplan;
- n1 = *l;
- for(i=0; i<p->len; i++) {
- e = &p->e[i];
- n1.xoffset = l->xoffset + e->xoffset;
- n1.type = e->expr->type;
- if(e->expr->op == OLITERAL)
- gdata(&n1, e->expr, n1.type->width);
- else {
- ll = nod(OXXX, N, N);
- *ll = n1;
- ll->orig = ll; // completely separate copy
- if(!staticassign(ll, e->expr, out)) {
- // Requires computation, but we're
- // copying someone else's computation.
- rr = nod(OXXX, N, N);
- *rr = *orig;
- rr->orig = rr; // completely separate copy
- rr->type = ll->type;
- rr->xoffset += e->xoffset;
- *out = list(*out, nod(OAS, ll, rr));
- }
- }
- }
- return 1;
- }
- return 0;
-}
-
-static int
-staticassign(Node *l, Node *r, NodeList **out)
-{
- Node *a, n1, nam;
- Type *ta;
- InitPlan *p;
- InitEntry *e;
- int i;
- Strlit *sval;
-
- switch(r->op) {
- default:
- //dump("not static", r);
- break;
-
- case ONAME:
- if(r->class == PEXTERN && r->sym->pkg == localpkg)
- return staticcopy(l, r, out);
- break;
-
- case OLITERAL:
- if(iszero(r))
- return 1;
- gdata(l, r, l->type->width);
- return 1;
-
- case OADDR:
- if(stataddr(&nam, r->left)) {
- n1 = *r;
- n1.left = &nam;
- gdata(l, &n1, l->type->width);
- return 1;
- }
-
- case OPTRLIT:
- switch(r->left->op) {
- default:
- //dump("not static ptrlit", r);
- break;
-
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- // Init pointer.
- a = staticname(r->left->type, 1);
- r->nname = a;
- gdata(l, nod(OADDR, a, N), l->type->width);
- // Init underlying literal.
- if(!staticassign(a, r->left, out))
- *out = list(*out, nod(OAS, a, r->left));
- return 1;
- }
- break;
-
- case OSTRARRAYBYTE:
- if(l->class == PEXTERN && r->left->op == OLITERAL) {
- sval = r->left->val.u.sval;
- slicebytes(l, sval->s, sval->len);
- return 1;
- }
- break;
-
- case OARRAYLIT:
- initplan(r);
- if(isslice(r->type)) {
- // Init slice.
- ta = typ(TARRAY);
- ta->type = r->type->type;
- ta->bound = mpgetfix(r->right->val.u.xval);
- a = staticname(ta, 1);
- r->nname = a;
- n1 = *l;
- n1.xoffset = l->xoffset + Array_array;
- gdata(&n1, nod(OADDR, a, N), widthptr);
- n1.xoffset = l->xoffset + Array_nel;
- gdata(&n1, r->right, widthint);
- n1.xoffset = l->xoffset + Array_cap;
- gdata(&n1, r->right, widthint);
- // Fall through to init underlying array.
- l = a;
- }
- // fall through
- case OSTRUCTLIT:
- initplan(r);
- p = r->initplan;
- n1 = *l;
- for(i=0; i<p->len; i++) {
- e = &p->e[i];
- n1.xoffset = l->xoffset + e->xoffset;
- n1.type = e->expr->type;
- if(e->expr->op == OLITERAL)
- gdata(&n1, e->expr, n1.type->width);
- else {
- a = nod(OXXX, N, N);
- *a = n1;
- a->orig = a; // completely separate copy
- if(!staticassign(a, e->expr, out))
- *out = list(*out, nod(OAS, a, e->expr));
- }
- }
- return 1;
-
- case OMAPLIT:
- // TODO: Table-driven map insert.
- break;
- }
- return 0;
-}
-
-/*
- * from here down is the walk analysis
- * of composite literals.
- * most of the work is to generate
- * data statements for the constant
- * part of the composite literal.
- */
-
-static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
-static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
-
-static Node*
-staticname(Type *t, int ctxt)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
- statuniqgen++;
- n = newname(lookup(namebuf));
- if(!ctxt)
- n->readonly = 1;
- addvar(n, t, PEXTERN);
- return n;
-}
-
-static int
-isliteral(Node *n)
-{
- if(n->op == OLITERAL)
- if(n->val.ctype != CTNIL)
- return 1;
- return 0;
-}
-
-static int
-simplename(Node *n)
-{
- if(n->op != ONAME)
- goto no;
- if(!n->addable)
- goto no;
- if(n->class & PHEAP)
- goto no;
- if(n->class == PPARAMREF)
- goto no;
- return 1;
-
-no:
- return 0;
-}
-
-static void
-litas(Node *l, Node *r, NodeList **init)
-{
- Node *a;
-
- a = nod(OAS, l, r);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-}
-
-enum
-{
- MODEDYNAM = 1,
- MODECONST = 2,
-};
-
-static int
-getdyn(Node *n, int top)
-{
- NodeList *nl;
- Node *value;
- int mode;
-
- mode = 0;
- switch(n->op) {
- default:
- if(isliteral(n))
- return MODECONST;
- return MODEDYNAM;
- case OARRAYLIT:
- if(!top && n->type->bound < 0)
- return MODEDYNAM;
- case OSTRUCTLIT:
- break;
- }
-
- for(nl=n->list; nl; nl=nl->next) {
- value = nl->n->right;
- mode |= getdyn(value, 0);
- if(mode == (MODEDYNAM|MODECONST))
- break;
- }
- return mode;
-}
-
-static void
-structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *nl;
- Node *index, *value;
-
- for(nl=n->list; nl; nl=nl->next) {
- r = nl->n;
- if(r->op != OKEY)
- fatal("structlit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(ODOT, var, newname(index->sym));
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(ODOT, var, newname(index->sym));
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var.field = expr
- a = nod(ODOT, var, newname(index->sym));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- if(pass == 1) {
- walkexpr(&a, init); // add any assignments in r to top
- if(a->op != OAS)
- fatal("structlit: not as");
- a->dodata = 2;
- } else {
- orderstmtinplace(&a);
- walkstmt(&a);
- }
- *init = list(*init, a);
- }
-}
-
-static void
-arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Node *index, *value;
-
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("arraylit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(OINDEX, var, index);
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(OINDEX, var, index);
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var[index] = value
- a = nod(OINDEX, var, index);
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- if(pass == 1) {
- walkexpr(&a, init);
- if(a->op != OAS)
- fatal("arraylit: not as");
- a->dodata = 2;
- } else {
- orderstmtinplace(&a);
- walkstmt(&a);
- }
- *init = list(*init, a);
- }
-}
-
-static void
-slicelit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Type *t;
- Node *vstat, *vauto;
- Node *index, *value;
- int mode;
-
- // make an array type
- t = shallow(n->type);
- t->bound = mpgetfix(n->right->val.u.xval);
- t->width = 0;
- t->sym = nil;
- t->haspointers = 0;
- dowidth(t);
-
- if(ctxt != 0) {
- // put everything into static array
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- arraylit(ctxt, 2, n, vstat, init);
-
- // copy static to slice
- a = nod(OSLICE, vstat, nod(OKEY, N, N));
- a = nod(OAS, var, a);
- typecheck(&a, Etop);
- a->dodata = 2;
- *init = list(*init, a);
- return;
- }
-
- // recipe for var = []t{...}
- // 1. make a static array
- // var vstat [...]t
- // 2. assign (data statements) the constant part
- // vstat = constpart{}
- // 3. make an auto pointer to array and allocate heap to it
- // var vauto *[...]t = new([...]t)
- // 4. copy the static array to the auto array
- // *vauto = vstat
- // 5. assign slice of allocated heap to var
- // var = [0:]*auto
- // 6. for each dynamic part assign to the slice
- // var[i] = dynamic part
- //
- // an optimization is done if there is no constant part
- // 3. var vauto *[...]t = new([...]t)
- // 5. var = [0:]*auto
- // 6. var[i] = dynamic part
-
- // if the literal contains constants,
- // make static initialized array (1),(2)
- vstat = N;
- mode = getdyn(n, 1);
- if(mode & MODECONST) {
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- }
-
- // make new auto *array (3 declare)
- vauto = temp(ptrto(t));
-
- // set auto to point at new temp or heap (3 assign)
- if(n->alloc != N) {
- // temp allocated during order.c for dddarg
- n->alloc->type = t;
- if(vstat == N) {
- a = nod(OAS, n->alloc, N);
- typecheck(&a, Etop);
- *init = list(*init, a); // zero new temp
- }
- a = nod(OADDR, n->alloc, N);
- } else if(n->esc == EscNone) {
- a = temp(t);
- if(vstat == N) {
- a = nod(OAS, temp(t), N);
- typecheck(&a, Etop);
- *init = list(*init, a); // zero new temp
- a = a->left;
- }
- a = nod(OADDR, a, N);
- } else {
- a = nod(ONEW, N, N);
- a->list = list1(typenod(t));
- }
- a = nod(OAS, vauto, a);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- if(vstat != N) {
- // copy static to heap (4)
- a = nod(OIND, vauto, N);
- a = nod(OAS, a, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
-
- // make slice out of heap (5)
- a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
- typecheck(&a, Etop);
- orderstmtinplace(&a);
- walkstmt(&a);
- *init = list(*init, a);
-
- // put dynamics into slice (6)
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
- a = nod(OINDEX, var, index);
- a->bounded = 1;
- // TODO need to check bounds?
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0)
- break;
- arraylit(ctxt, 2, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- structlit(ctxt, 2, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- orderstmtinplace(&a);
- walkstmt(&a);
- *init = list(*init, a);
- }
-}
-
-static void
-maplit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- int nerr;
- int64 b;
- Type *t, *tk, *tv, *t1;
- Node *vstat, *index, *value, *key, *val;
- Sym *syma, *symb;
-
-USED(ctxt);
-ctxt = 0;
-
- // make the map var
- nerr = nerrors;
-
- a = nod(OMAKE, N, N);
- a->list = list1(typenod(n->type));
- litas(var, a, init);
-
- // count the initializers
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("maplit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- b++;
- }
-
- if(b != 0) {
- // build type [count]struct { a Tindex, b Tvalue }
- t = n->type;
- tk = t->down;
- tv = t->type;
-
- symb = lookup("b");
- t = typ(TFIELD);
- t->type = tv;
- t->sym = symb;
-
- syma = lookup("a");
- t1 = t;
- t = typ(TFIELD);
- t->type = tk;
- t->sym = syma;
- t->down = t1;
-
- t1 = t;
- t = typ(TSTRUCT);
- t->type = t1;
-
- t1 = t;
- t = typ(TARRAY);
- t->bound = b;
- t->type = t1;
-
- dowidth(t);
-
- // make and initialize static array
- vstat = staticname(t, ctxt);
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("maplit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value)) {
- // build vstat[b].a = key;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(syma));
- a = nod(OAS, a, index);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- // build vstat[b].b = value;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(symb));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- b++;
- }
- }
-
- // loop adding structure elements to map
- // for i = 0; i < len(vstat); i++ {
- // map[vstat[i].a] = vstat[i].b
- // }
- index = temp(types[TINT]);
-
- a = nod(OINDEX, vstat, index);
- a->bounded = 1;
- a = nod(ODOT, a, newname(symb));
-
- r = nod(OINDEX, vstat, index);
- r->bounded = 1;
- r = nod(ODOT, r, newname(syma));
- r = nod(OINDEX, var, r);
-
- r = nod(OAS, r, a);
-
- a = nod(OFOR, N, N);
- a->nbody = list1(r);
-
- a->ninit = list1(nod(OAS, index, nodintconst(0)));
- a->ntest = nod(OLT, index, nodintconst(t->bound));
- a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1)));
-
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- }
-
- // put in dynamic entries one-at-a-time
- key = nil;
- val = nil;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("maplit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr.
- // use temporary so that mapassign1 can have addressable key, val.
- if(key == nil) {
- key = temp(var->type->down);
- val = temp(var->type->type);
- }
- a = nod(OAS, key, r->left);
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- a = nod(OAS, val, r->right);
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
-
- a = nod(OAS, nod(OINDEX, var, key), val);
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
-
- if(nerr != nerrors)
- break;
- }
-
- if(key != nil) {
- a = nod(OVARKILL, key, N);
- typecheck(&a, Etop);
- *init = list(*init, a);
- a = nod(OVARKILL, val, N);
- typecheck(&a, Etop);
- *init = list(*init, a);
- }
-}
-
-void
-anylit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Type *t;
- Node *a, *vstat, *r;
-
- t = n->type;
- switch(n->op) {
- default:
- fatal("anylit: not lit");
-
- case OPTRLIT:
- if(!isptr[t->etype])
- fatal("anylit: not ptr");
-
- if(n->right != N) {
- r = nod(OADDR, n->right, N);
- typecheck(&r, Erv);
- } else {
- r = nod(ONEW, N, N);
- r->typecheck = 1;
- r->type = t;
- r->esc = n->esc;
- }
- walkexpr(&r, init);
- a = nod(OAS, var, r);
-
- typecheck(&a, Etop);
- *init = list(*init, a);
-
- var = nod(OIND, var, N);
- typecheck(&var, Erv | Easgn);
- anylit(ctxt, n->left, var, init);
- break;
-
- case OSTRUCTLIT:
- if(t->etype != TSTRUCT)
- fatal("anylit: not struct");
-
- if(simplename(var) && count(n->list) > 4) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- structlit(ctxt, 1, n, vstat, init);
-
- // copy static to var
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- structlit(ctxt, 2, n, var, init);
- break;
- }
- structlit(ctxt, 1, n, var, init);
- structlit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(simplename(var) || count(n->list) < structcount(t)) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- structlit(ctxt, 3, n, var, init);
- break;
-
- case OARRAYLIT:
- if(t->etype != TARRAY)
- fatal("anylit: not array");
- if(t->bound < 0) {
- slicelit(ctxt, n, var, init);
- break;
- }
-
- if(simplename(var) && count(n->list) > 4) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- arraylit(1, 1, n, vstat, init);
-
- // copy static to automatic
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- arraylit(ctxt, 2, n, var, init);
- break;
- }
- arraylit(ctxt, 1, n, var, init);
- arraylit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(simplename(var) || count(n->list) < t->bound) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- arraylit(ctxt, 3, n, var, init);
- break;
-
- case OMAPLIT:
- if(t->etype != TMAP)
- fatal("anylit: not map");
- maplit(ctxt, n, var, init);
- break;
- }
-}
-
-int
-oaslit(Node *n, NodeList **init)
-{
- int ctxt;
-
- if(n->left == N || n->right == N)
- goto no;
- if(n->left->type == T || n->right->type == T)
- goto no;
- if(!simplename(n->left))
- goto no;
- if(!eqtype(n->left->type, n->right->type))
- goto no;
-
- // context is init() function.
- // implies generated data executed
- // exactly once and not subject to races.
- ctxt = 0;
-// if(n->dodata == 1)
-// ctxt = 1;
-
- switch(n->right->op) {
- default:
- goto no;
-
- case OSTRUCTLIT:
- case OARRAYLIT:
- case OMAPLIT:
- if(vmatch1(n->left, n->right))
- goto no;
- anylit(ctxt, n->right, n->left, init);
- break;
- }
- n->op = OEMPTY;
- return 1;
-
-no:
- // not a special composit literal assignment
- return 0;
-}
-
-static int
-getlit(Node *lit)
-{
- if(smallintconst(lit))
- return mpgetfix(lit->val.u.xval);
- return -1;
-}
-
-int
-stataddr(Node *nam, Node *n)
-{
- int l;
-
- if(n == N)
- goto no;
-
- switch(n->op) {
-
- case ONAME:
- *nam = *n;
- return n->addable;
-
- case ODOT:
- if(!stataddr(nam, n->left))
- break;
- nam->xoffset += n->xoffset;
- nam->type = n->type;
- return 1;
-
- case OINDEX:
- if(n->left->type->bound < 0)
- break;
- if(!stataddr(nam, n->left))
- break;
- l = getlit(n->right);
- if(l < 0)
- break;
- // Check for overflow.
- if(n->type->width != 0 && thearch.MAXWIDTH/n->type->width <= l)
- break;
- nam->xoffset += l*n->type->width;
- nam->type = n->type;
- return 1;
- }
-
-no:
- return 0;
-}
-
-int
-gen_as_init(Node *n)
-{
- Node *nr, *nl;
- Node nam, nod1;
-
- if(n->dodata == 0)
- goto no;
-
- nr = n->right;
- nl = n->left;
- if(nr == N) {
- if(!stataddr(&nam, nl))
- goto no;
- if(nam.class != PEXTERN)
- goto no;
- goto yes;
- }
-
- if(nr->type == T || !eqtype(nl->type, nr->type))
- goto no;
-
- if(!stataddr(&nam, nl))
- goto no;
-
- if(nam.class != PEXTERN)
- goto no;
-
- switch(nr->op) {
- default:
- goto no;
-
- case OCONVNOP:
- nr = nr->left;
- if(nr == N || nr->op != OSLICEARR)
- goto no;
- // fall through
-
- case OSLICEARR:
- if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
- nr = nr->left;
- goto slice;
- }
- goto no;
-
- case OLITERAL:
- break;
- }
-
- switch(nr->type->etype) {
- default:
- goto no;
-
- case TBOOL:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TPTR32:
- case TPTR64:
- case TFLOAT32:
- case TFLOAT64:
- gdata(&nam, nr, nr->type->width);
- break;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- gdatacomplex(&nam, nr->val.u.cval);
- break;
-
- case TSTRING:
- gdatastring(&nam, nr->val.u.sval);
- break;
- }
-
-yes:
- return 1;
-
-slice:
- gused(N); // in case the data is the dest of a goto
- nl = nr;
- if(nr == N || nr->op != OADDR)
- goto no;
- nr = nr->left;
- if(nr == N || nr->op != ONAME)
- goto no;
-
- // nr is the array being converted to a slice
- if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
- goto no;
-
- nam.xoffset += Array_array;
- gdata(&nam, nl, types[tptr]->width);
-
- nam.xoffset += Array_nel-Array_array;
- nodconst(&nod1, types[TINT], nr->type->bound);
- gdata(&nam, &nod1, widthint);
-
- nam.xoffset += Array_cap-Array_nel;
- gdata(&nam, &nod1, widthint);
-
- goto yes;
-
-no:
- if(n->dodata == 2) {
- dump("\ngen_as_init", n);
- fatal("gen_as_init couldnt make data statement");
- }
- return 0;
-}
-
-static int isvaluelit(Node*);
-static InitEntry* entry(InitPlan*);
-static void addvalue(InitPlan*, vlong, Node*, Node*);
-
-static void
-initplan(Node *n)
-{
- InitPlan *p;
- Node *a;
- NodeList *l;
-
- if(n->initplan != nil)
- return;
- p = mal(sizeof *p);
- n->initplan = p;
- switch(n->op) {
- default:
- fatal("initplan");
- case OARRAYLIT:
- for(l=n->list; l; l=l->next) {
- a = l->n;
- if(a->op != OKEY || !smallintconst(a->left))
- fatal("initplan arraylit");
- addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right);
- }
- break;
- case OSTRUCTLIT:
- for(l=n->list; l; l=l->next) {
- a = l->n;
- if(a->op != OKEY || a->left->type == T)
- fatal("initplan structlit");
- addvalue(p, a->left->type->width, N, a->right);
- }
- break;
- case OMAPLIT:
- for(l=n->list; l; l=l->next) {
- a = l->n;
- if(a->op != OKEY)
- fatal("initplan maplit");
- addvalue(p, -1, a->left, a->right);
- }
- break;
- }
-}
-
-static void
-addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
-{
- int i;
- InitPlan *q;
- InitEntry *e;
-
- USED(key);
-
- // special case: zero can be dropped entirely
- if(iszero(n)) {
- p->zero += n->type->width;
- return;
- }
-
- // special case: inline struct and array (not slice) literals
- if(isvaluelit(n)) {
- initplan(n);
- q = n->initplan;
- for(i=0; i<q->len; i++) {
- e = entry(p);
- *e = q->e[i];
- e->xoffset += xoffset;
- }
- return;
- }
-
- // add to plan
- if(n->op == OLITERAL)
- p->lit += n->type->width;
- else
- p->expr += n->type->width;
-
- e = entry(p);
- e->xoffset = xoffset;
- e->expr = n;
-}
-
-int
-iszero(Node *n)
-{
- NodeList *l;
-
- switch(n->op) {
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- dump("unexpected literal", n);
- fatal("iszero");
-
- case CTNIL:
- return 1;
-
- case CTSTR:
- return n->val.u.sval == nil || n->val.u.sval->len == 0;
-
- case CTBOOL:
- return n->val.u.bval == 0;
-
- case CTINT:
- case CTRUNE:
- return mpcmpfixc(n->val.u.xval, 0) == 0;
-
- case CTFLT:
- return mpcmpfltc(n->val.u.fval, 0) == 0;
-
- case CTCPLX:
- return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0;
- }
- break;
- case OARRAYLIT:
- if(isslice(n->type))
- break;
- // fall through
- case OSTRUCTLIT:
- for(l=n->list; l; l=l->next)
- if(!iszero(l->n->right))
- return 0;
- return 1;
- }
- return 0;
-}
-
-static int
-isvaluelit(Node *n)
-{
- return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT;
-}
-
-static InitEntry*
-entry(InitPlan *p)
-{
- if(p->len >= p->cap) {
- if(p->cap == 0)
- p->cap = 4;
- else
- p->cap *= 2;
- p->e = realloc(p->e, p->cap*sizeof p->e[0]);
- if(p->e == nil)
- fatal("out of memory");
- }
- return &p->e[p->len++];
-}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
deleted file mode 100644
index f739a72499..0000000000
--- a/src/cmd/gc/subr.c
+++ /dev/null
@@ -1,3856 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "md5.h"
-#include "y.tab.h"
-#include "yerr.h"
-
-typedef struct Error Error;
-struct Error
-{
- int lineno;
- int seq;
- char *msg;
-};
-static Error *err;
-static int nerr;
-static int merr;
-
-void
-errorexit(void)
-{
- flusherrors();
- if(outfile)
- remove(outfile);
- exits("error");
-}
-
-extern int yychar;
-int
-parserline(void)
-{
- if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
- return prevlineno;
- return lineno;
-}
-
-void
-adderrorname(Node *n)
-{
- char *old;
-
- if(n->op != ODOT)
- return;
- old = smprint("%L: undefined: %N\n", n->lineno, n->left);
- if(nerr > 0 && err[nerr-1].lineno == n->lineno && strcmp(err[nerr-1].msg, old) == 0)
- err[nerr-1].msg = smprint("%L: undefined: %N in %N\n", n->lineno, n->left, n);
- free(old);
-}
-
-static void
-adderr(int line, char *fmt, va_list arg)
-{
- Fmt f;
- Error *p;
-
- fmtstrinit(&f);
- fmtprint(&f, "%L: ", line);
- fmtvprint(&f, fmt, arg);
- fmtprint(&f, "\n");
-
- if(nerr >= merr) {
- if(merr == 0)
- merr = 16;
- else
- merr *= 2;
- p = realloc(err, merr*sizeof err[0]);
- if(p == nil) {
- merr = nerr;
- flusherrors();
- print("out of memory\n");
- errorexit();
- }
- err = p;
- }
- err[nerr].seq = nerr;
- err[nerr].lineno = line;
- err[nerr].msg = fmtstrflush(&f);
- nerr++;
-}
-
-static int
-errcmp(const void *va, const void *vb)
-{
- Error *a, *b;
-
- a = (Error*)va;
- b = (Error*)vb;
- if(a->lineno != b->lineno)
- return a->lineno - b->lineno;
- if(a->seq != b->seq)
- return a->seq - b->seq;
- return strcmp(a->msg, b->msg);
-}
-
-void
-flusherrors(void)
-{
- int i;
-
- Bflush(&bstdout);
- if(nerr == 0)
- return;
- qsort(err, nerr, sizeof err[0], errcmp);
- for(i=0; i<nerr; i++)
- if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
- print("%s", err[i].msg);
- nerr = 0;
-}
-
-static void
-hcrash(void)
-{
- if(debug['h']) {
- flusherrors();
- if(outfile)
- remove(outfile);
- *(volatile int*)0 = 0;
- }
-}
-
-void
-yyerrorl(int line, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(line, fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nsavederrors+nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", line);
- errorexit();
- }
-}
-
-extern int yystate, yychar;
-
-void
-yyerror(char *fmt, ...)
-{
- int i;
- static int lastsyntax;
- va_list arg;
- char buf[512], *p;
-
- if(strncmp(fmt, "syntax error", 12) == 0) {
- nsyntaxerrors++;
-
- if(debug['x'])
- print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
-
- // An unexpected EOF caused a syntax error. Use the previous
- // line number since getc generated a fake newline character.
- if(curio.eofnl)
- lexlineno = prevlineno;
-
- // only one syntax error per line
- if(lastsyntax == lexlineno)
- return;
- lastsyntax = lexlineno;
-
- if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) {
- // The grammar has { and LBRACE but both show up as {.
- // Rewrite syntax error referring to "{ or {" to say just "{".
- strecpy(buf, buf+sizeof buf, fmt);
- p = strstr(buf, "{ or {");
- if(p)
- memmove(p+1, p+6, strlen(p+6)+1);
-
- // The grammar has ? and @ but only for reading imports.
- // Silence them in ordinary errors.
- p = strstr(buf, " or ?");
- if(p)
- memmove(p, p+5, strlen(p+5)+1);
- p = strstr(buf, " or @");
- if(p)
- memmove(p, p+5, strlen(p+5)+1);
- fmt = buf;
- }
-
- // look for parse state-specific errors in list (see go.errors).
- for(i=0; i<nelem(yymsg); i++) {
- if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
- yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
- return;
- }
- }
-
- // plain "syntax error" gets "near foo" added
- if(strcmp(fmt, "syntax error") == 0) {
- yyerrorl(lexlineno, "syntax error near %s", lexbuf);
- return;
- }
-
- // if bison says "syntax error, more info"; print "syntax error: more info".
- if(fmt[12] == ',') {
- yyerrorl(lexlineno, "syntax error:%s", fmt+13);
- return;
- }
-
- yyerrorl(lexlineno, "%s", fmt);
- return;
- }
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nsavederrors+nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", parserline());
- errorexit();
- }
-}
-
-void
-warn(char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
-}
-
-void
-warnl(int line, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(line, fmt, arg);
- va_end(arg);
- if(debug['m'])
- flusherrors();
-}
-
-void
-fatal(char *fmt, ...)
-{
- va_list arg;
-
- flusherrors();
-
- print("%L: internal compiler error: ", lineno);
- va_start(arg, fmt);
- vfprint(1, fmt, arg);
- va_end(arg);
- print("\n");
-
- // If this is a released compiler version, ask for a bug report.
- if(strncmp(getgoversion(), "release", 7) == 0) {
- print("\n");
- print("Please file a bug report including a short program that triggers the error.\n");
- print("https://golang.org/issue/new\n");
- }
- hcrash();
- errorexit();
-}
-
-void
-linehist(char *file, int32 off, int relative)
-{
- if(debug['i']) {
- if(file != nil) {
- if(off < 0)
- print("pragma %s", file);
- else
- if(off > 0)
- print("line %s", file);
- else
- print("import %s", file);
- } else
- print("end of import");
- print(" at line %L\n", lexlineno);
- }
-
- if(off < 0 && file[0] != '/' && !relative)
- file = smprint("%s/%s", ctxt->pathname, file);
- linklinehist(ctxt, lexlineno, file, off);
-}
-
-int32
-setlineno(Node *n)
-{
- int32 lno;
-
- lno = lineno;
- if(n != N)
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- break;
- default:
- lineno = n->lineno;
- if(lineno == 0) {
- if(debug['K'])
- warn("setlineno: line 0");
- lineno = lno;
- }
- }
- return lno;
-}
-
-uint32
-stringhash(char *p)
-{
- uint32 h;
- int c;
-
- h = 0;
- for(;;) {
- c = *p++;
- if(c == 0)
- break;
- h = h*PRIME1 + c;
- }
-
- if((int32)h < 0) {
- h = -h;
- if((int32)h < 0)
- h = 0;
- }
- return h;
-}
-
-Sym*
-lookup(char *name)
-{
- return pkglookup(name, localpkg);
-}
-
-Sym*
-pkglookup(char *name, Pkg *pkg)
-{
- Sym *s;
- uint32 h;
- int c;
-
- h = stringhash(name) % NHASH;
- c = name[0];
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != c || s->pkg != pkg)
- continue;
- if(strcmp(s->name, name) == 0)
- return s;
- }
-
- s = mal(sizeof(*s));
- s->name = mal(strlen(name)+1);
- strcpy(s->name, name);
-
- s->pkg = pkg;
-
- s->link = hash[h];
- hash[h] = s;
- s->lexical = LNAME;
-
- return s;
-}
-
-Sym*
-restrictlookup(char *name, Pkg *pkg)
-{
- if(!exportname(name) && pkg != localpkg)
- yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
- return pkglookup(name, pkg);
-}
-
-
-// find all the exported symbols in package opkg
-// and make them available in the current package
-void
-importdot(Pkg *opkg, Node *pack)
-{
- Sym *s, *s1;
- uint32 h;
- int n;
- char *pkgerror;
-
- n = 0;
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->pkg != opkg)
- continue;
- if(s->def == N)
- continue;
- if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot
- continue;
- s1 = lookup(s->name);
- if(s1->def != N) {
- pkgerror = smprint("during import \"%Z\"", opkg->path);
- redeclare(s1, pkgerror);
- continue;
- }
- s1->def = s->def;
- s1->block = s->block;
- s1->def->pack = pack;
- s1->origpkg = opkg;
- n++;
- }
- }
- if(n == 0) {
- // can't possibly be used - there were no symbols
- yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path);
- }
-}
-
-static void
-gethunk(void)
-{
- char *h;
- int32 nh;
-
- nh = NHUNK;
- if(thunk >= 10L*NHUNK)
- nh = 10L*NHUNK;
- h = (char*)malloc(nh);
- if(h == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- hunk = h;
- nhunk = nh;
- thunk += nh;
-}
-
-void*
-mal(int32 n)
-{
- void *p;
-
- if(n >= NHUNK) {
- p = malloc(n);
- if(p == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- memset(p, 0, n);
- return p;
- }
-
- while((uintptr)hunk & MAXALIGN) {
- hunk++;
- nhunk--;
- }
- if(nhunk < n)
- gethunk();
-
- p = hunk;
- nhunk -= n;
- hunk += n;
- memset(p, 0, n);
- return p;
-}
-
-void*
-remal(void *p, int32 on, int32 n)
-{
- void *q;
-
- q = (uchar*)p + on;
- if(q != hunk || nhunk < n) {
- if(on+n >= NHUNK) {
- q = mal(on+n);
- memmove(q, p, on);
- return q;
- }
- if(nhunk < on+n)
- gethunk();
- memmove(hunk, p, on);
- p = hunk;
- hunk += on;
- nhunk -= on;
- }
- hunk += n;
- nhunk -= n;
- return p;
-}
-
-Node*
-nod(int op, Node *nleft, Node *nright)
-{
- Node *n;
-
- n = mal(sizeof(*n));
- n->op = op;
- n->left = nleft;
- n->right = nright;
- n->lineno = parserline();
- n->xoffset = BADWIDTH;
- n->orig = n;
- n->curfn = curfn;
- return n;
-}
-
-void
-saveorignode(Node *n)
-{
- Node *norig;
-
- if(n->orig != N)
- return;
- norig = nod(n->op, N, N);
- *norig = *n;
- n->orig = norig;
-}
-
-// ispaddedfield reports whether the given field
-// is followed by padding. For the case where t is
-// the last field, total gives the size of the enclosing struct.
-static int
-ispaddedfield(Type *t, vlong total)
-{
- if(t->etype != TFIELD)
- fatal("ispaddedfield called non-field %T", t);
- if(t->down == T)
- return t->width + t->type->width != total;
- return t->width + t->type->width != t->down->width;
-}
-
-int
-algtype1(Type *t, Type **bad)
-{
- int a, ret;
- Type *t1;
-
- if(bad)
- *bad = T;
- if(t->broke)
- return AMEM;
- if(t->noalg)
- return ANOEQ;
-
- switch(t->etype) {
- case TANY:
- case TFORW:
- // will be defined later.
- *bad = t;
- return -1;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TUNSAFEPTR:
- return AMEM;
-
- case TFUNC:
- case TMAP:
- if(bad)
- *bad = t;
- return ANOEQ;
-
- case TFLOAT32:
- return AFLOAT32;
-
- case TFLOAT64:
- return AFLOAT64;
-
- case TCOMPLEX64:
- return ACPLX64;
-
- case TCOMPLEX128:
- return ACPLX128;
-
- case TSTRING:
- return ASTRING;
-
- case TINTER:
- if(isnilinter(t))
- return ANILINTER;
- return AINTER;
-
- case TARRAY:
- if(isslice(t)) {
- if(bad)
- *bad = t;
- return ANOEQ;
- }
- a = algtype1(t->type, bad);
- if(a == ANOEQ || a == AMEM) {
- if(a == ANOEQ && bad)
- *bad = t;
- return a;
- }
- return -1; // needs special compare
-
- case TSTRUCT:
- if(t->type != T && t->type->down == T && !isblanksym(t->type->sym)) {
- // One-field struct is same as that one field alone.
- return algtype1(t->type->type, bad);
- }
- ret = AMEM;
- for(t1=t->type; t1!=T; t1=t1->down) {
- // All fields must be comparable.
- a = algtype1(t1->type, bad);
- if(a == ANOEQ)
- return ANOEQ;
-
- // Blank fields, padded fields, fields with non-memory
- // equality need special compare.
- if(a != AMEM || isblanksym(t1->sym) || ispaddedfield(t1, t->width)) {
- ret = -1;
- continue;
- }
- }
- return ret;
- }
-
- fatal("algtype1: unexpected type %T", t);
- return 0;
-}
-
-int
-algtype(Type *t)
-{
- int a;
-
- a = algtype1(t, nil);
- if(a == AMEM || a == ANOEQ) {
- if(isslice(t))
- return ASLICE;
- switch(t->width) {
- case 0:
- return a + AMEM0 - AMEM;
- case 1:
- return a + AMEM8 - AMEM;
- case 2:
- return a + AMEM16 - AMEM;
- case 4:
- return a + AMEM32 - AMEM;
- case 8:
- return a + AMEM64 - AMEM;
- case 16:
- return a + AMEM128 - AMEM;
- }
- }
- return a;
-}
-
-Type*
-maptype(Type *key, Type *val)
-{
- Type *t;
- Type *bad;
- int atype, mtype;
-
- if(key != nil) {
- atype = algtype1(key, &bad);
- if(bad == T)
- mtype = key->etype;
- else
- mtype = bad->etype;
- switch(mtype) {
- default:
- if(atype == ANOEQ)
- yyerror("invalid map key type %T", key);
- break;
- case TANY:
- // will be resolved later.
- break;
- case TFORW:
- // map[key] used during definition of key.
- // postpone check until key is fully defined.
- // if there are multiple uses of map[key]
- // before key is fully defined, the error
- // will only be printed for the first one.
- // good enough.
- if(key->maplineno == 0)
- key->maplineno = lineno;
- break;
- }
- }
- t = typ(TMAP);
- t->down = key;
- t->type = val;
- return t;
-}
-
-Type*
-typ(int et)
-{
- Type *t;
-
- t = mal(sizeof(*t));
- t->etype = et;
- t->width = BADWIDTH;
- t->lineno = lineno;
- t->orig = t;
- return t;
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
- Type *a, *b;
- int k;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- if(a->sym == S && b->sym == S)
- return 0;
- if(a->sym == S)
- return -1;
- if(b->sym == S)
- return 1;
- k = strcmp(a->sym->name, b->sym->name);
- if(k != 0)
- return k;
- if(!exportname(a->sym->name)) {
- k = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
- if(k != 0)
- return k;
- }
- return 0;
-}
-
-Type*
-sortinter(Type *t)
-{
- Type *f;
- int i;
- Type **a;
-
- if(t->type == nil || t->type->down == nil)
- return t;
-
- i=0;
- for(f=t->type; f; f=f->down)
- i++;
- a = mal(i*sizeof f);
- i = 0;
- for(f=t->type; f; f=f->down)
- a[i++] = f;
- qsort(a, i, sizeof a[0], methcmp);
- while(i-- > 0) {
- a[i]->down = f;
- f = a[i];
- }
- t->type = f;
- return t;
-}
-
-Node*
-nodintconst(int64 v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.xval = mal(sizeof(*c->val.u.xval));
- mpmovecfix(c->val.u.xval, v);
- c->val.ctype = CTINT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-Node*
-nodfltconst(Mpflt* v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.fval = mal(sizeof(*c->val.u.fval));
- mpmovefltflt(c->val.u.fval, v);
- c->val.ctype = CTFLT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-void
-nodconst(Node *n, Type *t, int64 v)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(n->val.u.xval, v);
- n->val.ctype = CTINT;
- n->type = t;
-
- if(isfloat[t->etype])
- fatal("nodconst: bad type %T", t);
-}
-
-Node*
-nodnil(void)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTNIL;
- c->type = types[TNIL];
- return c;
-}
-
-Node*
-nodbool(int b)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTBOOL;
- c->val.u.bval = b;
- c->type = idealbool;
- return c;
-}
-
-Type*
-aindex(Node *b, Type *t)
-{
- Type *r;
- int64 bound;
-
- bound = -1; // open bound
- typecheck(&b, Erv);
- if(b != nil) {
- switch(consttype(b)) {
- default:
- yyerror("array bound must be an integer expression");
- break;
- case CTINT:
- case CTRUNE:
- bound = mpgetfix(b->val.u.xval);
- if(bound < 0)
- yyerror("array bound must be non negative");
- break;
- }
- }
-
- // fixed array
- r = typ(TARRAY);
- r->type = t;
- r->bound = bound;
- return r;
-}
-
-Node*
-treecopy(Node *n)
-{
- Node *m;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- default:
- m = nod(OXXX, N, N);
- *m = *n;
- m->orig = m;
- m->left = treecopy(n->left);
- m->right = treecopy(n->right);
- m->list = listtreecopy(n->list);
- if(m->defn)
- abort();
- break;
-
- case ONONAME:
- if(n->sym == lookup("iota")) {
- // Not sure yet whether this is the real iota,
- // but make a copy of the Node* just in case,
- // so that all the copies of this const definition
- // don't have the same iota value.
- m = nod(OXXX, N, N);
- *m = *n;
- m->iota = iota;
- break;
- }
- // fall through
- case ONAME:
- case OLITERAL:
- case OTYPE:
- m = n;
- break;
- }
- return m;
-}
-
-
-int
-isnil(Node *n)
-{
- if(n == N)
- return 0;
- if(n->op != OLITERAL)
- return 0;
- if(n->val.ctype != CTNIL)
- return 0;
- return 1;
-}
-
-int
-isptrto(Type *t, int et)
-{
- if(t == T)
- return 0;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t == T)
- return 0;
- if(t->etype != et)
- return 0;
- return 1;
-}
-
-int
-istype(Type *t, int et)
-{
- return t != T && t->etype == et;
-}
-
-int
-isfixedarray(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound >= 0;
-}
-
-int
-isslice(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound < 0;
-}
-
-int
-isblank(Node *n)
-{
- if(n == N)
- return 0;
- return isblanksym(n->sym);
-}
-
-int
-isblanksym(Sym *s)
-{
- char *p;
-
- if(s == S)
- return 0;
- p = s->name;
- if(p == nil)
- return 0;
- return p[0] == '_' && p[1] == '\0';
-}
-
-int
-isinter(Type *t)
-{
- return t != T && t->etype == TINTER;
-}
-
-int
-isnilinter(Type *t)
-{
- if(!isinter(t))
- return 0;
- if(t->type != T)
- return 0;
- return 1;
-}
-
-int
-isideal(Type *t)
-{
- if(t == T)
- return 0;
- if(t == idealstring || t == idealbool)
- return 1;
- switch(t->etype) {
- case TNIL:
- case TIDEAL:
- return 1;
- }
- return 0;
-}
-
-/*
- * given receiver of type t (t == r or t == *r)
- * return type to hang methods off (r).
- */
-Type*
-methtype(Type *t, int mustname)
-{
- if(t == T)
- return T;
-
- // strip away pointer if it's there
- if(isptr[t->etype]) {
- if(t->sym != S)
- return T;
- t = t->type;
- if(t == T)
- return T;
- }
-
- // need a type name
- if(t->sym == S && (mustname || t->etype != TSTRUCT))
- return T;
-
- // check types
- if(!issimple[t->etype])
- switch(t->etype) {
- default:
- return T;
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- case TCHAN:
- case TSTRING:
- case TFUNC:
- break;
- }
-
- return t;
-}
-
-int
-cplxsubtype(int et)
-{
- switch(et) {
- case TCOMPLEX64:
- return TFLOAT32;
- case TCOMPLEX128:
- return TFLOAT64;
- }
- fatal("cplxsubtype: %E\n", et);
- return 0;
-}
-
-static int
-eqnote(Strlit *a, Strlit *b)
-{
- if(a == b)
- return 1;
- if(a == nil || b == nil)
- return 0;
- if(a->len != b->len)
- return 0;
- return memcmp(a->s, b->s, a->len) == 0;
-}
-
-typedef struct TypePairList TypePairList;
-struct TypePairList
-{
- Type *t1;
- Type *t2;
- TypePairList *next;
-};
-
-static int
-onlist(TypePairList *l, Type *t1, Type *t2)
-{
- for(; l; l=l->next)
- if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
- return 1;
- return 0;
-}
-
-static int eqtype1(Type*, Type*, TypePairList*);
-
-// Return 1 if t1 and t2 are identical, following the spec rules.
-//
-// Any cyclic type must go through a named type, and if one is
-// named, it is only identical to the other if they are the same
-// pointer (t1 == t2), so there's no chance of chasing cycles
-// ad infinitum, so no need for a depth counter.
-int
-eqtype(Type *t1, Type *t2)
-{
- return eqtype1(t1, t2, nil);
-}
-
-static int
-eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
-{
- TypePairList l;
-
- if(t1 == t2)
- return 1;
- if(t1 == T || t2 == T || t1->etype != t2->etype)
- return 0;
- if(t1->sym || t2->sym) {
- // Special case: we keep byte and uint8 separate
- // for error messages. Treat them as equal.
- switch(t1->etype) {
- case TUINT8:
- if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
- return 1;
- break;
- case TINT:
- case TINT32:
- if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
- return 1;
- break;
- }
- return 0;
- }
-
- if(onlist(assumed_equal, t1, t2))
- return 1;
- l.next = assumed_equal;
- l.t1 = t1;
- l.t2 = t2;
-
- switch(t1->etype) {
- case TINTER:
- case TSTRUCT:
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- if(t1->etype != TFIELD || t2->etype != TFIELD)
- fatal("struct/interface missing field: %T %T", t1, t2);
- if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
- goto no;
- }
- if(t1 == T && t2 == T)
- goto yes;
- goto no;
-
- case TFUNC:
- // Loop over structs: receiver, in, out.
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- Type *ta, *tb;
-
- if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- fatal("func missing struct: %T %T", t1, t2);
-
- // Loop over fields in structs, ignoring argument names.
- for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
- if(ta->etype != TFIELD || tb->etype != TFIELD)
- fatal("func struct missing field: %T %T", ta, tb);
- if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
- goto no;
- }
- if(ta != T || tb != T)
- goto no;
- }
- if(t1 == T && t2 == T)
- goto yes;
- goto no;
-
- case TARRAY:
- if(t1->bound != t2->bound)
- goto no;
- break;
-
- case TCHAN:
- if(t1->chan != t2->chan)
- goto no;
- break;
- }
-
- if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
- goto yes;
- goto no;
-
-yes:
- return 1;
-
-no:
- return 0;
-}
-
-// Are t1 and t2 equal struct types when field names are ignored?
-// For deciding whether the result struct from g can be copied
-// directly when compiling f(g()).
-int
-eqtypenoname(Type *t1, Type *t2)
-{
- if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- return 0;
-
- t1 = t1->type;
- t2 = t2->type;
- for(;;) {
- if(!eqtype(t1, t2))
- return 0;
- if(t1 == T)
- return 1;
- t1 = t1->down;
- t2 = t2->down;
- }
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return 0.
-int
-assignop(Type *src, Type *dst, char **why)
-{
- Type *missing, *have;
- int ptr;
-
- if(why != nil)
- *why = "";
-
- // TODO(rsc,lvd): This behaves poorly in the presence of inlining.
- // https://golang.org/issue/2795
- if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
- yyerror("cannot use unsafe.Pointer");
- errorexit();
- }
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
- return 0;
-
- // 1. src type is identical to dst.
- if(eqtype(src, dst))
- return OCONVNOP;
-
- // 2. src and dst have identical underlying types
- // and either src or dst is not a named type or
- // both are empty interface types.
- // For assignable but different non-empty interface types,
- // we want to recompute the itab.
- if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src)))
- return OCONVNOP;
-
- // 3. dst is an interface type and src implements dst.
- if(dst->etype == TINTER && src->etype != TNIL) {
- if(implements(src, dst, &missing, &have, &ptr))
- return OCONVIFACE;
-
- // we'll have complained about this method anyway, suppress spurious messages.
- if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
- return OCONVIFACE;
-
- if(why != nil) {
- if(isptrto(src, TINTER))
- *why = smprint(":\n\t%T is pointer to interface, not interface", src);
- else if(have && have->sym == missing->sym && have->nointerface)
- *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')",
- src, dst, missing->sym);
- else if(have && have->sym == missing->sym)
- *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else if(ptr)
- *why = smprint(":\n\t%T does not implement %T (%S method has pointer receiver)",
- src, dst, missing->sym);
- else if(have)
- *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else
- *why = smprint(":\n\t%T does not implement %T (missing %S method)",
- src, dst, missing->sym);
- }
- return 0;
- }
- if(isptrto(dst, TINTER)) {
- if(why != nil)
- *why = smprint(":\n\t%T is pointer to interface, not interface", dst);
- return 0;
- }
- if(src->etype == TINTER && dst->etype != TBLANK) {
- if(why != nil && implements(dst, src, &missing, &have, &ptr))
- *why = ": need type assertion";
- return 0;
- }
-
- // 4. src is a bidirectional channel value, dst is a channel type,
- // src and dst have identical element types, and
- // either src or dst is not a named type.
- if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
- if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
- return OCONVNOP;
-
- // 5. src is the predeclared identifier nil and dst is a nillable type.
- if(src->etype == TNIL) {
- switch(dst->etype) {
- case TARRAY:
- if(dst->bound != -100) // not slice
- break;
- case TPTR32:
- case TPTR64:
- case TFUNC:
- case TMAP:
- case TCHAN:
- case TINTER:
- return OCONVNOP;
- }
- }
-
- // 6. rule about untyped constants - already converted by defaultlit.
-
- // 7. Any typed value can be assigned to the blank identifier.
- if(dst->etype == TBLANK)
- return OCONVNOP;
-
- return 0;
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return 0.
-int
-convertop(Type *src, Type *dst, char **why)
-{
- int op;
-
- if(why != nil)
- *why = "";
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T)
- return 0;
-
- // 1. src can be assigned to dst.
- if((op = assignop(src, dst, why)) != 0)
- return op;
-
- // The rules for interfaces are no different in conversions
- // than assignments. If interfaces are involved, stop now
- // with the good message from assignop.
- // Otherwise clear the error.
- if(src->etype == TINTER || dst->etype == TINTER)
- return 0;
- if(why != nil)
- *why = "";
-
- // 2. src and dst have identical underlying types.
- if(eqtype(src->orig, dst->orig))
- return OCONVNOP;
-
- // 3. src and dst are unnamed pointer types
- // and their base types have identical underlying types.
- if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
- if(eqtype(src->type->orig, dst->type->orig))
- return OCONVNOP;
-
- // 4. src and dst are both integer or floating point types.
- if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 5. src and dst are both complex types.
- if(iscomplex[src->etype] && iscomplex[dst->etype]) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 6. src is an integer or has type []byte or []rune
- // and dst is a string type.
- if(isint[src->etype] && dst->etype == TSTRING)
- return ORUNESTR;
-
- if(isslice(src) && dst->etype == TSTRING) {
- if(src->type->etype == bytetype->etype)
- return OARRAYBYTESTR;
- if(src->type->etype == runetype->etype)
- return OARRAYRUNESTR;
- }
-
- // 7. src is a string and dst is []byte or []rune.
- // String to slice.
- if(src->etype == TSTRING && isslice(dst)) {
- if(dst->type->etype == bytetype->etype)
- return OSTRARRAYBYTE;
- if(dst->type->etype == runetype->etype)
- return OSTRARRAYRUNE;
- }
-
- // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
- if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
- return OCONVNOP;
-
- // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
- if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
- return OCONVNOP;
-
- return 0;
-}
-
-// Convert node n for assignment to type t.
-Node*
-assignconv(Node *n, Type *t, char *context)
-{
- int op;
- Node *r, *old;
- char *why;
-
- if(n == N || n->type == T || n->type->broke)
- return n;
-
- if(t->etype == TBLANK && n->type->etype == TNIL)
- yyerror("use of untyped nil");
-
- old = n;
- old->diag++; // silence errors about n; we'll issue one below
- defaultlit(&n, t);
- old->diag--;
- if(t->etype == TBLANK)
- return n;
-
- // Convert ideal bool from comparison to plain bool
- // if the next step is non-bool (like interface{}).
- if(n->type == idealbool && t->etype != TBOOL) {
- if(n->op == ONAME || n->op == OLITERAL) {
- r = nod(OCONVNOP, n, N);
- r->type = types[TBOOL];
- r->typecheck = 1;
- r->implicit = 1;
- n = r;
- }
- }
-
- if(eqtype(n->type, t))
- return n;
-
- op = assignop(n->type, t, &why);
- if(op == 0) {
- yyerror("cannot use %lN as type %T in %s%s", n, t, context, why);
- op = OCONV;
- }
-
- r = nod(op, n, N);
- r->type = t;
- r->typecheck = 1;
- r->implicit = 1;
- r->orig = n->orig;
- return r;
-}
-
-static int
-subtype(Type **stp, Type *t, int d)
-{
- Type *st;
-
-loop:
- st = *stp;
- if(st == T)
- return 0;
-
- d++;
- if(d >= 10)
- return 0;
-
- switch(st->etype) {
- default:
- return 0;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- stp = &st->type;
- goto loop;
-
- case TANY:
- if(!st->copyany)
- return 0;
- *stp = t;
- break;
-
- case TMAP:
- if(subtype(&st->down, t, d))
- break;
- stp = &st->type;
- goto loop;
-
- case TFUNC:
- for(;;) {
- if(subtype(&st->type, t, d))
- break;
- if(subtype(&st->type->down->down, t, d))
- break;
- if(subtype(&st->type->down, t, d))
- break;
- return 0;
- }
- break;
-
- case TSTRUCT:
- for(st=st->type; st!=T; st=st->down)
- if(subtype(&st->type, t, d))
- return 1;
- return 0;
- }
- return 1;
-}
-
-/*
- * Is this a 64-bit type?
- */
-int
-is64(Type *t)
-{
- if(t == T)
- return 0;
- switch(simtype[t->etype]) {
- case TINT64:
- case TUINT64:
- case TPTR64:
- return 1;
- }
- return 0;
-}
-
-/*
- * Is a conversion between t1 and t2 a no-op?
- */
-int
-noconv(Type *t1, Type *t2)
-{
- int e1, e2;
-
- e1 = simtype[t1->etype];
- e2 = simtype[t2->etype];
-
- switch(e1) {
- case TINT8:
- case TUINT8:
- return e2 == TINT8 || e2 == TUINT8;
-
- case TINT16:
- case TUINT16:
- return e2 == TINT16 || e2 == TUINT16;
-
- case TINT32:
- case TUINT32:
- case TPTR32:
- return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
-
- case TFLOAT32:
- return e2 == TFLOAT32;
-
- case TFLOAT64:
- return e2 == TFLOAT64;
- }
- return 0;
-}
-
-void
-argtype(Node *on, Type *t)
-{
- dowidth(t);
- if(!subtype(&on->type, t, 0))
- fatal("argtype: failed %N %T\n", on, t);
-}
-
-Type*
-shallow(Type *t)
-{
- Type *nt;
-
- if(t == T)
- return T;
- nt = typ(0);
- *nt = *t;
- if(t->orig == t)
- nt->orig = nt;
- return nt;
-}
-
-static Type*
-deep(Type *t)
-{
- Type *nt, *xt;
-
- if(t == T)
- return T;
-
- switch(t->etype) {
- default:
- nt = t; // share from here down
- break;
-
- case TANY:
- nt = shallow(t);
- nt->copyany = 1;
- break;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- nt = shallow(t);
- nt->type = deep(t->type);
- break;
-
- case TMAP:
- nt = shallow(t);
- nt->down = deep(t->down);
- nt->type = deep(t->type);
- break;
-
- case TFUNC:
- nt = shallow(t);
- nt->type = deep(t->type);
- nt->type->down = deep(t->type->down);
- nt->type->down->down = deep(t->type->down->down);
- break;
-
- case TSTRUCT:
- nt = shallow(t);
- nt->type = shallow(t->type);
- xt = nt->type;
-
- for(t=t->type; t!=T; t=t->down) {
- xt->type = deep(t->type);
- xt->down = shallow(t->down);
- xt = xt->down;
- }
- break;
- }
- return nt;
-}
-
-Node*
-syslook(char *name, int copy)
-{
- Sym *s;
- Node *n;
-
- s = pkglookup(name, runtimepkg);
- if(s == S || s->def == N)
- fatal("syslook: can't find runtime.%s", name);
-
- if(!copy)
- return s->def;
-
- n = nod(0, N, N);
- *n = *s->def;
- n->type = deep(s->def->type);
-
- return n;
-}
-
-/*
- * compute a hash value for type t.
- * if t is a method type, ignore the receiver
- * so that the hash can be used in interface checks.
- * %T already contains
- * all the necessary logic to generate a representation
- * of the type that completely describes it.
- * using smprint here avoids duplicating that code.
- * using md5 here is overkill, but i got tired of
- * accidental collisions making the runtime think
- * two types are equal when they really aren't.
- */
-uint32
-typehash(Type *t)
-{
- char *p;
- MD5 d;
-
- if(t->thistuple) {
- // hide method receiver from Tpretty
- t->thistuple = 0;
- p = smprint("%-uT", t);
- t->thistuple = 1;
- } else
- p = smprint("%-uT", t);
- //print("typehash: %s\n", p);
- md5reset(&d);
- md5write(&d, (uchar*)p, strlen(p));
- free(p);
- return md5sum(&d, nil);
-}
-
-Type*
-ptrto(Type *t)
-{
- Type *t1;
-
- if(tptr == 0)
- fatal("ptrto: no tptr");
- t1 = typ(tptr);
- t1->type = t;
- t1->width = widthptr;
- t1->align = widthptr;
- return t1;
-}
-
-void
-frame(int context)
-{
- NodeList *l;
- Node *n;
- vlong w;
-
- if(context) {
- print("--- external frame ---\n");
- l = externdcl;
- } else if(curfn) {
- print("--- %S frame ---\n", curfn->nname->sym);
- l = curfn->dcl;
- } else
- return;
-
- for(; l; l=l->next) {
- n = l->n;
- w = -1;
- if(n->type)
- w = n->type->width;
- switch(n->op) {
- case ONAME:
- print("%O %S G%d %T width=%lld\n", n->op, n->sym, n->vargen, n->type, w);
- break;
-
- case OTYPE:
- print("%O %T width=%lld\n", n->op, n->type, w);
- break;
- }
- }
-}
-
-/*
- * calculate sethi/ullman number
- * roughly how many registers needed to
- * compile a node. used to compile the
- * hardest side first to minimize registers.
- */
-void
-ullmancalc(Node *n)
-{
- int ul, ur;
-
- if(n == N)
- return;
-
- if(n->ninit != nil) {
- ul = UINF;
- goto out;
- }
-
- switch(n->op) {
- case OREGISTER:
- case OLITERAL:
- case ONAME:
- ul = 1;
- if(n->class == PPARAMREF || (n->class & PHEAP))
- ul++;
- goto out;
- case OCALL:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- ul = UINF;
- goto out;
- case OANDAND:
- case OOROR:
- // hard with race detector
- if(flag_race) {
- ul = UINF;
- goto out;
- }
- }
- ul = 1;
- if(n->left != N)
- ul = n->left->ullman;
- ur = 1;
- if(n->right != N)
- ur = n->right->ullman;
- if(ul == ur)
- ul += 1;
- if(ur > ul)
- ul = ur;
-
-out:
- if(ul > 200)
- ul = 200; // clamp to uchar with room to grow
- n->ullman = ul;
-}
-
-void
-badtype(int o, Type *tl, Type *tr)
-{
- Fmt fmt;
- char *s;
-
- fmtstrinit(&fmt);
- if(tl != T)
- fmtprint(&fmt, "\n %T", tl);
- if(tr != T)
- fmtprint(&fmt, "\n %T", tr);
-
- // common mistake: *struct and *interface.
- if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
- if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
- fmtprint(&fmt, "\n (*struct vs *interface)");
- else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
- fmtprint(&fmt, "\n (*interface vs *struct)");
- }
- s = fmtstrflush(&fmt);
- yyerror("illegal types for operand: %O%s", o, s);
-}
-
-/*
- * iterator to walk a structure declaration
- */
-Type*
-structfirst(Iter *s, Type **nn)
-{
- Type *n, *t;
-
- n = *nn;
- if(n == T)
- goto bad;
-
- switch(n->etype) {
- default:
- goto bad;
-
- case TSTRUCT:
- case TINTER:
- case TFUNC:
- break;
- }
-
- t = n->type;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- fatal("structfirst: not field %T", t);
-
- s->t = t;
- return t;
-
-bad:
- fatal("structfirst: not struct %T", n);
-
-rnil:
- return T;
-}
-
-Type*
-structnext(Iter *s)
-{
- Type *n, *t;
-
- n = s->t;
- t = n->down;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- goto bad;
-
- s->t = t;
- return t;
-
-bad:
- fatal("structnext: not struct %T", n);
-
-rnil:
- return T;
-}
-
-/*
- * iterator to this and inargs in a function
- */
-Type*
-funcfirst(Iter *s, Type *t)
-{
- Type *fp;
-
- if(t == T)
- goto bad;
-
- if(t->etype != TFUNC)
- goto bad;
-
- s->tfunc = t;
- s->done = 0;
- fp = structfirst(s, getthis(t));
- if(fp == T) {
- s->done = 1;
- fp = structfirst(s, getinarg(t));
- }
- return fp;
-
-bad:
- fatal("funcfirst: not func %T", t);
- return T;
-}
-
-Type*
-funcnext(Iter *s)
-{
- Type *fp;
-
- fp = structnext(s);
- if(fp == T && !s->done) {
- s->done = 1;
- fp = structfirst(s, getinarg(s->tfunc));
- }
- return fp;
-}
-
-Type**
-getthis(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getthis: not a func %T", t);
- return &t->type;
-}
-
-Type**
-getoutarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getoutarg: not a func %T", t);
- return &t->type->down;
-}
-
-Type**
-getinarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getinarg: not a func %T", t);
- return &t->type->down->down;
-}
-
-Type*
-getthisx(Type *t)
-{
- return *getthis(t);
-}
-
-Type*
-getoutargx(Type *t)
-{
- return *getoutarg(t);
-}
-
-Type*
-getinargx(Type *t)
-{
- return *getinarg(t);
-}
-
-/*
- * return !(op)
- * eg == <=> !=
- */
-int
-brcom(int a)
-{
- switch(a) {
- case OEQ: return ONE;
- case ONE: return OEQ;
- case OLT: return OGE;
- case OGT: return OLE;
- case OLE: return OGT;
- case OGE: return OLT;
- }
- fatal("brcom: no com for %O\n", a);
- return a;
-}
-
-/*
- * return reverse(op)
- * eg a op b <=> b r(op) a
- */
-int
-brrev(int a)
-{
- switch(a) {
- case OEQ: return OEQ;
- case ONE: return ONE;
- case OLT: return OGT;
- case OGT: return OLT;
- case OLE: return OGE;
- case OGE: return OLE;
- }
- fatal("brcom: no rev for %O\n", a);
- return a;
-}
-
-/*
- * return side effect-free n, appending side effects to init.
- * result is assignable if n is.
- */
-Node*
-safeexpr(Node *n, NodeList **init)
-{
- Node *l;
- Node *r;
- Node *a;
-
- if(n == N)
- return N;
-
- if(n->ninit) {
- walkstmtlist(n->ninit);
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- }
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
-
- case ODOT:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- r = nod(OXXX, N, N);
- *r = *n;
- r->left = l;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- return r;
-
- case ODOTPTR:
- case OIND:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- walkexpr(&a, init);
- return a;
-
- case OINDEX:
- case OINDEXMAP:
- l = safeexpr(n->left, init);
- r = safeexpr(n->right, init);
- if(l == n->left && r == n->right)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- a->right = r;
- walkexpr(&a, init);
- return a;
- }
-
- // make a copy; must not be used as an lvalue
- if(islvalue(n))
- fatal("missing lvalue case in safeexpr: %N", n);
- return cheapexpr(n, init);
-}
-
-Node*
-copyexpr(Node *n, Type *t, NodeList **init)
-{
- Node *a, *l;
-
- l = temp(t);
- a = nod(OAS, l, n);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- return l;
-}
-
-/*
- * return side-effect free and cheap n, appending side effects to init.
- * result may not be assignable.
- */
-Node*
-cheapexpr(Node *n, NodeList **init)
-{
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
- }
-
- return copyexpr(n, n->type, init);
-}
-
-/*
- * return n in a local variable of type t if it is not already.
- * the value is guaranteed not to change except by direct
- * assignment to it.
- */
-Node*
-localexpr(Node *n, Type *t, NodeList **init)
-{
- if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) &&
- (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
- convertop(n->type, t, nil) == OCONVNOP)
- return n;
-
- return copyexpr(n, t, init);
-}
-
-void
-setmaxarg(Type *t, int32 extra)
-{
- int64 w;
-
- dowidth(t);
- w = t->argwid;
- if(w >= thearch.MAXWIDTH)
- fatal("bad argwid %T", t);
- w += extra;
- if(w >= thearch.MAXWIDTH)
- fatal("bad argwid %d + %T", extra, t);
- if(w > maxarg)
- maxarg = w;
-}
-
-/*
- * unicode-aware case-insensitive strcmp
- */
-
-static int
-ucistrcmp(char *p, char *q)
-{
- Rune rp, rq;
-
- while(*p || *q) {
- if(*p == 0)
- return +1;
- if(*q == 0)
- return -1;
- p += chartorune(&rp, p);
- q += chartorune(&rq, q);
- rp = tolowerrune(rp);
- rq = tolowerrune(rq);
- if(rp < rq)
- return -1;
- if(rp > rq)
- return +1;
- }
- return 0;
-}
-
-/*
- * code to resolve elided DOTs
- * in embedded types
- */
-
-// search depth 0 --
-// return count of fields+methods
-// found with a given name
-static int
-lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c;
-
- u = t;
- if(isptr[u->etype])
- u = u->type;
-
- c = 0;
- if(u->etype == TSTRUCT || u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down)
- if(f->sym == s || (ignorecase && f->type->etype == TFUNC && f->type->thistuple > 0 && ucistrcmp(f->sym->name, s->name) == 0)) {
- if(save)
- *save = f;
- c++;
- }
- }
- u = methtype(t, 0);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down)
- if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
- if(save)
- *save = f;
- c++;
- }
- }
- return c;
-}
-
-// search depth d for field/method s --
-// return count of fields+methods
-// found at search depth.
-// answer is in dotlist array and
-// count of number of ways is returned.
-int
-adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c, a;
-
- if(t->trecur)
- return 0;
- t->trecur = 1;
-
- if(d == 0) {
- c = lookdot0(s, t, save, ignorecase);
- goto out;
- }
-
- c = 0;
- u = t;
- if(isptr[u->etype])
- u = u->type;
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- d--;
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- a = adddot1(s, f->type, d, save, ignorecase);
- if(a != 0 && c == 0)
- dotlist[d].field = f;
- c += a;
- }
-
-out:
- t->trecur = 0;
- return c;
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-Node*
-adddot(Node *n)
-{
- Type *t;
- Sym *s;
- int c, d;
-
- typecheck(&n->left, Etype|Erv);
- n->diag |= n->left->diag;
- t = n->left->type;
- if(t == T)
- goto ret;
-
- if(n->left->op == OTYPE)
- goto ret;
-
- if(n->right->op != ONAME)
- goto ret;
- s = n->right->sym;
- if(s == S)
- goto ret;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, nil, 0);
- if(c > 0)
- goto out;
- }
- goto ret;
-
-out:
- if(c > 1) {
- yyerror("ambiguous selector %N", n);
- n->left = N;
- return n;
- }
-
- // rebuild elided dots
- for(c=d-1; c>=0; c--)
- n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
-ret:
- return n;
-}
-
-
-/*
- * code to help generate trampoline
- * functions for methods on embedded
- * subtypes.
- * these are approx the same as
- * the corresponding adddot routines
- * except that they expect to be called
- * with unique tasks and they return
- * the actual methods.
- */
-
-typedef struct Symlink Symlink;
-struct Symlink
-{
- Type* field;
- uchar good;
- uchar followptr;
- Symlink* link;
-};
-static Symlink* slist;
-
-static void
-expand0(Type *t, int followptr)
-{
- Type *f, *u;
- Symlink *sl;
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
-
- if(u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down) {
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- return;
- }
-
- u = methtype(t, 0);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down) {
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- }
-}
-
-static void
-expand1(Type *t, int d, int followptr)
-{
- Type *f, *u;
-
- if(t->trecur)
- return;
- if(d == 0)
- return;
- t->trecur = 1;
-
- if(d != nelem(dotlist)-1)
- expand0(t, followptr);
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- expand1(f->type, d-1, followptr);
- }
-
-out:
- t->trecur = 0;
-}
-
-void
-expandmeth(Type *t)
-{
- Symlink *sl;
- Type *f;
- int c, d;
-
- if(t == T || t->xmethod != nil)
- return;
-
- // mark top-level method symbols
- // so that expand1 doesn't consider them.
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags |= SymUniq;
-
- // generate all reachable methods
- slist = nil;
- expand1(t, nelem(dotlist)-1, 0);
-
- // check each method to be uniquely reachable
- for(sl=slist; sl!=nil; sl=sl->link) {
- sl->field->sym->flags &= ~SymUniq;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(sl->field->sym, t, d, &f, 0);
- if(c == 0)
- continue;
- if(c == 1) {
- // addot1 may have dug out arbitrary fields, we only want methods.
- if(f->type->etype == TFUNC && f->type->thistuple > 0) {
- sl->good = 1;
- sl->field = f;
- }
- }
- break;
- }
- }
-
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags &= ~SymUniq;
-
- t->xmethod = t->method;
- for(sl=slist; sl!=nil; sl=sl->link) {
- if(sl->good) {
- // add it to the base type method list
- f = typ(TFIELD);
- *f = *sl->field;
- f->embedded = 1; // needs a trampoline
- if(sl->followptr)
- f->embedded = 2;
- f->down = t->xmethod;
- t->xmethod = f;
- }
- }
-}
-
-/*
- * Given funarg struct list, return list of ODCLFIELD Node fn args.
- */
-static NodeList*
-structargs(Type **tl, int mustname)
-{
- Iter savet;
- Node *a, *n;
- NodeList *args;
- Type *t;
- char buf[100];
- int gen;
-
- args = nil;
- gen = 0;
- for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
- n = N;
- if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) {
- // invent a name so that we can refer to it in the trampoline
- snprint(buf, sizeof buf, ".anon%d", gen++);
- n = newname(lookup(buf));
- } else if(t->sym)
- n = newname(t->sym);
- a = nod(ODCLFIELD, n, typenod(t->type));
- a->isddd = t->isddd;
- if(n != N)
- n->isddd = t->isddd;
- args = list(args, a);
- }
- return args;
-}
-
-/*
- * Generate a wrapper function to convert from
- * a receiver of type T to a receiver of type U.
- * That is,
- *
- * func (t T) M() {
- * ...
- * }
- *
- * already exists; this function generates
- *
- * func (u U) M() {
- * u.M()
- * }
- *
- * where the types T and U are such that u.M() is valid
- * and calls the T.M method.
- * The resulting function is for use in method tables.
- *
- * rcvr - U
- * method - M func (t T)(), a TFIELD type struct
- * newnam - the eventual mangled name of this function
- */
-void
-genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- Node *this, *fn, *call, *n, *t, *pad, *dot, *as;
- NodeList *l, *args, *in, *out;
- Type *tpad, *methodrcvr;
- int isddd;
- Val v;
- static int linehistdone = 0;
-
- if(0 && debug['r'])
- print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
- rcvr, method, newnam);
-
- lexlineno++;
- lineno = lexlineno;
- if (linehistdone == 0) {
- // All the wrappers can share the same linehist entry.
- linehist("<autogenerated>", 0, 0);
- linehistdone = 1;
- }
-
- dclcontext = PEXTERN;
- markdcl();
-
- this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
- this->left->ntype = this->right;
- in = structargs(getinarg(method->type), 1);
- out = structargs(getoutarg(method->type), 0);
-
- t = nod(OTFUNC, N, N);
- l = list1(this);
- if(iface && rcvr->width < types[tptr]->width) {
- // Building method for interface table and receiver
- // is smaller than the single pointer-sized word
- // that the interface call will pass in.
- // Add a dummy padding argument after the
- // receiver to make up the difference.
- tpad = typ(TARRAY);
- tpad->type = types[TUINT8];
- tpad->bound = types[tptr]->width - rcvr->width;
- pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
- l = list(l, pad);
- }
- t->list = concat(l, in);
- t->rlist = out;
-
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(newnam);
- fn->nname->defn = fn;
- fn->nname->ntype = t;
- declare(fn->nname, PFUNC);
- funchdr(fn);
-
- // arg list
- args = nil;
- isddd = 0;
- for(l=in; l; l=l->next) {
- args = list(args, l->n->left);
- isddd = l->n->left->isddd;
- }
-
- methodrcvr = getthisx(method->type)->type->type;
-
- // generate nil pointer check for better error
- if(isptr[rcvr->etype] && rcvr->type == methodrcvr) {
- // generating wrapper from *T to T.
- n = nod(OIF, N, N);
- n->ntest = nod(OEQ, this->left, nodnil());
- // these strings are already in the reflect tables,
- // so no space cost to use them here.
- l = nil;
- v.ctype = CTSTR;
- v.u.sval = newstrlit(rcvr->type->sym->pkg->name); // package name
- l = list(l, nodlit(v));
- v.u.sval = newstrlit(rcvr->type->sym->name); // type name
- l = list(l, nodlit(v));
- v.u.sval = newstrlit(method->sym->name);
- l = list(l, nodlit(v)); // method name
- call = nod(OCALL, syslook("panicwrap", 0), N);
- call->list = l;
- n->nbody = list1(call);
- fn->nbody = list(fn->nbody, n);
- }
-
- dot = adddot(nod(OXDOT, this->left, newname(method->sym)));
-
- // generate call
- if(!flag_race && isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !isifacemethod(method->type)) {
- // generate tail call: adjust pointer receiver and jump to embedded method.
- dot = dot->left; // skip final .M
- if(!isptr[dotlist[0].field->type->etype])
- dot = nod(OADDR, dot, N);
- as = nod(OAS, this->left, nod(OCONVNOP, dot, N));
- as->right->type = rcvr;
- fn->nbody = list(fn->nbody, as);
- n = nod(ORETJMP, N, N);
- n->left = newname(methodsym(method->sym, methodrcvr, 0));
- fn->nbody = list(fn->nbody, n);
- } else {
- fn->wrapper = 1; // ignore frame for panic+recover matching
- call = nod(OCALL, dot, N);
- call->list = args;
- call->isddd = isddd;
- if(method->type->outtuple > 0) {
- n = nod(ORETURN, N, N);
- n->list = list1(call);
- call = n;
- }
- fn->nbody = list(fn->nbody, call);
- }
-
- if(0 && debug['r'])
- dumplist("genwrapper body", fn->nbody);
-
- funcbody(fn);
- curfn = fn;
- // wrappers where T is anonymous (struct or interface) can be duplicated.
- if(rcvr->etype == TSTRUCT ||
- rcvr->etype == TINTER ||
- isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
- fn->dupok = 1;
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
-
- // Set inl_nonlocal to whether we are calling a method on a
- // type defined in a different package. Checked in inlvar.
- if(!methodrcvr->local)
- inl_nonlocal = 1;
-
- inlcalls(fn);
-
- inl_nonlocal = 0;
-
- curfn = nil;
- funccompile(fn);
-}
-
-static Node*
-hashmem(Type *t)
-{
- Node *tfn, *n;
- Sym *sym;
-
- sym = pkglookup("memhash", runtimepkg);
-
- n = newname(sym);
- n->class = PFUNC;
- tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
- tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
- typecheck(&tfn, Etype);
- n->type = tfn->type;
- return n;
-}
-
-static Node*
-hashfor(Type *t)
-{
- int a;
- Sym *sym;
- Node *tfn, *n;
-
- a = algtype1(t, nil);
- switch(a) {
- case AMEM:
- fatal("hashfor with AMEM type");
- case AINTER:
- sym = pkglookup("interhash", runtimepkg);
- break;
- case ANILINTER:
- sym = pkglookup("nilinterhash", runtimepkg);
- break;
- case ASTRING:
- sym = pkglookup("strhash", runtimepkg);
- break;
- case AFLOAT32:
- sym = pkglookup("f32hash", runtimepkg);
- break;
- case AFLOAT64:
- sym = pkglookup("f64hash", runtimepkg);
- break;
- case ACPLX64:
- sym = pkglookup("c64hash", runtimepkg);
- break;
- case ACPLX128:
- sym = pkglookup("c128hash", runtimepkg);
- break;
- default:
- sym = typesymprefix(".hash", t);
- break;
- }
-
- n = newname(sym);
- n->class = PFUNC;
- tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
- tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
- typecheck(&tfn, Etype);
- n->type = tfn->type;
- return n;
-}
-
-/*
- * Generate a helper function to compute the hash of a value of type t.
- */
-void
-genhash(Sym *sym, Type *t)
-{
- Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r;
- Node *hashel;
- Type *first, *t1;
- int old_safemode;
- int64 size, mul, offend;
-
- if(debug['r'])
- print("genhash %S %T\n", sym, t);
-
- lineno = 1; // less confusing than end of input
- dclcontext = PEXTERN;
- markdcl();
-
- // func sym(p *T, h uintptr) uintptr
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(sym);
- fn->nname->class = PFUNC;
- tfn = nod(OTFUNC, N, N);
- fn->nname->ntype = tfn;
-
- n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
- tfn->list = list(tfn->list, n);
- np = n->left;
- n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
- tfn->list = list(tfn->list, n);
- nh = n->left;
- n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value
- tfn->rlist = list(tfn->rlist, n);
-
- funchdr(fn);
- typecheck(&fn->nname->ntype, Etype);
-
- // genhash is only called for types that have equality but
- // cannot be handled by the standard algorithms,
- // so t must be either an array or a struct.
- switch(t->etype) {
- default:
- fatal("genhash %T", t);
- case TARRAY:
- if(isslice(t))
- fatal("genhash %T", t);
- // An array of pure memory would be handled by the
- // standard algorithm, so the element type must not be
- // pure memory.
- hashel = hashfor(t->type);
- n = nod(ORANGE, N, nod(OIND, np, N));
- ni = newname(lookup("i"));
- ni->type = types[TINT];
- n->list = list1(ni);
- n->colas = 1;
- colasdefn(n->list, n);
- ni = n->list->n;
-
- // TODO: with aeshash we don't need these shift/mul parts
-
- // h = h<<3 | h>>61
- n->nbody = list(n->nbody,
- nod(OAS,
- nh,
- nod(OOR,
- nod(OLSH, nh, nodintconst(3)),
- nod(ORSH, nh, nodintconst(widthptr*8-3)))));
-
- // h *= mul
- // Same multipliers as in runtime.memhash.
- if(widthptr == 4)
- mul = 3267000013LL;
- else
- mul = 23344194077549503LL;
- n->nbody = list(n->nbody,
- nod(OAS,
- nh,
- nod(OMUL, nh, nodintconst(mul))));
-
- // h = hashel(&p[i], h)
- call = nod(OCALL, hashel, N);
- nx = nod(OINDEX, np, ni);
- nx->bounded = 1;
- na = nod(OADDR, nx, N);
- na->etype = 1; // no escape to heap
- call->list = list(call->list, na);
- call->list = list(call->list, nh);
- n->nbody = list(n->nbody, nod(OAS, nh, call));
-
- fn->nbody = list(fn->nbody, n);
- break;
-
- case TSTRUCT:
- // Walk the struct using memhash for runs of AMEM
- // and calling specific hash functions for the others.
- first = T;
- offend = 0;
- for(t1=t->type;; t1=t1->down) {
- if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
- offend = t1->width + t1->type->width;
- if(first == T)
- first = t1;
- // If it's a memory field but it's padded, stop here.
- if(ispaddedfield(t1, t->width))
- t1 = t1->down;
- else
- continue;
- }
- // Run memhash for fields up to this one.
- if(first != T) {
- size = offend - first->width; // first->width is offset
- hashel = hashmem(first->type);
- // h = hashel(&p.first, size, h)
- call = nod(OCALL, hashel, N);
- nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages?
- na = nod(OADDR, nx, N);
- na->etype = 1; // no escape to heap
- call->list = list(call->list, na);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(size));
- fn->nbody = list(fn->nbody, nod(OAS, nh, call));
-
- first = T;
- }
- if(t1 == T)
- break;
- if(isblanksym(t1->sym))
- continue;
-
- // Run hash for this field.
- if(algtype1(t1->type, nil) == AMEM) {
- hashel = hashmem(t1->type);
- // h = memhash(&p.t1, h, size)
- call = nod(OCALL, hashel, N);
- nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
- na = nod(OADDR, nx, N);
- na->etype = 1; // no escape to heap
- call->list = list(call->list, na);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(t1->type->width));
- fn->nbody = list(fn->nbody, nod(OAS, nh, call));
- } else {
- hashel = hashfor(t1->type);
- // h = hashel(&p.t1, h)
- call = nod(OCALL, hashel, N);
- nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
- na = nod(OADDR, nx, N);
- na->etype = 1; // no escape to heap
- call->list = list(call->list, na);
- call->list = list(call->list, nh);
- fn->nbody = list(fn->nbody, nod(OAS, nh, call));
- }
- }
- break;
- }
- r = nod(ORETURN, N, N);
- r->list = list(r->list, nh);
- fn->nbody = list(fn->nbody, r);
-
- if(debug['r'])
- dumplist("genhash body", fn->nbody);
-
- funcbody(fn);
- curfn = fn;
- fn->dupok = 1;
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
- curfn = nil;
-
- // Disable safemode while compiling this code: the code we
- // generate internally can refer to unsafe.Pointer.
- // In this case it can happen if we need to generate an ==
- // for a struct containing a reflect.Value, which itself has
- // an unexported field of type unsafe.Pointer.
- old_safemode = safemode;
- safemode = 0;
- funccompile(fn);
- safemode = old_safemode;
-}
-
-// Return node for
-// if p.field != q.field { return false }
-static Node*
-eqfield(Node *p, Node *q, Node *field)
-{
- Node *nif, *nx, *ny, *r;
-
- nx = nod(OXDOT, p, field);
- ny = nod(OXDOT, q, field);
- nif = nod(OIF, N, N);
- nif->ntest = nod(ONE, nx, ny);
- r = nod(ORETURN, N, N);
- r->list = list(r->list, nodbool(0));
- nif->nbody = list(nif->nbody, r);
- return nif;
-}
-
-static Node*
-eqmemfunc(vlong size, Type *type, int *needsize)
-{
- char buf[30];
- Node *fn;
-
- switch(size) {
- default:
- fn = syslook("memequal", 1);
- *needsize = 1;
- break;
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- snprint(buf, sizeof buf, "memequal%d", (int)size*8);
- fn = syslook(buf, 1);
- *needsize = 0;
- break;
- }
- argtype(fn, type);
- argtype(fn, type);
- return fn;
-}
-
-// Return node for
-// if !memequal(&p.field, &q.field [, size]) { return false }
-static Node*
-eqmem(Node *p, Node *q, Node *field, vlong size)
-{
- Node *nif, *nx, *ny, *call, *r;
- int needsize;
-
- nx = nod(OADDR, nod(OXDOT, p, field), N);
- nx->etype = 1; // does not escape
- ny = nod(OADDR, nod(OXDOT, q, field), N);
- ny->etype = 1; // does not escape
- typecheck(&nx, Erv);
- typecheck(&ny, Erv);
-
- call = nod(OCALL, eqmemfunc(size, nx->type->type, &needsize), N);
- call->list = list(call->list, nx);
- call->list = list(call->list, ny);
- if(needsize)
- call->list = list(call->list, nodintconst(size));
-
- nif = nod(OIF, N, N);
- nif->ninit = list(nif->ninit, call);
- nif->ntest = nod(ONOT, call, N);
- r = nod(ORETURN, N, N);
- r->list = list(r->list, nodbool(0));
- nif->nbody = list(nif->nbody, r);
- return nif;
-}
-
-/*
- * Generate a helper function to check equality of two values of type t.
- */
-void
-geneq(Sym *sym, Type *t)
-{
- Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r;
- Type *t1, *first;
- int old_safemode;
- int64 size;
- int64 offend;
-
- if(debug['r'])
- print("geneq %S %T\n", sym, t);
-
- lineno = 1; // less confusing than end of input
- dclcontext = PEXTERN;
- markdcl();
-
- // func sym(p, q *T) bool
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(sym);
- fn->nname->class = PFUNC;
- tfn = nod(OTFUNC, N, N);
- fn->nname->ntype = tfn;
-
- n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
- tfn->list = list(tfn->list, n);
- np = n->left;
- n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
- tfn->list = list(tfn->list, n);
- nq = n->left;
- n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
- tfn->rlist = list(tfn->rlist, n);
-
- funchdr(fn);
-
- // geneq is only called for types that have equality but
- // cannot be handled by the standard algorithms,
- // so t must be either an array or a struct.
- switch(t->etype) {
- default:
- fatal("geneq %T", t);
- case TARRAY:
- if(isslice(t))
- fatal("geneq %T", t);
- // An array of pure memory would be handled by the
- // standard memequal, so the element type must not be
- // pure memory. Even if we unrolled the range loop,
- // each iteration would be a function call, so don't bother
- // unrolling.
- nrange = nod(ORANGE, N, nod(OIND, np, N));
- ni = newname(lookup("i"));
- ni->type = types[TINT];
- nrange->list = list1(ni);
- nrange->colas = 1;
- colasdefn(nrange->list, nrange);
- ni = nrange->list->n;
-
- // if p[i] != q[i] { return false }
- nx = nod(OINDEX, np, ni);
- nx->bounded = 1;
- ny = nod(OINDEX, nq, ni);
- ny->bounded = 1;
-
- nif = nod(OIF, N, N);
- nif->ntest = nod(ONE, nx, ny);
- r = nod(ORETURN, N, N);
- r->list = list(r->list, nodbool(0));
- nif->nbody = list(nif->nbody, r);
- nrange->nbody = list(nrange->nbody, nif);
- fn->nbody = list(fn->nbody, nrange);
- break;
-
- case TSTRUCT:
- // Walk the struct using memequal for runs of AMEM
- // and calling specific equality tests for the others.
- // Skip blank-named fields.
- first = T;
- offend = 0;
- for(t1=t->type;; t1=t1->down) {
- if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
- offend = t1->width + t1->type->width;
- if(first == T)
- first = t1;
- // If it's a memory field but it's padded, stop here.
- if(ispaddedfield(t1, t->width))
- t1 = t1->down;
- else
- continue;
- }
- // Run memequal for fields up to this one.
- // TODO(rsc): All the calls to newname are wrong for
- // cross-package unexported fields.
- if(first != T) {
- if(first->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
- } else if(first->down->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
- first = first->down;
- if(!isblanksym(first->sym))
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
- } else {
- // More than two fields: use memequal.
- size = offend - first->width; // first->width is offset
- fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size));
- }
- first = T;
- }
- if(t1 == T)
- break;
- if(isblanksym(t1->sym))
- continue;
-
- // Check this field, which is not just memory.
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym)));
- }
-
- break;
- }
-
- // return true
- r = nod(ORETURN, N, N);
- r->list = list(r->list, nodbool(1));
- fn->nbody = list(fn->nbody, r);
-
- if(debug['r'])
- dumplist("geneq body", fn->nbody);
-
- funcbody(fn);
- curfn = fn;
- fn->dupok = 1;
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
- curfn = nil;
-
- // Disable safemode while compiling this code: the code we
- // generate internally can refer to unsafe.Pointer.
- // In this case it can happen if we need to generate an ==
- // for a struct containing a reflect.Value, which itself has
- // an unexported field of type unsafe.Pointer.
- old_safemode = safemode;
- safemode = 0;
- funccompile(fn);
- safemode = old_safemode;
-}
-
-static Type*
-ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
-{
- int i, c, d;
- Type *m;
-
- *followptr = 0;
-
- if(t == T)
- return T;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, &m, ignorecase);
- if(c > 1) {
- yyerror("%T.%S is ambiguous", t, s);
- return T;
- }
- if(c == 1) {
- for(i=0; i<d; i++) {
- if(isptr[dotlist[i].field->type->etype]) {
- *followptr = 1;
- break;
- }
- }
- if(m->type->etype != TFUNC || m->type->thistuple == 0) {
- yyerror("%T.%S is a field, not a method", t, s);
- return T;
- }
- return m;
- }
- }
- return T;
-}
-
-int
-implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
-{
- Type *t0, *im, *tm, *rcvr, *imtype;
- int followptr;
-
- t0 = t;
- if(t == T)
- return 0;
-
- // if this is too slow,
- // could sort these first
- // and then do one loop.
-
- if(t->etype == TINTER) {
- for(im=iface->type; im; im=im->down) {
- for(tm=t->type; tm; tm=tm->down) {
- if(tm->sym == im->sym) {
- if(eqtype(tm->type, im->type))
- goto found;
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- }
- *m = im;
- *samename = nil;
- *ptr = 0;
- return 0;
- found:;
- }
- return 1;
- }
-
- t = methtype(t, 0);
- if(t != T)
- expandmeth(t);
- for(im=iface->type; im; im=im->down) {
- imtype = methodfunc(im->type, 0);
- tm = ifacelookdot(im->sym, t, &followptr, 0);
- if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
- if(tm == T)
- tm = ifacelookdot(im->sym, t, &followptr, 1);
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- // if pointer receiver in method,
- // the method does not exist for value types.
- rcvr = getthisx(tm->type)->type->type;
- if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
- if(0 && debug['r'])
- yyerror("interface pointer mismatch");
-
- *m = im;
- *samename = nil;
- *ptr = 1;
- return 0;
- }
- }
- return 1;
-}
-
-/*
- * even simpler simtype; get rid of ptr, bool.
- * assuming that the front end has rejected
- * all the invalid conversions (like ptr -> bool)
- */
-int
-simsimtype(Type *t)
-{
- int et;
-
- if(t == 0)
- return 0;
-
- et = simtype[t->etype];
- switch(et) {
- case TPTR32:
- et = TUINT32;
- break;
- case TPTR64:
- et = TUINT64;
- break;
- case TBOOL:
- et = TUINT8;
- break;
- }
- return et;
-}
-
-NodeList*
-concat(NodeList *a, NodeList *b)
-{
- if(a == nil)
- return b;
- if(b == nil)
- return a;
-
- a->end->next = b;
- a->end = b->end;
- b->end = nil;
- return a;
-}
-
-NodeList*
-list1(Node *n)
-{
- NodeList *l;
-
- if(n == nil)
- return nil;
- if(n->op == OBLOCK && n->ninit == nil) {
- // Flatten list and steal storage.
- // Poison pointer to catch errant uses.
- l = n->list;
- n->list = (NodeList*)1;
- return l;
- }
- l = mal(sizeof *l);
- l->n = n;
- l->end = l;
- return l;
-}
-
-NodeList*
-list(NodeList *l, Node *n)
-{
- return concat(l, list1(n));
-}
-
-void
-listsort(NodeList** l, int(*f)(Node*, Node*))
-{
- NodeList *l1, *l2, *le;
-
- if(*l == nil || (*l)->next == nil)
- return;
-
- l1 = *l;
- l2 = *l;
- for(;;) {
- l2 = l2->next;
- if(l2 == nil)
- break;
- l2 = l2->next;
- if(l2 == nil)
- break;
- l1 = l1->next;
- }
-
- l2 = l1->next;
- l1->next = nil;
- l2->end = (*l)->end;
- (*l)->end = l1;
-
- l1 = *l;
- listsort(&l1, f);
- listsort(&l2, f);
-
- if((*f)(l1->n, l2->n) < 0) {
- *l = l1;
- } else {
- *l = l2;
- l2 = l1;
- l1 = *l;
- }
-
- // now l1 == *l; and l1 < l2
-
- while ((l1 != nil) && (l2 != nil)) {
- while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
- l1 = l1->next;
-
- // l1 is last one from l1 that is < l2
- le = l1->next; // le is the rest of l1, first one that is >= l2
- if(le != nil)
- le->end = (*l)->end;
-
- (*l)->end = l1; // cut *l at l1
- *l = concat(*l, l2); // glue l2 to *l's tail
-
- l1 = l2; // l1 is the first element of *l that is < the new l2
- l2 = le; // ... because l2 now is the old tail of l1
- }
-
- *l = concat(*l, l2); // any remainder
-}
-
-NodeList*
-listtreecopy(NodeList *l)
-{
- NodeList *out;
-
- out = nil;
- for(; l; l=l->next)
- out = list(out, treecopy(l->n));
- return out;
-}
-
-Node*
-liststmt(NodeList *l)
-{
- Node *n;
-
- n = nod(OBLOCK, N, N);
- n->list = l;
- if(l)
- n->lineno = l->n->lineno;
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-count(NodeList *l)
-{
- vlong n;
-
- n = 0;
- for(; l; l=l->next)
- n++;
- if((int)n != n) { // Overflow.
- yyerror("too many elements in list");
- }
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-structcount(Type *t)
-{
- int v;
- Iter s;
-
- v = 0;
- for(t = structfirst(&s, &t); t != T; t = structnext(&s))
- v++;
- return v;
-}
-
-/*
- * return power of 2 of the constant
- * operand. -1 if it is not a power of 2.
- * 1000+ if it is a -(power of 2)
- */
-int
-powtwo(Node *n)
-{
- uvlong v, b;
- int i;
-
- if(n == N || n->op != OLITERAL || n->type == T)
- goto no;
- if(!isint[n->type->etype])
- goto no;
-
- v = mpgetfix(n->val.u.xval);
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i;
- b = b<<1;
- }
-
- if(!issigned[n->type->etype])
- goto no;
-
- v = -v;
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i+1000;
- b = b<<1;
- }
-
-no:
- return -1;
-}
-
-/*
- * return the unsigned type for
- * a signed integer type.
- * returns T if input is not a
- * signed integer type.
- */
-Type*
-tounsigned(Type *t)
-{
-
- // this is types[et+1], but not sure
- // that this relation is immutable
- switch(t->etype) {
- default:
- print("tounsigned: unknown type %T\n", t);
- t = T;
- break;
- case TINT:
- t = types[TUINT];
- break;
- case TINT8:
- t = types[TUINT8];
- break;
- case TINT16:
- t = types[TUINT16];
- break;
- case TINT32:
- t = types[TUINT32];
- break;
- case TINT64:
- t = types[TUINT64];
- break;
- }
- return t;
-}
-
-/*
- * magic number for signed division
- * see hacker's delight chapter 10
- */
-void
-smagic(Magic *m)
-{
- int p;
- uint64 ad, anc, delta, q1, r1, q2, r2, t;
- uint64 mask, two31;
-
- m->bad = 0;
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffULL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- p = m->w-1;
- ad = m->sd;
- if(m->sd < 0)
- ad = -(uvlong)m->sd;
-
- // bad denominators
- if(ad == 0 || ad == 1 || ad == two31) {
- m->bad = 1;
- return;
- }
-
- t = two31;
- ad &= mask;
-
- anc = t - 1 - t%ad;
- anc &= mask;
-
- q1 = two31/anc;
- r1 = two31 - q1*anc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = two31/ad;
- r2 = two31 - q2*ad;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- q1 <<= 1;
- r1 <<= 1;
- q1 &= mask;
- r1 &= mask;
- if(r1 >= anc) {
- q1++;
- r1 -= anc;
- q1 &= mask;
- r1 &= mask;
- }
-
- q2 <<= 1;
- r2 <<= 1;
- q2 &= mask;
- r2 &= mask;
- if(r2 >= ad) {
- q2++;
- r2 -= ad;
- q2 &= mask;
- r2 &= mask;
- }
-
- delta = ad - r2;
- delta &= mask;
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
-
- m->sm = q2+1;
- if(m->sm & two31)
- m->sm |= ~mask;
- m->s = p-m->w;
-}
-
-/*
- * magic number for unsigned division
- * see hacker's delight chapter 10
- */
-void
-umagic(Magic *m)
-{
- int p;
- uint64 nc, delta, q1, r1, q2, r2;
- uint64 mask, two31;
-
- m->bad = 0;
- m->ua = 0;
-
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffULL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- m->ud &= mask;
- if(m->ud == 0 || m->ud == two31) {
- m->bad = 1;
- return;
- }
- nc = mask - (-m->ud&mask)%m->ud;
- p = m->w-1;
-
- q1 = two31/nc;
- r1 = two31 - q1*nc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = (two31-1) / m->ud;
- r2 = (two31-1) - q2*m->ud;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- if(r1 >= nc-r1) {
- q1 <<= 1;
- q1++;
- r1 <<= 1;
- r1 -= nc;
- } else {
- q1 <<= 1;
- r1 <<= 1;
- }
- q1 &= mask;
- r1 &= mask;
- if(r2+1 >= m->ud-r2) {
- if(q2 >= two31-1) {
- m->ua = 1;
- }
- q2 <<= 1;
- q2++;
- r2 <<= 1;
- r2++;
- r2 -= m->ud;
- } else {
- if(q2 >= two31) {
- m->ua = 1;
- }
- q2 <<= 1;
- r2 <<= 1;
- r2++;
- }
- q2 &= mask;
- r2 &= mask;
-
- delta = m->ud - 1 - r2;
- delta &= mask;
-
- if(p < m->w+m->w)
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
- m->um = q2+1;
- m->s = p-m->w;
-}
-
-Sym*
-ngotype(Node *n)
-{
- if(n->type != T)
- return typenamesym(n->type);
- return S;
-}
-
-/*
- * Convert raw string to the prefix that will be used in the symbol
- * table. All control characters, space, '%' and '"', as well as
- * non-7-bit clean bytes turn into %xx. The period needs escaping
- * only in the last segment of the path, and it makes for happier
- * users if we escape that as little as possible.
- *
- * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
- * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
- */
-static char*
-pathtoprefix(char *s)
-{
- static char hex[] = "0123456789abcdef";
- char *p, *r, *w, *l;
- int n;
-
- // find first character past the last slash, if any.
- l = s;
- for(r=s; *r; r++)
- if(*r == '/')
- l = r+1;
-
- // check for chars that need escaping
- n = 0;
- for(r=s; *r; r++)
- if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
- n++;
-
- // quick exit
- if(n == 0)
- return s;
-
- // escape
- p = mal((r-s)+1+2*n);
- for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
- *w++ = '%';
- *w++ = hex[(*r>>4)&0xF];
- *w++ = hex[*r&0xF];
- } else
- *w++ = *r;
- }
- *w = '\0';
- return p;
-}
-
-Pkg*
-mkpkg(Strlit *path)
-{
- Pkg *p;
- int h;
-
- h = stringhash(path->s) & (nelem(phash)-1);
- for(p=phash[h]; p; p=p->link)
- if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
- return p;
-
- p = mal(sizeof *p);
- p->path = path;
- p->prefix = pathtoprefix(path->s);
- p->link = phash[h];
- phash[h] = p;
- return p;
-}
-
-Strlit*
-newstrlit(char *s)
-{
- Strlit *t;
-
- t = mal(sizeof *t + strlen(s));
- strcpy(t->s, s);
- t->len = strlen(s);
- return t;
-}
-
-void
-addinit(Node **np, NodeList *init)
-{
- Node *n;
-
- if(init == nil)
- return;
-
- n = *np;
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- // There may be multiple refs to this node;
- // introduce OCONVNOP to hold init list.
- n = nod(OCONVNOP, n, N);
- n->type = n->left->type;
- n->typecheck = 1;
- *np = n;
- break;
- }
- n->ninit = concat(init, n->ninit);
- n->ullman = UINF;
-}
-
-static char* reservedimports[] = {
- "go",
- "type",
-};
-
-int
-isbadimport(Strlit *path)
-{
- int i;
- char *s;
- Rune r;
-
- if(strlen(path->s) != path->len) {
- yyerror("import path contains NUL");
- return 1;
- }
-
- for(i=0; i<nelem(reservedimports); i++) {
- if(strcmp(path->s, reservedimports[i]) == 0) {
- yyerror("import path \"%s\" is reserved and cannot be used", path->s);
- return 1;
- }
- }
-
- s = path->s;
- while(*s) {
- s += chartorune(&r, s);
- if(r == Runeerror) {
- yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
- return 1;
- }
- if(r < 0x20 || r == 0x7f) {
- yyerror("import path contains control character: \"%Z\"", path);
- return 1;
- }
- if(r == '\\') {
- yyerror("import path contains backslash; use slash: \"%Z\"", path);
- return 1;
- }
- if(isspacerune(r)) {
- yyerror("import path contains space character: \"%Z\"", path);
- return 1;
- }
- if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
- yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
- return 1;
- }
- }
- return 0;
-}
-
-void
-checknil(Node *x, NodeList **init)
-{
- Node *n;
-
- if(isinter(x->type)) {
- x = nod(OITAB, x, N);
- typecheck(&x, Erv);
- }
- n = nod(OCHECKNIL, x, N);
- n->typecheck = 1;
- *init = list(*init, n);
-}
-
-/*
- * Can this type be stored directly in an interface word?
- * Yes, if the representation is a single pointer.
- */
-int
-isdirectiface(Type *t)
-{
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TMAP:
- case TFUNC:
- case TUNSAFEPTR:
- return 1;
- case TARRAY:
- // Array of 1 direct iface type can be direct.
- return t->bound == 1 && isdirectiface(t->type);
- case TSTRUCT:
- // Struct with 1 field of direct iface type can be direct.
- return t->type != T && t->type->down == T && isdirectiface(t->type->type);
- }
- return 0;
-}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
deleted file mode 100644
index 0dc0065ed9..0000000000
--- a/src/cmd/gc/swt.c
+++ /dev/null
@@ -1,944 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum
-{
- Snorm = 0,
- Strue,
- Sfalse,
- Stype,
-
- Tdefault, // default case
- Texprconst, // normal constant case
- Texprvar, // normal variable case
- Ttypenil, // case nil
- Ttypeconst, // type hashes
- Ttypevar, // interface type
-
- Ncase = 4, // count needed to split
-};
-
-typedef struct Case Case;
-struct Case
-{
- Node* node; // points at case statement
- uint32 hash; // hash of a type switch
- uint8 type; // type of case
- uint8 diag; // suppress multiple diagnostics
- uint16 ordinal; // position in switch
- Case* link; // linked list to link
-};
-#define C ((Case*)nil)
-/*c2go Case *C; */
-
-void
-dumpcase(Case *c0)
-{
- Case *c;
-
- for(c=c0; c!=C; c=c->link) {
- switch(c->type) {
- case Tdefault:
- print("case-default\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprconst:
- print("case-exprconst\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprvar:
- print("case-exprvar\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- break;
- case Ttypenil:
- print("case-typenil\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Ttypeconst:
- print("case-typeconst\n");
- print(" ord=%d\n", c->ordinal);
- print(" hash=%ux\n", c->hash);
- break;
- case Ttypevar:
- print("case-typevar\n");
- print(" ord=%d\n", c->ordinal);
- break;
- default:
- print("case-???\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- print(" hash=%ux\n", c->hash);
- break;
- }
- }
- print("\n");
-}
-
-static int
-ordlcmp(Case *c1, Case *c2)
-{
- // sort default first
- if(c1->type == Tdefault)
- return -1;
- if(c2->type == Tdefault)
- return +1;
-
- // sort nil second
- if(c1->type == Ttypenil)
- return -1;
- if(c2->type == Ttypenil)
- return +1;
-
- // sort by ordinal
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static int
-exprcmp(Case *c1, Case *c2)
-{
- int ct, n;
- Node *n1, *n2;
-
- // sort non-constants last
- if(c1->type != Texprconst)
- return +1;
- if(c2->type != Texprconst)
- return -1;
-
- n1 = c1->node->left;
- n2 = c2->node->left;
-
- // sort by type (for switches on interface)
- ct = n1->val.ctype;
- if(ct != n2->val.ctype)
- return ct - n2->val.ctype;
- if(!eqtype(n1->type, n2->type)) {
- if(n1->type->vargen > n2->type->vargen)
- return +1;
- else
- return -1;
- }
-
- // sort by constant value
- n = 0;
- switch(ct) {
- case CTFLT:
- n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
- break;
- case CTSTR:
- n = cmpslit(n1, n2);
- break;
- }
-
- return n;
-}
-
-static int
-typecmp(Case *c1, Case *c2)
-{
-
- // sort non-constants last
- if(c1->type != Ttypeconst)
- return +1;
- if(c2->type != Ttypeconst)
- return -1;
-
- // sort by hash code
- if(c1->hash > c2->hash)
- return +1;
- if(c1->hash < c2->hash)
- return -1;
-
- // sort by ordinal so duplicate error
- // happens on later case.
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static Case*
-csort(Case *l, int(*f)(Case*, Case*))
-{
- Case *l1, *l2, *le;
-
- if(l == C || l->link == C)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == C)
- break;
- l2 = l2->link;
- if(l2 == C)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = C;
- l1 = csort(l, f);
- l2 = csort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == C) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = C;
- break;
- }
- if(l2 == C) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = C;
- return l;
-}
-
-static Node*
-newlabel(void)
-{
- static int label;
-
- label++;
- snprint(namebuf, sizeof(namebuf), "%.6d", label);
- return newname(lookup(namebuf));
-}
-
-/*
- * build separate list of statements and cases
- * make labels between cases and statements
- * deal with fallthrough, break, unreachable statements
- */
-static void
-casebody(Node *sw, Node *typeswvar)
-{
- Node *n, *c, *last;
- Node *def;
- NodeList *cas, *stat, *l, *lc;
- Node *go, *br;
- int32 lno, needvar;
-
- if(sw->list == nil)
- return;
-
- lno = setlineno(sw);
-
- cas = nil; // cases
- stat = nil; // statements
- def = N; // defaults
- br = nod(OBREAK, N, N);
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- setlineno(n);
- if(n->op != OXCASE)
- fatal("casebody %O", n->op);
- n->op = OCASE;
- needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
-
- go = nod(OGOTO, newlabel(), N);
- if(n->list == nil) {
- if(def != N)
- yyerror("more than one default case");
- // reuse original default case
- n->right = go;
- def = n;
- }
-
- if(n->list != nil && n->list->next == nil) {
- // one case - reuse OCASE node.
- c = n->list->n;
- n->left = c;
- n->right = go;
- n->list = nil;
- cas = list(cas, n);
- } else {
- // expand multi-valued cases
- for(lc=n->list; lc; lc=lc->next) {
- c = lc->n;
- cas = list(cas, nod(OCASE, c, go));
- }
- }
-
- stat = list(stat, nod(OLABEL, go->left, N));
- if(typeswvar && needvar && n->nname != N) {
- NodeList *l;
-
- l = list1(nod(ODCL, n->nname, N));
- l = list(l, nod(OAS, n->nname, typeswvar));
- typechecklist(l, Etop);
- stat = concat(stat, l);
- }
- stat = concat(stat, n->nbody);
-
- // botch - shouldn't fall thru declaration
- last = stat->end->n;
- if(last->xoffset == n->xoffset && last->op == OXFALL) {
- if(typeswvar) {
- setlineno(last);
- yyerror("cannot fallthrough in type switch");
- }
- if(l->next == nil) {
- setlineno(last);
- yyerror("cannot fallthrough final case in switch");
- }
- last->op = OFALL;
- } else
- stat = list(stat, br);
- }
-
- stat = list(stat, br);
- if(def)
- cas = list(cas, def);
-
- sw->list = cas;
- sw->nbody = stat;
- lineno = lno;
-}
-
-static Case*
-mkcaselist(Node *sw, int arg)
-{
- Node *n;
- Case *c, *c1, *c2;
- NodeList *l;
- int ord;
-
- c = C;
- ord = 0;
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- c1 = mal(sizeof(*c1));
- c1->link = c;
- c = c1;
-
- ord++;
- if((uint16)ord != ord)
- fatal("too many cases in switch");
- c->ordinal = ord;
- c->node = n;
-
- if(n->left == N) {
- c->type = Tdefault;
- continue;
- }
-
- switch(arg) {
- case Stype:
- c->hash = 0;
- if(n->left->op == OLITERAL) {
- c->type = Ttypenil;
- continue;
- }
- if(istype(n->left->type, TINTER)) {
- c->type = Ttypevar;
- continue;
- }
-
- c->hash = typehash(n->left->type);
- c->type = Ttypeconst;
- continue;
-
- case Snorm:
- case Strue:
- case Sfalse:
- c->type = Texprvar;
- c->hash = typehash(n->left->type);
- switch(consttype(n->left)) {
- case CTFLT:
- case CTINT:
- case CTRUNE:
- case CTSTR:
- c->type = Texprconst;
- }
- continue;
- }
- }
-
- if(c == C)
- return C;
-
- // sort by value and diagnose duplicate cases
- switch(arg) {
- case Stype:
- c = csort(c, typecmp);
- for(c1=c; c1!=C; c1=c1->link) {
- for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
- if(c1->type == Ttypenil || c1->type == Tdefault)
- break;
- if(c2->type == Ttypenil || c2->type == Tdefault)
- break;
- if(!eqtype(c1->node->left->type, c2->node->left->type))
- continue;
- yyerrorl(c2->node->lineno, "duplicate case %T in type switch\n\tprevious case at %L", c2->node->left->type, c1->node->lineno);
- }
- }
- break;
- case Snorm:
- case Strue:
- case Sfalse:
- c = csort(c, exprcmp);
- for(c1=c; c1->link!=C; c1=c1->link) {
- if(exprcmp(c1, c1->link) != 0)
- continue;
- setlineno(c1->link->node);
- yyerror("duplicate case %N in switch\n\tprevious case at %L", c1->node->left, c1->node->lineno);
- }
- break;
- }
-
- // put list back in processing order
- c = csort(c, ordlcmp);
- return c;
-}
-
-static Node* exprname;
-
-static Node*
-exprbsw(Case *c0, int ncase, int arg)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half, lno;
-
- cas = nil;
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- lno = setlineno(n);
-
- if((arg != Strue && arg != Sfalse) ||
- assignop(n->left->type, exprname->type, nil) == OCONVIFACE ||
- assignop(exprname->type, n->left->type, nil) == OCONVIFACE) {
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, exprname, n->left); // if name == val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- } else if(arg == Strue) {
- a = nod(OIF, N, N);
- a->ntest = n->left; // if val
- a->nbody = list1(n->right); // then goto l
- } else { // arg == Sfalse
- a = nod(OIF, N, N);
- a->ntest = nod(ONOT, n->left, N); // if !val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- }
-
- cas = list(cas, a);
- c0 = c0->link;
- lineno = lno;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, exprname, c->node->left);
- typecheck(&a->ntest, Erv);
- a->nbody = list1(exprbsw(c0, half, arg));
- a->nelse = list1(exprbsw(c->link, ncase-half, arg));
- return a;
-}
-
-/*
- * normal (expression) switch.
- * rebuild case statements into if .. goto
- */
-static void
-exprswitch(Node *sw)
-{
- Node *def;
- NodeList *cas;
- Node *a;
- Case *c0, *c, *c1;
- Type *t;
- int arg, ncase;
-
- casebody(sw, N);
-
- arg = Snorm;
- if(isconst(sw->ntest, CTBOOL)) {
- arg = Strue;
- if(sw->ntest->val.u.bval == 0)
- arg = Sfalse;
- }
- walkexpr(&sw->ntest, &sw->ninit);
- t = sw->type;
- if(t == T)
- return;
-
- /*
- * convert the switch into OIF statements
- */
- exprname = N;
- cas = nil;
- if(arg == Strue || arg == Sfalse)
- exprname = nodbool(arg == Strue);
- else if(consttype(sw->ntest) >= 0)
- // leave constants to enable dead code elimination (issue 9608)
- exprname = sw->ntest;
- else {
- exprname = temp(sw->ntest->type);
- cas = list1(nod(OAS, exprname, sw->ntest));
- typechecklist(cas, Etop);
- }
-
- c0 = mkcaselist(sw, arg);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
-loop:
- if(c0 == C) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- return;
- }
-
- // deal with the variables one-at-a-time
- if(!okforcmp[t->etype] || c0->type != Texprconst) {
- a = exprbsw(c0, 1, arg);
- cas = list(cas, a);
- c0 = c0->link;
- goto loop;
- }
-
- // do binary search on run of constants
- ncase = 1;
- for(c=c0; c->link!=C; c=c->link) {
- if(c->link->type != Texprconst)
- break;
- ncase++;
- }
-
- // break the chain at the count
- c1 = c->link;
- c->link = C;
-
- // sort and compile constants
- c0 = csort(c0, exprcmp);
- a = exprbsw(c0, ncase, arg);
- cas = list(cas, a);
-
- c0 = c1;
- goto loop;
-
-}
-
-static Node* hashname;
-static Node* facename;
-static Node* boolname;
-
-static Node*
-typeone(Node *t)
-{
- NodeList *init;
- Node *a, *b, *var;
-
- var = t->nname;
- init = nil;
- if(var == N) {
- typecheck(&nblank, Erv | Easgn);
- var = nblank;
- } else
- init = list1(nod(ODCL, var, N));
-
- a = nod(OAS2, N, N);
- a->list = list(list1(var), boolname); // var,bool =
- b = nod(ODOTTYPE, facename, N);
- b->type = t->left->type; // interface.(type)
- a->rlist = list1(b);
- typecheck(&a, Etop);
- init = list(init, a);
-
- b = nod(OIF, N, N);
- b->ntest = boolname;
- b->nbody = list1(t->right); // if bool { goto l }
- a = liststmt(list(init, b));
- return a;
-}
-
-static Node*
-typebsw(Case *c0, int ncase)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half;
-
- cas = nil;
-
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- if(c0->type != Ttypeconst)
- fatal("typebsw");
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right);
- cas = list(cas, a);
- c0 = c0->link;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, hashname, nodintconst(c->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(typebsw(c0, half));
- a->nelse = list1(typebsw(c->link, ncase-half));
- return a;
-}
-
-/*
- * convert switch of the form
- * switch v := i.(type) { case t1: ..; case t2: ..; }
- * into if statements
- */
-static void
-typeswitch(Node *sw)
-{
- Node *def;
- NodeList *cas, *hash;
- Node *a, *n;
- Case *c, *c0, *c1;
- int ncase;
- Type *t;
- Val v;
-
- if(sw->ntest == nil)
- return;
- if(sw->ntest->right == nil) {
- setlineno(sw);
- yyerror("type switch must have an assignment");
- return;
- }
- walkexpr(&sw->ntest->right, &sw->ninit);
- if(!istype(sw->ntest->right->type, TINTER)) {
- yyerror("type switch must be on an interface");
- return;
- }
- cas = nil;
-
- /*
- * predeclare temporary variables
- * and the boolean var
- */
- facename = temp(sw->ntest->right->type);
- a = nod(OAS, facename, sw->ntest->right);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- casebody(sw, facename);
-
- boolname = temp(types[TBOOL]);
- typecheck(&boolname, Erv);
-
- hashname = temp(types[TUINT32]);
- typecheck(&hashname, Erv);
-
- t = sw->ntest->right->type;
- if(isnilinter(t))
- a = syslook("efacethash", 1);
- else
- a = syslook("ifacethash", 1);
- argtype(a, t);
- a = nod(OCALL, a, N);
- a->list = list1(facename);
- a = nod(OAS, hashname, a);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- c0 = mkcaselist(sw, Stype);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
- /*
- * insert if statement into each case block
- */
- for(c=c0; c!=C; c=c->link) {
- n = c->node;
- switch(c->type) {
-
- case Ttypenil:
- v.ctype = CTNIL;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, facename, nodlit(v));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // if i==nil { goto l }
- n->right = a;
- break;
-
- case Ttypevar:
- case Ttypeconst:
- n->right = typeone(n);
- break;
- }
- }
-
- /*
- * generate list of if statements, binary search for constant sequences
- */
- while(c0 != C) {
- if(c0->type != Ttypeconst) {
- n = c0->node;
- cas = list(cas, n->right);
- c0=c0->link;
- continue;
- }
-
- // identify run of constants
- c1 = c = c0;
- while(c->link!=C && c->link->type==Ttypeconst)
- c = c->link;
- c0 = c->link;
- c->link = nil;
-
- // sort by hash
- c1 = csort(c1, typecmp);
-
- // for debugging: linear search
- if(0) {
- for(c=c1; c!=C; c=c->link) {
- n = c->node;
- cas = list(cas, n->right);
- }
- continue;
- }
-
- // combine adjacent cases with the same hash
- ncase = 0;
- for(c=c1; c!=C; c=c->link) {
- ncase++;
- hash = list1(c->node->right);
- while(c->link != C && c->link->hash == c->hash) {
- hash = list(hash, c->link->node->right);
- c->link = c->link->link;
- }
- c->node->right = liststmt(hash);
- }
-
- // binary search among cases to narrow by hash
- cas = list(cas, typebsw(c1, ncase));
- }
- if(nerrors == 0) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- }
-}
-
-void
-walkswitch(Node *sw)
-{
- /*
- * reorder the body into (OLIST, cases, statements)
- * cases have OGOTO into statements.
- * both have inserted OBREAK statements
- */
- if(sw->ntest == N) {
- sw->ntest = nodbool(1);
- typecheck(&sw->ntest, Erv);
- }
-
- if(sw->ntest->op == OTYPESW) {
- typeswitch(sw);
-//dump("sw", sw);
- return;
- }
- exprswitch(sw);
- // Discard old AST elements after a walk. They can confuse racewealk.
- sw->ntest = nil;
- sw->list = nil;
-}
-
-/*
- * type check switch statement
- */
-void
-typecheckswitch(Node *n)
-{
- int top, lno, ptr;
- char *nilonly;
- Type *t, *badtype, *missing, *have;
- NodeList *l, *ll;
- Node *ncase, *nvar;
- Node *def;
-
- lno = lineno;
- typechecklist(n->ninit, Etop);
- nilonly = nil;
-
- if(n->ntest != N && n->ntest->op == OTYPESW) {
- // type switch
- top = Etype;
- typecheck(&n->ntest->right, Erv);
- t = n->ntest->right->type;
- if(t != T && t->etype != TINTER)
- yyerror("cannot type switch on non-interface value %lN", n->ntest->right);
- } else {
- // value switch
- top = Erv;
- if(n->ntest) {
- typecheck(&n->ntest, Erv);
- defaultlit(&n->ntest, T);
- t = n->ntest->type;
- } else
- t = types[TBOOL];
- if(t) {
- if(!okforeq[t->etype])
- yyerror("cannot switch on %lN", n->ntest);
- else if(t->etype == TARRAY && !isfixedarray(t))
- nilonly = "slice";
- else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ)
- yyerror("cannot switch on %lN", n->ntest);
- else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ)
- yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype);
- else if(t->etype == TFUNC)
- nilonly = "func";
- else if(t->etype == TMAP)
- nilonly = "map";
- }
- }
- n->type = t;
-
- def = N;
- for(l=n->list; l; l=l->next) {
- ncase = l->n;
- setlineno(n);
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in switch (first at %L)", def->lineno);
- else
- def = ncase;
- } else {
- for(ll=ncase->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv | Etype);
- if(ll->n->type == T || t == T)
- continue;
- setlineno(ncase);
- switch(top) {
- case Erv: // expression switch
- defaultlit(&ll->n, t);
- if(ll->n->op == OTYPE)
- yyerror("type %T is not an expression", ll->n->type);
- else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
- if(n->ntest)
- yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
- else
- yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
- } else if(nilonly && !isconst(ll->n, CTNIL)) {
- yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
- }
- break;
- case Etype: // type switch
- if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
- ;
- } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||?
- yyerror("%lN is not a type", ll->n);
- // reset to original type
- ll->n = n->ntest->right;
- } else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) {
- if(have && !missing->broke && !have->broke)
- yyerror("impossible type switch case: %lN cannot have dynamic type %T"
- " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
- n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
- missing->sym, missing->type);
- else if(!missing->broke)
- yyerror("impossible type switch case: %lN cannot have dynamic type %T"
- " (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
- }
- break;
- }
- }
- }
- if(top == Etype && n->type != T) {
- ll = ncase->list;
- nvar = ncase->nname;
- if(nvar != N) {
- if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
- // single entry type switch
- nvar->ntype = typenod(ll->n->type);
- } else {
- // multiple entry type switch or default
- nvar->ntype = typenod(n->type);
- }
- typecheck(&nvar, Erv | Easgn);
- ncase->nname = nvar;
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
-
- lineno = lno;
-}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
deleted file mode 100644
index 649f1c5120..0000000000
--- a/src/cmd/gc/typecheck.c
+++ /dev/null
@@ -1,3649 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * type check the whole tree of an expression.
- * calculates expression types.
- * evaluates compile time constants.
- * marks variables that escape the local frame.
- * rewrites n->op to be more specific in some cases.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static void implicitstar(Node**);
-static int onearg(Node*, char*, ...);
-static int twoarg(Node*);
-static int lookdot(Node*, Type*, int);
-static int looktypedot(Node*, Type*, int);
-static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
-static Type* lookdot1(Node*, Sym *s, Type *t, Type *f, int);
-static int nokeys(NodeList*);
-static void typecheckcomplit(Node**);
-static void typecheckas2(Node*);
-static void typecheckas(Node*);
-static void typecheckfunc(Node*);
-static void checklvalue(Node*, char*);
-static void checkassignlist(Node*, NodeList*);
-static void stringtoarraylit(Node**);
-static Node* resolve(Node*);
-static void checkdefergo(Node*);
-static int checkmake(Type*, char*, Node*);
-static int checksliceindex(Node*, Node*, Type*);
-static int checksliceconst(Node*, Node*);
-
-static NodeList* typecheckdefstack;
-
-/*
- * resolve ONONAME to definition, if any.
- */
-static Node*
-resolve(Node *n)
-{
- Node *r;
-
- if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) {
- if(r->op != OIOTA)
- n = r;
- else if(n->iota >= 0)
- n = nodintconst(n->iota);
- }
- return n;
-}
-
-void
-typechecklist(NodeList *l, int top)
-{
- for(; l; l=l->next)
- typecheck(&l->n, top);
-}
-
-static char* _typekind[] = {
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TBOOL] = "bool",
- [TSTRING] = "string",
- [TPTR32] = "pointer",
- [TPTR64] = "pointer",
- [TUNSAFEPTR] = "unsafe.Pointer",
- [TSTRUCT] = "struct",
- [TINTER] = "interface",
- [TCHAN] = "chan",
- [TMAP] = "map",
- [TARRAY] = "array",
- [TFUNC] = "func",
- [TNIL] = "nil",
- [TIDEAL] = "untyped number",
-};
-
-static char*
-typekind(Type *t)
-{
- int et;
- static char buf[50];
- char *s;
-
- if(isslice(t))
- return "slice";
- et = t->etype;
- if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
- return s;
- snprint(buf, sizeof buf, "etype=%d", et);
- return buf;
-}
-
-/*
- * sprint_depchain prints a dependency chain
- * of nodes into fmt.
- * It is used by typecheck in the case of OLITERAL nodes
- * to print constant definition loops.
- */
-static void
-sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first)
-{
- NodeList *l;
-
- for(l = stack; l; l=l->next) {
- if(l->n->op == cur->op) {
- if(l->n != first)
- sprint_depchain(fmt, l->next, l->n, first);
- fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur);
- return;
- }
- }
-}
-
-/*
- * type check node *np.
- * replaces *np with a new pointer in some cases.
- * returns the final value of *np as a convenience.
- */
-static void typecheck1(Node **, int);
-Node*
-typecheck(Node **np, int top)
-{
- Node *n;
- int lno;
- Fmt fmt;
- NodeList *l;
- static NodeList *tcstack, *tcfree;
-
- // cannot type check until all the source has been parsed
- if(!typecheckok)
- fatal("early typecheck");
-
- n = *np;
- if(n == N)
- return N;
-
- lno = setlineno(n);
-
- // Skip over parens.
- while(n->op == OPAREN)
- n = n->left;
-
- // Resolve definition of name and value of iota lazily.
- n = resolve(n);
-
- *np = n;
-
- // Skip typecheck if already done.
- // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
- if(n->typecheck == 1) {
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OLITERAL:
- case OPACK:
- break;
- default:
- lineno = lno;
- return n;
- }
- }
-
- if(n->typecheck == 2) {
- // Typechecking loop. Trying printing a meaningful message,
- // otherwise a stack trace of typechecking.
- switch(n->op) {
- case ONAME:
- // We can already diagnose variables used as types.
- if((top & (Erv|Etype)) == Etype)
- yyerror("%N is not a type", n);
- break;
- case OLITERAL:
- if((top & (Erv|Etype)) == Etype) {
- yyerror("%N is not a type", n);
- break;
- }
- fmtstrinit(&fmt);
- sprint_depchain(&fmt, tcstack, n, n);
- yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt));
- break;
- }
- if(nsavederrors+nerrors == 0) {
- fmtstrinit(&fmt);
- for(l=tcstack; l; l=l->next)
- fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n);
- yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt));
- }
- lineno = lno;
- return n;
- }
- n->typecheck = 2;
-
- if(tcfree != nil) {
- l = tcfree;
- tcfree = l->next;
- } else
- l = mal(sizeof *l);
- l->next = tcstack;
- l->n = n;
- tcstack = l;
-
- typecheck1(&n, top);
- *np = n;
- n->typecheck = 1;
-
- if(tcstack != l)
- fatal("typecheck stack out of sync");
- tcstack = l->next;
- l->next = tcfree;
- tcfree = l;
-
- lineno = lno;
- return n;
-}
-
-/*
- * does n contain a call or receive operation?
- */
-static int callrecvlist(NodeList*);
-
-static int
-callrecv(Node *n)
-{
- if(n == nil)
- return 0;
-
- switch(n->op) {
- case OCALL:
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- case ORECV:
- case OCAP:
- case OLEN:
- case OCOPY:
- case ONEW:
- case OAPPEND:
- case ODELETE:
- return 1;
- }
-
- return callrecv(n->left) ||
- callrecv(n->right) ||
- callrecv(n->ntest) ||
- callrecv(n->nincr) ||
- callrecvlist(n->ninit) ||
- callrecvlist(n->nbody) ||
- callrecvlist(n->nelse) ||
- callrecvlist(n->list) ||
- callrecvlist(n->rlist);
-}
-
-static int
-callrecvlist(NodeList *l)
-{
- for(; l; l=l->next)
- if(callrecv(l->n))
- return 1;
- return 0;
-}
-
-// indexlit implements typechecking of untyped values as
-// array/slice indexes. It is equivalent to defaultlit
-// except for constants of numerical kind, which are acceptable
-// whenever they can be represented by a value of type int.
-static void
-indexlit(Node **np)
-{
- Node *n;
-
- n = *np;
- if(n == N || !isideal(n->type))
- return;
- switch(consttype(n)) {
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- defaultlit(np, types[TINT]);
- break;
- }
- defaultlit(np, T);
-}
-
-static void
-typecheck1(Node **np, int top)
-{
- int et, aop, op, ptr;
- Node *n, *l, *r, *lo, *mid, *hi;
- NodeList *args;
- int ok, ntop;
- Type *t, *tp, *missing, *have, *badtype;
- Val v;
- char *why, *desc, descbuf[64];
- vlong x;
-
- n = *np;
-
- if(n->sym) {
- if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
- yyerror("use of builtin %S not in function call", n->sym);
- goto error;
- }
-
- typecheckdef(n);
- if(n->op == ONONAME)
- goto error;
- }
- *np = n;
-
-reswitch:
- ok = 0;
- switch(n->op) {
- default:
- // until typecheck is complete, do nothing.
- dump("typecheck", n);
- fatal("typecheck %O", n->op);
-
- /*
- * names
- */
- case OLITERAL:
- ok |= Erv;
- if(n->type == T && n->val.ctype == CTSTR)
- n->type = idealstring;
- goto ret;
-
- case ONONAME:
- ok |= Erv;
- goto ret;
-
- case ONAME:
- if(n->decldepth == 0)
- n->decldepth = decldepth;
- if(n->etype != 0) {
- ok |= Ecall;
- goto ret;
- }
- if(!(top & Easgn)) {
- // not a write to the variable
- if(isblank(n)) {
- yyerror("cannot use _ as value");
- goto error;
- }
- n->used = 1;
- }
- if(!(top &Ecall) && isunsafebuiltin(n)) {
- yyerror("%N is not an expression, must be called", n);
- goto error;
- }
- ok |= Erv;
- goto ret;
-
- case OPACK:
- yyerror("use of package %S without selector", n->sym);
- goto error;
-
- case ODDD:
- break;
-
- /*
- * types (OIND is with exprs)
- */
- case OTYPE:
- ok |= Etype;
- if(n->type == T)
- goto error;
- break;
-
- case OTARRAY:
- ok |= Etype;
- t = typ(TARRAY);
- l = n->left;
- r = n->right;
- if(l == nil) {
- t->bound = -1; // slice
- } else if(l->op == ODDD) {
- t->bound = -100; // to be filled in
- if(!(top&Ecomplit) && !n->diag) {
- t->broke = 1;
- n->diag = 1;
- yyerror("use of [...] array outside of array literal");
- }
- } else {
- l = typecheck(&n->left, Erv);
- switch(consttype(l)) {
- case CTINT:
- case CTRUNE:
- v = l->val;
- break;
- case CTFLT:
- v = toint(l->val);
- break;
- default:
- if(l->type != T && isint[l->type->etype] && l->op != OLITERAL)
- yyerror("non-constant array bound %N", l);
- else
- yyerror("invalid array bound %N", l);
- goto error;
- }
- t->bound = mpgetfix(v.u.xval);
- if(doesoverflow(v, types[TINT])) {
- yyerror("array bound is too large");
- goto error;
- } else if(t->bound < 0) {
- yyerror("array bound must be non-negative");
- goto error;
- }
- }
- typecheck(&r, Etype);
- if(r->type == T)
- goto error;
- t->type = r->type;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->right = N;
- if(t->bound != -100)
- checkwidth(t);
- break;
-
- case OTMAP:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- r = typecheck(&n->right, Etype);
- if(l->type == T || r->type == T)
- goto error;
- n->op = OTYPE;
- n->type = maptype(l->type, r->type);
- n->left = N;
- n->right = N;
- break;
-
- case OTCHAN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- t = typ(TCHAN);
- t->type = l->type;
- t->chan = n->etype;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->etype = 0;
- break;
-
- case OTSTRUCT:
- ok |= Etype;
- n->op = OTYPE;
- n->type = tostruct(n->list);
- if(n->type == T || n->type->broke)
- goto error;
- n->list = nil;
- break;
-
- case OTINTER:
- ok |= Etype;
- n->op = OTYPE;
- n->type = tointerface(n->list);
- if(n->type == T)
- goto error;
- break;
-
- case OTFUNC:
- ok |= Etype;
- n->op = OTYPE;
- n->type = functype(n->left, n->list, n->rlist);
- if(n->type == T)
- goto error;
- break;
-
- /*
- * type or expr
- */
- case OIND:
- ntop = Erv | Etype;
- if(!(top & Eaddr)) // The *x in &*x is not an indirect.
- ntop |= Eindir;
- ntop |= top & Ecomplit;
- l = typecheck(&n->left, ntop);
- if((t = l->type) == T)
- goto error;
- if(l->op == OTYPE) {
- ok |= Etype;
- n->op = OTYPE;
- n->type = ptrto(l->type);
- n->left = N;
- goto ret;
- }
- if(!isptr[t->etype]) {
- if(top & (Erv | Etop)) {
- yyerror("invalid indirect of %lN", n->left);
- goto error;
- }
- goto ret;
- }
- ok |= Erv;
- n->type = t->type;
- goto ret;
-
- /*
- * arithmetic exprs
- */
- case OASOP:
- ok |= Etop;
- l = typecheck(&n->left, Erv);
- r = typecheck(&n->right, Erv);
- checkassign(n, n->left);
- if(l->type == T || r->type == T)
- goto error;
- op = n->etype;
- goto arith;
-
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case ORSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case OSUB:
- case OXOR:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- op = n->op;
- goto arith;
-
- case OCOM:
- case OMINUS:
- case ONOT:
- case OPLUS:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- if((t = l->type) == T)
- goto error;
- if(!okfor[n->op][t->etype]) {
- yyerror("invalid operation: %O %T", n->op, t);
- goto error;
- }
- n->type = t;
- goto ret;
-
- /*
- * exprs
- */
- case OADDR:
- ok |= Erv;
- typecheck(&n->left, Erv | Eaddr);
- if(n->left->type == T)
- goto error;
- checklvalue(n->left, "take the address of");
- r = outervalue(n->left);
- for(l = n->left; l != r; l = l->left) {
- l->addrtaken = 1;
- if(l->closure)
- l->closure->addrtaken = 1;
- }
- if(l->orig != l && l->op == ONAME)
- fatal("found non-orig name node %N", l);
- l->addrtaken = 1;
- if(l->closure)
- l->closure->addrtaken = 1;
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- n->type = ptrto(t);
- goto ret;
-
- case OCOMPLIT:
- ok |= Erv;
- typecheckcomplit(&n);
- if(n->type == T)
- goto error;
- goto ret;
-
- case OXDOT:
- n = adddot(n);
- n->op = ODOT;
- if(n->left == N)
- goto error;
- // fall through
- case ODOT:
- typecheck(&n->left, Erv|Etype);
- defaultlit(&n->left, T);
- if(n->right->op != ONAME) {
- yyerror("rhs of . must be a name"); // impossible
- goto error;
- }
- if((t = n->left->type) == T) {
- adderrorname(n);
- goto error;
- }
- r = n->right;
-
- if(n->left->op == OTYPE) {
- if(!looktypedot(n, t, 0)) {
- if(looktypedot(n, t, 1))
- yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym);
- else
- yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym);
- goto error;
- }
- if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, n->right->sym);
- n->type = T;
- goto error;
- }
- n->op = ONAME;
- n->sym = n->right->sym;
- n->type = methodfunc(n->type, n->left->type);
- n->xoffset = 0;
- n->class = PFUNC;
- ok = Erv;
- goto ret;
- }
- if(isptr[t->etype] && t->type->etype != TINTER) {
- t = t->type;
- if(t == T)
- goto error;
- n->op = ODOTPTR;
- checkwidth(t);
- }
- if(isblank(n->right)) {
- yyerror("cannot refer to blank field or method");
- goto error;
- }
- if(!lookdot(n, t, 0)) {
- if(lookdot(n, t, 1))
- yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
- else
- yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym);
- goto error;
- }
- switch(n->op) {
- case ODOTINTER:
- case ODOTMETH:
- if(top&Ecall)
- ok |= Ecall;
- else {
- typecheckpartialcall(n, r);
- ok |= Erv;
- }
- break;
- default:
- ok |= Erv;
- break;
- }
- goto ret;
-
- case ODOTTYPE:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(!isinter(t)) {
- yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t);
- goto error;
- }
- if(n->right != N) {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- n->right = N;
- if(n->type == T)
- goto error;
- }
- if(n->type != T && n->type->etype != TINTER)
- if(!implements(n->type, t, &missing, &have, &ptr)) {
- if(have && have->sym == missing->sym)
- yyerror("impossible type assertion:\n\t%T does not implement %T (wrong type for %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else if(ptr)
- yyerror("impossible type assertion:\n\t%T does not implement %T (%S method has pointer receiver)",
- n->type, t, missing->sym);
- else if(have)
- yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else
- yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)",
- n->type, t, missing->sym);
- goto error;
- }
- goto ret;
-
- case OINDEX:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- typecheck(&n->right, Erv);
- r = n->right;
- if((t = l->type) == T || r->type == T)
- goto error;
- switch(t->etype) {
- default:
- yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
- goto error;
-
-
- case TSTRING:
- case TARRAY:
- indexlit(&n->right);
- if(t->etype == TSTRING)
- n->type = types[TUINT8];
- else
- n->type = t->type;
- why = "string";
- if(t->etype == TARRAY) {
- if(isfixedarray(t))
- why = "array";
- else
- why = "slice";
- }
- if(n->right->type != T && !isint[n->right->type->etype]) {
- yyerror("non-integer %s index %N", why, n->right);
- break;
- }
- if(isconst(n->right, CTINT)) {
- x = mpgetfix(n->right->val.u.xval);
- if(x < 0)
- yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
- else if(isfixedarray(t) && t->bound > 0 && x >= t->bound)
- yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
- else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len)
- yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len);
- else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
- yyerror("invalid %s index %N (index too large)", why, n->right);
- }
- break;
-
- case TMAP:
- n->etype = 0;
- defaultlit(&n->right, t->down);
- if(n->right->type != T)
- n->right = assignconv(n->right, t->down, "map index");
- n->type = t->type;
- n->op = OINDEXMAP;
- break;
- }
- goto ret;
-
- case ORECV:
- ok |= Etop | Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %N (receive from non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Crecv)) {
- yyerror("invalid operation: %N (receive from send-only type %T)", n, t);
- goto error;
- }
- n->type = t->type;
- goto ret;
-
- case OSEND:
- ok |= Etop;
- l = typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %N (send to non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Csend)) {
- yyerror("invalid operation: %N (send to receive-only type %T)", n, t);
- goto error;
- }
- defaultlit(&n->right, t->type);
- r = n->right;
- if(r->type == T)
- goto error;
- n->right = assignconv(r, l->type->type, "send");
- // TODO: more aggressive
- n->etype = 0;
- n->type = T;
- goto ret;
-
- case OSLICE:
- ok |= Erv;
- typecheck(&n->left, top);
- typecheck(&n->right->left, Erv);
- typecheck(&n->right->right, Erv);
- defaultlit(&n->left, T);
- indexlit(&n->right->left);
- indexlit(&n->right->right);
- l = n->left;
- if(isfixedarray(l->type)) {
- if(!islvalue(n->left)) {
- yyerror("invalid operation %N (slice of unaddressable value)", n);
- goto error;
- }
- n->left = nod(OADDR, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Erv);
- l = n->left;
- }
- if((t = l->type) == T)
- goto error;
- tp = nil;
- if(istype(t, TSTRING)) {
- n->type = t;
- n->op = OSLICESTR;
- } else if(isptr[t->etype] && isfixedarray(t->type)) {
- tp = t->type;
- n->type = typ(TARRAY);
- n->type->type = tp->type;
- n->type->bound = -1;
- dowidth(n->type);
- n->op = OSLICEARR;
- } else if(isslice(t)) {
- n->type = t;
- } else {
- yyerror("cannot slice %N (type %T)", l, t);
- goto error;
- }
- if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
- goto error;
- if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0)
- goto error;
- if(checksliceconst(lo, hi) < 0)
- goto error;
- goto ret;
-
- case OSLICE3:
- ok |= Erv;
- typecheck(&n->left, top);
- typecheck(&n->right->left, Erv);
- typecheck(&n->right->right->left, Erv);
- typecheck(&n->right->right->right, Erv);
- defaultlit(&n->left, T);
- indexlit(&n->right->left);
- indexlit(&n->right->right->left);
- indexlit(&n->right->right->right);
- l = n->left;
- if(isfixedarray(l->type)) {
- if(!islvalue(n->left)) {
- yyerror("invalid operation %N (slice of unaddressable value)", n);
- goto error;
- }
- n->left = nod(OADDR, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Erv);
- l = n->left;
- }
- if((t = l->type) == T)
- goto error;
- tp = nil;
- if(istype(t, TSTRING)) {
- yyerror("invalid operation %N (3-index slice of string)", n);
- goto error;
- }
- if(isptr[t->etype] && isfixedarray(t->type)) {
- tp = t->type;
- n->type = typ(TARRAY);
- n->type->type = tp->type;
- n->type->bound = -1;
- dowidth(n->type);
- n->op = OSLICE3ARR;
- } else if(isslice(t)) {
- n->type = t;
- } else {
- yyerror("cannot slice %N (type %T)", l, t);
- goto error;
- }
- if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
- goto error;
- if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0)
- goto error;
- if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0)
- goto error;
- if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0)
- goto error;
- goto ret;
-
- /*
- * call and call like
- */
- case OCALL:
- l = n->left;
- if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
- if(n->isddd)
- yyerror("invalid use of ... with builtin %N", l);
- n = r;
- goto reswitch;
- }
- typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
- n->diag |= n->left->diag;
- l = n->left;
- if(l->op == ONAME && l->etype != 0) {
- if(n->isddd && l->etype != OAPPEND)
- yyerror("invalid use of ... with builtin %N", l);
- // builtin: OLEN, OCAP, etc.
- n->op = l->etype;
- n->left = n->right;
- n->right = N;
- goto reswitch;
- }
- defaultlit(&n->left, T);
- l = n->left;
- if(l->op == OTYPE) {
- if(n->isddd || l->type->bound == -100) {
- if(!l->type->broke)
- yyerror("invalid use of ... in type conversion", l);
- n->diag = 1;
- }
- // pick off before type-checking arguments
- ok |= Erv;
- // turn CALL(type, arg) into CONV(arg) w/ type
- n->left = N;
- n->op = OCONV;
- n->type = l->type;
- if(onearg(n, "conversion to %T", l->type) < 0)
- goto error;
- goto doconv;
- }
-
- if(count(n->list) == 1 && !n->isddd)
- typecheck(&n->list->n, Erv | Efnstruct);
- else
- typechecklist(n->list, Erv);
- if((t = l->type) == T)
- goto error;
- checkwidth(t);
-
- switch(l->op) {
- case ODOTINTER:
- n->op = OCALLINTER;
- break;
-
- case ODOTMETH:
- n->op = OCALLMETH;
- // typecheckaste was used here but there wasn't enough
- // information further down the call chain to know if we
- // were testing a method receiver for unexported fields.
- // It isn't necessary, so just do a sanity check.
- tp = getthisx(t)->type->type;
- if(l->left == N || !eqtype(l->left->type, tp))
- fatal("method receiver");
- break;
-
- default:
- n->op = OCALLFUNC;
- if(t->etype != TFUNC) {
- yyerror("cannot call non-function %N (type %T)", l, t);
- goto error;
- }
- break;
- }
- if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf)
- desc = descbuf;
- else
- desc = "function argument";
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc);
- ok |= Etop;
- if(t->outtuple == 0)
- goto ret;
- ok |= Erv;
- if(t->outtuple == 1) {
- t = getoutargx(l->type)->type;
- if(t == T)
- goto error;
- if(t->etype == TFIELD)
- t = t->type;
- n->type = t;
- goto ret;
- }
- // multiple return
- if(!(top & (Efnstruct | Etop))) {
- yyerror("multiple-value %N() in single-value context", l);
- goto ret;
- }
- n->type = getoutargx(l->type);
- goto ret;
-
- case OCAP:
- case OLEN:
- case OREAL:
- case OIMAG:
- ok |= Erv;
- if(onearg(n, "%O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- t = l->type;
- if(t == T)
- goto error;
- switch(n->op) {
- case OCAP:
- if(!okforcap[t->etype])
- goto badcall1;
- break;
- case OLEN:
- if(!okforlen[t->etype])
- goto badcall1;
- break;
- case OREAL:
- case OIMAG:
- if(!iscomplex[t->etype])
- goto badcall1;
- if(isconst(l, CTCPLX)){
- r = n;
- if(n->op == OREAL)
- n = nodfltconst(&l->val.u.cval->real);
- else
- n = nodfltconst(&l->val.u.cval->imag);
- n->orig = r;
- }
- n->type = types[cplxsubtype(t->etype)];
- goto ret;
- }
- // might be constant
- switch(t->etype) {
- case TSTRING:
- if(isconst(l, CTSTR)) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], l->val.u.sval->len);
- r->orig = n;
- n = r;
- }
- break;
- case TARRAY:
- if(t->bound < 0) // slice
- break;
- if(callrecv(l)) // has call or receive
- break;
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], t->bound);
- r->orig = n;
- n = r;
- break;
- }
- n->type = types[TINT];
- goto ret;
-
- case OCOMPLEX:
- ok |= Erv;
- if(count(n->list) == 1) {
- typechecklist(n->list, Efnstruct);
- if(n->list->n->op != OCALLFUNC && n->list->n->op != OCALLMETH) {
- yyerror("invalid operation: complex expects two arguments");
- goto error;
- }
- t = n->list->n->left->type;
- if(t->outtuple != 2) {
- yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
- goto error;
- }
- t = n->list->n->type->type;
- l = t->nname;
- r = t->down->nname;
- } else {
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- if(l->type == T || r->type == T)
- goto error;
- n->left = l;
- n->right = r;
- }
- if(!eqtype(l->type, r->type)) {
- yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
- goto error;
- }
- switch(l->type->etype) {
- default:
- yyerror("invalid operation: %N (arguments have type %T, expected floating-point)", n, l->type, r->type);
- goto error;
- case TIDEAL:
- t = types[TIDEAL];
- break;
- case TFLOAT32:
- t = types[TCOMPLEX64];
- break;
- case TFLOAT64:
- t = types[TCOMPLEX128];
- break;
- }
- if(l->op == OLITERAL && r->op == OLITERAL) {
- // make it a complex literal
- r = nodcplxlit(l->val, r->val);
- r->orig = n;
- n = r;
- }
- n->type = t;
- goto ret;
-
- case OCLOSE:
- if(onearg(n, "%O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %N (non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Csend)) {
- yyerror("invalid operation: %N (cannot close receive-only channel)", n);
- goto error;
- }
- ok |= Etop;
- goto ret;
-
- case ODELETE:
- args = n->list;
- if(args == nil) {
- yyerror("missing arguments to delete");
- goto error;
- }
- if(args->next == nil) {
- yyerror("missing second (key) argument to delete");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to delete");
- goto error;
- }
- ok |= Etop;
- typechecklist(args, Erv);
- l = args->n;
- r = args->next->n;
- if(l->type != T && l->type->etype != TMAP) {
- yyerror("first argument to delete must be map; have %lT", l->type);
- goto error;
- }
- args->next->n = assignconv(r, l->type->down, "delete");
- goto ret;
-
- case OAPPEND:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing arguments to append");
- goto error;
- }
-
- if(count(args) == 1 && !n->isddd)
- typecheck(&args->n, Erv | Efnstruct);
- else
- typechecklist(args, Erv);
-
- if((t = args->n->type) == T)
- goto error;
-
- // Unpack multiple-return result before type-checking.
- if(istype(t, TSTRUCT) && t->funarg) {
- t = t->type;
- if(istype(t, TFIELD))
- t = t->type;
- }
-
- n->type = t;
- if(!isslice(t)) {
- if(isconst(args->n, CTNIL)) {
- yyerror("first argument to append must be typed slice; have untyped nil", t);
- goto error;
- }
- yyerror("first argument to append must be slice; have %lT", t);
- goto error;
- }
-
- if(n->isddd) {
- if(args->next == nil) {
- yyerror("cannot use ... on first argument to append");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to append");
- goto error;
- }
- if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
- defaultlit(&args->next->n, types[TSTRING]);
- goto ret;
- }
- args->next->n = assignconv(args->next->n, t->orig, "append");
- goto ret;
- }
- for(args=args->next; args != nil; args=args->next) {
- if(args->n->type == T)
- continue;
- args->n = assignconv(args->n, t->type, "append");
- }
- goto ret;
-
- case OCOPY:
- ok |= Etop|Erv;
- args = n->list;
- if(args == nil || args->next == nil) {
- yyerror("missing arguments to copy");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to copy");
- goto error;
- }
- n->left = args->n;
- n->right = args->next->n;
- n->list = nil;
- n->type = types[TINT];
- typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- if(n->left->type == T || n->right->type == T)
- goto error;
- defaultlit(&n->left, T);
- defaultlit(&n->right, T);
- if(n->left->type == T || n->right->type == T)
- goto error;
-
- // copy([]byte, string)
- if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
- if(eqtype(n->left->type->type, bytetype))
- goto ret;
- yyerror("arguments to copy have different element types: %lT and string", n->left->type);
- goto error;
- }
-
- if(!isslice(n->left->type) || !isslice(n->right->type)) {
- if(!isslice(n->left->type) && !isslice(n->right->type))
- yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
- else if(!isslice(n->left->type))
- yyerror("first argument to copy should be slice; have %lT", n->left->type);
- else
- yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
- goto error;
- }
- if(!eqtype(n->left->type->type, n->right->type->type)) {
- yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
- goto error;
- }
- goto ret;
-
- case OCONV:
- goto doconv;
-
- case OMAKE:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to make");
- goto error;
- }
- n->list = nil;
- l = args->n;
- args = args->next;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
-
- switch(t->etype) {
- default:
- yyerror("cannot make type %T", t);
- goto error;
-
- case TARRAY:
- if(!isslice(t)) {
- yyerror("cannot make type %T", t);
- goto error;
- }
- if(args == nil) {
- yyerror("missing len argument to make(%T)", t);
- goto error;
- }
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- r = N;
- if(args != nil) {
- r = args->n;
- args = args->next;
- typecheck(&r, Erv);
- }
- if(l->type == T || (r && r->type == T))
- goto error;
- et = checkmake(t, "len", l) < 0;
- et |= r && checkmake(t, "cap", r) < 0;
- if(et)
- goto error;
- if(isconst(l, CTINT) && r && isconst(r, CTINT) && mpcmpfixfix(l->val.u.xval, r->val.u.xval) > 0) {
- yyerror("len larger than cap in make(%T)", t);
- goto error;
- }
- n->left = l;
- n->right = r;
- n->op = OMAKESLICE;
- break;
-
- case TMAP:
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(checkmake(t, "size", l) < 0)
- goto error;
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKEMAP;
- break;
-
- case TCHAN:
- l = N;
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(checkmake(t, "buffer", l) < 0)
- goto error;
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKECHAN;
- break;
- }
- if(args != nil) {
- yyerror("too many arguments to make(%T)", t);
- n->op = OMAKE;
- goto error;
- }
- n->type = t;
- goto ret;
-
- case ONEW:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to new");
- goto error;
- }
- l = args->n;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
- if(args->next != nil) {
- yyerror("too many arguments to new(%T)", t);
- goto error;
- }
- n->left = l;
- n->type = ptrto(t);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- ok |= Etop;
- typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
- for(args=n->list; args; args=args->next) {
- // Special case for print: int constant is int64, not int.
- if(isconst(args->n, CTINT))
- defaultlit(&args->n, types[TINT64]);
- else
- defaultlit(&args->n, T);
- }
- goto ret;
-
- case OPANIC:
- ok |= Etop;
- if(onearg(n, "panic") < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, types[TINTER]);
- if(n->left->type == T)
- goto error;
- goto ret;
-
- case ORECOVER:
- ok |= Erv|Etop;
- if(n->list != nil) {
- yyerror("too many arguments to recover");
- goto error;
- }
- n->type = types[TINTER];
- goto ret;
-
- case OCLOSURE:
- ok |= Erv;
- typecheckclosure(n, top);
- if(n->type == T)
- goto error;
- goto ret;
-
- case OITAB:
- ok |= Erv;
- typecheck(&n->left, Erv);
- if((t = n->left->type) == T)
- goto error;
- if(t->etype != TINTER)
- fatal("OITAB of %T", t);
- n->type = ptrto(types[TUINTPTR]);
- goto ret;
-
- case OSPTR:
- ok |= Erv;
- typecheck(&n->left, Erv);
- if((t = n->left->type) == T)
- goto error;
- if(!isslice(t) && t->etype != TSTRING)
- fatal("OSPTR of %T", t);
- if(t->etype == TSTRING)
- n->type = ptrto(types[TUINT8]);
- else
- n->type = ptrto(t->type);
- goto ret;
-
- case OCLOSUREVAR:
- ok |= Erv;
- goto ret;
-
- case OCFUNC:
- ok |= Erv;
- typecheck(&n->left, Erv);
- n->type = types[TUINTPTR];
- goto ret;
-
- case OCONVNOP:
- ok |= Erv;
- typecheck(&n->left, Erv);
- goto ret;
-
- /*
- * statements
- */
- case OAS:
- ok |= Etop;
- typecheckas(n);
- // Code that creates temps does not bother to set defn, so do it here.
- if(n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0)
- n->left->defn = n;
- goto ret;
-
- case OAS2:
- ok |= Etop;
- typecheckas2(n);
- goto ret;
-
- case OBREAK:
- case OCONTINUE:
- case ODCL:
- case OEMPTY:
- case OGOTO:
- case OXFALL:
- case OVARKILL:
- ok |= Etop;
- goto ret;
-
- case OLABEL:
- ok |= Etop;
- decldepth++;
- goto ret;
-
- case ODEFER:
- ok |= Etop;
- typecheck(&n->left, Etop|Erv);
- if(!n->left->diag)
- checkdefergo(n);
- goto ret;
-
- case OPROC:
- ok |= Etop;
- typecheck(&n->left, Etop|Eproc|Erv);
- checkdefergo(n);
- goto ret;
-
- case OFOR:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- decldepth++;
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %lN used as for condition", n->ntest);
- typecheck(&n->nincr, Etop);
- typechecklist(n->nbody, Etop);
- decldepth--;
- goto ret;
-
- case OIF:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %lN used as if condition", n->ntest);
- typechecklist(n->nbody, Etop);
- typechecklist(n->nelse, Etop);
- goto ret;
-
- case ORETURN:
- ok |= Etop;
- if(count(n->list) == 1)
- typechecklist(n->list, Erv | Efnstruct);
- else
- typechecklist(n->list, Erv);
- if(curfn == N) {
- yyerror("return outside function");
- goto error;
- }
- if(curfn->type->outnamed && n->list == nil)
- goto ret;
- typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
- goto ret;
-
- case ORETJMP:
- ok |= Etop;
- goto ret;
-
- case OSELECT:
- ok |= Etop;
- typecheckselect(n);
- goto ret;
-
- case OSWITCH:
- ok |= Etop;
- typecheckswitch(n);
- goto ret;
-
- case ORANGE:
- ok |= Etop;
- typecheckrange(n);
- goto ret;
-
- case OTYPESW:
- yyerror("use of .(type) outside type switch");
- goto error;
-
- case OXCASE:
- ok |= Etop;
- typechecklist(n->list, Erv);
- typechecklist(n->nbody, Etop);
- goto ret;
-
- case ODCLFUNC:
- ok |= Etop;
- typecheckfunc(n);
- goto ret;
-
- case ODCLCONST:
- ok |= Etop;
- typecheck(&n->left, Erv);
- goto ret;
-
- case ODCLTYPE:
- ok |= Etop;
- typecheck(&n->left, Etype);
- if(!incannedimport)
- checkwidth(n->left->type);
- goto ret;
- }
- goto ret;
-
-arith:
- if(op == OLSH || op == ORSH)
- goto shift;
- // ideal mixed with non-ideal
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type == T || r->type == T)
- goto error;
- t = l->type;
- if(t->etype == TIDEAL)
- t = r->type;
- et = t->etype;
- if(et == TIDEAL)
- et = TINT;
- aop = 0;
- if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- // comparison is okay as long as one side is
- // assignable to the other. convert so they have
- // the same type.
- //
- // the only conversion that isn't a no-op is concrete == interface.
- // in that case, check comparability of the concrete type.
- // The conversion allocates, so only do it if the concrete type is huge.
- if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
- if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
- goto error;
- }
- dowidth(l->type);
- if(isinter(r->type) == isinter(l->type) || l->type->width >= 1<<16) {
- l = nod(aop, l, N);
- l->type = r->type;
- l->typecheck = 1;
- n->left = l;
- }
- t = r->type;
- goto converted;
- }
- if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
- if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
- goto error;
- }
- dowidth(r->type);
- if(isinter(r->type) == isinter(l->type) || r->type->width >= 1<<16) {
- r = nod(aop, r, N);
- r->type = l->type;
- r->typecheck = 1;
- n->right = r;
- }
- t = l->type;
- }
- converted:
- et = t->etype;
- }
- if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- defaultlit2(&l, &r, 1);
- if(n->op == OASOP && n->implicit) {
- yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
- goto error;
- }
- if(isinter(r->type) == isinter(l->type) || aop == 0) {
- yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
- goto error;
- }
- }
- if(!okfor[op][et]) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t));
- goto error;
- }
- // okfor allows any array == array, map == map, func == func.
- // restrict to slice/map/func == nil and nil == slice/map/func.
- if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (%T cannot be compared)", n, l->type);
- goto error;
- }
- if(isslice(l->type) && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (slice can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (map can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (func can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
- yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
- goto error;
- }
-
- t = l->type;
- if(iscmp[n->op]) {
- evconst(n);
- t = idealbool;
- if(n->op != OLITERAL) {
- defaultlit2(&l, &r, 1);
- n->left = l;
- n->right = r;
- }
- } else if(n->op == OANDAND || n->op == OOROR) {
- if(l->type == r->type)
- t = l->type;
- else if(l->type == idealbool)
- t = r->type;
- else if(r->type == idealbool)
- t = l->type;
- // non-comparison operators on ideal bools should make them lose their ideal-ness
- } else if(t == idealbool)
- t = types[TBOOL];
-
- if(et == TSTRING) {
- if(iscmp[n->op]) {
- n->etype = n->op;
- n->op = OCMPSTR;
- } else if(n->op == OADD) {
- // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
- n->op = OADDSTR;
- if(l->op == OADDSTR)
- n->list = l->list;
- else
- n->list = list1(l);
- if(r->op == OADDSTR)
- n->list = concat(n->list, r->list);
- else
- n->list = list(n->list, r);
- n->left = N;
- n->right = N;
- }
- }
- if(et == TINTER) {
- if(l->op == OLITERAL && l->val.ctype == CTNIL) {
- // swap for back end
- n->left = r;
- n->right = l;
- } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
- // leave alone for back end
- } else if(isinter(r->type) == isinter(l->type)) {
- n->etype = n->op;
- n->op = OCMPIFACE;
- }
- }
-
- if((op == ODIV || op == OMOD) && isconst(r, CTINT))
- if(mpcmpfixc(r->val.u.xval, 0) == 0) {
- yyerror("division by zero");
- goto error;
- }
-
- n->type = t;
- goto ret;
-
-shift:
- defaultlit(&r, types[TUINT]);
- n->right = r;
- t = r->type;
- if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
- goto error;
- }
- t = l->type;
- if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
- yyerror("invalid operation: %N (shift of type %T)", n, t);
- goto error;
- }
- // no defaultlit for left
- // the outer context gives the type
- n->type = l->type;
- goto ret;
-
-doconv:
- ok |= Erv;
- saveorignode(n);
- typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
- convlit1(&n->left, n->type, 1);
- if((t = n->left->type) == T || n->type == T)
- goto error;
- if((n->op = convertop(t, n->type, &why)) == 0) {
- if(!n->diag && !n->type->broke) {
- yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
- n->diag = 1;
- }
- n->op = OCONV;
- }
- switch(n->op) {
- case OCONVNOP:
- if(n->left->op == OLITERAL && n->type != types[TBOOL]) {
- r = nod(OXXX, N, N);
- n->op = OCONV;
- n->orig = r;
- *r = *n;
- n->op = OLITERAL;
- n->val = n->left->val;
- }
- break;
- case OSTRARRAYBYTE:
- // do not use stringtoarraylit.
- // generated code and compiler memory footprint is better without it.
- break;
- case OSTRARRAYRUNE:
- if(n->left->op == OLITERAL)
- stringtoarraylit(&n);
- break;
- }
- goto ret;
-
-ret:
- t = n->type;
- if(t && !t->funarg && n->op != OTYPE) {
- switch(t->etype) {
- case TFUNC: // might have TANY; wait until its called
- case TANY:
- case TFORW:
- case TIDEAL:
- case TNIL:
- case TBLANK:
- break;
- default:
- checkwidth(t);
- }
- }
-
- if(safemode && !incannedimport && !importpkg && !compiling_wrappers && t && t->etype == TUNSAFEPTR)
- yyerror("cannot use unsafe.Pointer");
-
- evconst(n);
- if(n->op == OTYPE && !(top & Etype)) {
- yyerror("type %T is not an expression", n->type);
- goto error;
- }
- if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%N is not a type", n);
- goto error;
- }
- // TODO(rsc): simplify
- if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
- yyerror("%N used as value", n);
- goto error;
- }
- if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
- if(n->diag == 0) {
- yyerror("%N evaluated but not used", n);
- n->diag = 1;
- }
- goto error;
- }
-
- /* TODO
- if(n->type == T)
- fatal("typecheck nil type");
- */
- goto out;
-
-badcall1:
- yyerror("invalid argument %lN for %O", n->left, n->op);
- goto error;
-
-error:
- n->type = T;
-
-out:
- *np = n;
-}
-
-static int
-checksliceindex(Node *l, Node *r, Type *tp)
-{
- Type *t;
-
- if((t = r->type) == T)
- return -1;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %N (type %T)", r, t);
- return -1;
- }
- if(r->op == OLITERAL) {
- if(mpgetfix(r->val.u.xval) < 0) {
- yyerror("invalid slice index %N (index must be non-negative)", r);
- return -1;
- } else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) {
- yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound);
- return -1;
- } else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) {
- yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len);
- return -1;
- } else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) {
- yyerror("invalid slice index %N (index too large)", r);
- return -1;
- }
- }
- return 0;
-}
-
-static int
-checksliceconst(Node *lo, Node *hi)
-{
- if(lo != N && hi != N && lo->op == OLITERAL && hi->op == OLITERAL
- && mpcmpfixfix(lo->val.u.xval, hi->val.u.xval) > 0) {
- yyerror("invalid slice index: %N > %N", lo, hi);
- return -1;
- }
- return 0;
-}
-
-static void
-checkdefergo(Node *n)
-{
- char *what;
-
- what = "defer";
- if(n->op == OPROC)
- what = "go";
-
- switch(n->left->op) {
- case OCALLINTER:
- case OCALLMETH:
- case OCALLFUNC:
- case OCLOSE:
- case OCOPY:
- case ODELETE:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case ORECOVER:
- // ok
- return;
- case OAPPEND:
- case OCAP:
- case OCOMPLEX:
- case OIMAG:
- case OLEN:
- case OMAKE:
- case OMAKESLICE:
- case OMAKECHAN:
- case OMAKEMAP:
- case ONEW:
- case OREAL:
- case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
- if(n->left->orig != N && n->left->orig->op == OCONV)
- break;
- yyerror("%s discards result of %N", what, n->left);
- return;
- }
-
- // type is broken or missing, most likely a method call on a broken type
- // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
- if(n->left->type == T || n->left->type->broke)
- return;
-
- if(!n->diag) {
- // The syntax made sure it was a call, so this must be
- // a conversion.
- n->diag = 1;
- yyerror("%s requires function call, not conversion", what);
- }
-}
-
-static void
-implicitstar(Node **nn)
-{
- Type *t;
- Node *n;
-
- // insert implicit * if needed for fixed array
- n = *nn;
- t = n->type;
- if(t == T || !isptr[t->etype])
- return;
- t = t->type;
- if(t == T)
- return;
- if(!isfixedarray(t))
- return;
- n = nod(OIND, n, N);
- n->implicit = 1;
- typecheck(&n, Erv);
- *nn = n;
-}
-
-static int
-onearg(Node *n, char *f, ...)
-{
- va_list arg;
- char *p;
-
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("missing argument to %s: %N", p, n);
- return -1;
- }
- if(n->list->next != nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("too many arguments to %s: %N", p, n);
- n->left = n->list->n;
- n->list = nil;
- return -1;
- }
- n->left = n->list->n;
- n->list = nil;
- return 0;
-}
-
-static int
-twoarg(Node *n)
-{
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- yyerror("missing argument to %O - %N", n->op, n);
- return -1;
- }
- n->left = n->list->n;
- if(n->list->next == nil) {
- yyerror("missing argument to %O - %N", n->op, n);
- n->list = nil;
- return -1;
- }
- if(n->list->next->next != nil) {
- yyerror("too many arguments to %O - %N", n->op, n);
- n->list = nil;
- return -1;
- }
- n->right = n->list->next->n;
- n->list = nil;
- return 0;
-}
-
-static Type*
-lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp)
-{
- Type *r;
-
- r = T;
- for(; f!=T; f=f->down) {
- if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
- return f;
- if(f->sym != s)
- continue;
- if(r != T) {
- if(errnode)
- yyerror("ambiguous selector %N", errnode);
- else if(isptr[t->etype])
- yyerror("ambiguous selector (%T).%S", t, s);
- else
- yyerror("ambiguous selector %T.%S", t, s);
- break;
- }
- r = f;
- }
- return r;
-}
-
-static int
-looktypedot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2;
- Sym *s;
-
- s = n->right->sym;
-
- if(t->etype == TINTER) {
- f1 = lookdot1(n, s, t, t->type, dostrcmp);
- if(f1 == T)
- return 0;
-
- n->right = methodname(n->right, t);
- n->xoffset = f1->width;
- n->type = f1->type;
- n->op = ODOTINTER;
- return 1;
- }
-
- // Find the base type: methtype will fail if t
- // is not of the form T or *T.
- f2 = methtype(t, 0);
- if(f2 == T)
- return 0;
-
- expandmeth(f2);
- f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp);
- if(f2 == T)
- return 0;
-
- // disallow T.m if m requires *T receiver
- if(isptr[getthisx(f2->type)->type->type->etype]
- && !isptr[t->etype]
- && f2->embedded != 2
- && !isifacemethod(f2->type)) {
- yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym);
- return 0;
- }
-
- n->right = methodname(n->right, t);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
-}
-
-static Type*
-derefall(Type* t)
-{
- while(t && t->etype == tptr)
- t = t->type;
- return t;
-}
-
-static int
-lookdot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2, *tt, *rcvr;
- Sym *s;
-
- s = n->right->sym;
-
- dowidth(t);
- f1 = T;
- if(t->etype == TSTRUCT || t->etype == TINTER)
- f1 = lookdot1(n, s, t, t->type, dostrcmp);
-
- f2 = T;
- if(n->left->type == t || n->left->type->sym == S) {
- f2 = methtype(t, 0);
- if(f2 != T) {
- // Use f2->method, not f2->xmethod: adddot has
- // already inserted all the necessary embedded dots.
- f2 = lookdot1(n, s, f2, f2->method, dostrcmp);
- }
- }
-
- if(f1 != T) {
- if(f2 != T)
- yyerror("%S is both field and method",
- n->right->sym);
- if(f1->width == BADWIDTH)
- fatal("lookdot badwidth %T %p", f1, f1);
- n->xoffset = f1->width;
- n->type = f1->type;
- n->paramfld = f1;
- if(t->etype == TINTER) {
- if(isptr[n->left->type->etype]) {
- n->left = nod(OIND, n->left, N); // implicitstar
- n->left->implicit = 1;
- typecheck(&n->left, Erv);
- }
- n->op = ODOTINTER;
- }
- return 1;
- }
-
- if(f2 != T) {
- tt = n->left->type;
- dowidth(tt);
- rcvr = getthisx(f2->type)->type->type;
- if(!eqtype(rcvr, tt)) {
- if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
- checklvalue(n->left, "call pointer method on");
- n->left = nod(OADDR, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) {
- n->left = nod(OIND, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) {
- yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
- while(tt->etype == tptr) {
- // Stop one level early for method with pointer receiver.
- if(rcvr->etype == tptr && tt->type->etype != tptr)
- break;
- n->left = nod(OIND, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- tt = tt->type;
- }
- } else {
- fatal("method mismatch: %T for %T", rcvr, tt);
- }
- }
- n->right = methodname(n->right, n->left->type);
- n->xoffset = f2->width;
- n->type = f2->type;
-// print("lookdot found [%p] %T\n", f2->type, f2->type);
- n->op = ODOTMETH;
- return 1;
- }
-
- return 0;
-}
-
-static int
-nokeys(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return 0;
- return 1;
-}
-
-static int
-hasddd(Type *t)
-{
- Type *tl;
-
- for(tl=t->type; tl; tl=tl->down) {
- if(tl->isddd)
- return 1;
- }
- return 0;
-}
-
-static int
-downcount(Type *t)
-{
- Type *tl;
- int n;
-
- n = 0;
- for(tl=t->type; tl; tl=tl->down) {
- n++;
- }
- return n;
-}
-
-/*
- * typecheck assignment: type list = expression list
- */
-static void
-typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
-{
- Type *t, *tl, *tn;
- Node *n;
- int lno;
- char *why;
- int n1, n2;
-
- lno = lineno;
-
- if(tstruct->broke)
- goto out;
-
- n = N;
- if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
- if(n->type->etype == TSTRUCT && n->type->funarg) {
- if(!hasddd(tstruct)) {
- n1 = downcount(tstruct);
- n2 = downcount(n->type);
- if(n2 > n1)
- goto toomany;
- if(n2 < n1)
- goto notenough;
- }
-
- tn = n->type->type;
- for(tl=tstruct->type; tl; tl=tl->down) {
- if(tl->isddd) {
- for(; tn; tn=tn->down) {
- if(assignop(tn->type, tl->type->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
- }
- }
- goto out;
- }
- if(tn == T)
- goto notenough;
- if(assignop(tn->type, tl->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
- }
- tn = tn->down;
- }
- if(tn != T)
- goto toomany;
- goto out;
- }
-
- n1 = downcount(tstruct);
- n2 = count(nl);
- if(!hasddd(tstruct)) {
- if(n2 > n1)
- goto toomany;
- if(n2 < n1)
- goto notenough;
- }
- else {
- if(!isddd) {
- if(n2 < n1-1)
- goto notenough;
- } else {
- if(n2 > n1)
- goto toomany;
- if(n2 < n1)
- goto notenough;
- }
- }
-
- for(tl=tstruct->type; tl; tl=tl->down) {
- t = tl->type;
- if(tl->isddd) {
- if(isddd) {
- if(nl == nil)
- goto notenough;
- if(nl->next != nil)
- goto toomany;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- goto out;
- }
- for(; nl; nl=nl->next) {
- n = nl->n;
- setlineno(nl->n);
- if(n->type != T)
- nl->n = assignconv(n, t->type, desc);
- }
- goto out;
- }
- if(nl == nil)
- goto notenough;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- nl = nl->next;
- }
- if(nl != nil)
- goto toomany;
- if(isddd) {
- if(call != N)
- yyerror("invalid use of ... in call to %N", call);
- else
- yyerror("invalid use of ... in %O", op);
- }
-
-out:
- lineno = lno;
- return;
-
-notenough:
- if(n == N || !n->diag) {
- if(call != N)
- yyerror("not enough arguments in call to %N", call);
- else
- yyerror("not enough arguments to %O", op);
- if(n != N)
- n->diag = 1;
- }
- goto out;
-
-toomany:
- if(call != N)
- yyerror("too many arguments in call to %N", call);
- else
- yyerror("too many arguments to %O", op);
- goto out;
-}
-
-/*
- * type check composite
- */
-
-static void
-fielddup(Node *n, Node **hash, ulong nhash)
-{
- uint h;
- char *s;
- Node *a;
-
- if(n->op != ONAME)
- fatal("fielddup: not ONAME");
- s = n->sym->name;
- h = stringhash(s)%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- if(strcmp(a->sym->name, s) == 0) {
- yyerror("duplicate field name in struct literal: %s", s);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static void
-keydup(Node *n, Node **hash, ulong nhash)
-{
- uint h;
- ulong b;
- double d;
- int i;
- Node *a, *orign;
- Node cmp;
- char *s;
-
- orign = n;
- if(n->op == OCONVIFACE)
- n = n->left;
- evconst(n);
- if(n->op != OLITERAL)
- return; // we dont check variables
-
- switch(n->val.ctype) {
- default: // unknown, bool, nil
- b = 23;
- break;
- case CTINT:
- case CTRUNE:
- b = mpgetfix(n->val.u.xval);
- break;
- case CTFLT:
- d = mpgetflt(n->val.u.fval);
- s = (char*)&d;
- b = 0;
- for(i=sizeof(d); i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- case CTSTR:
- b = 0;
- s = n->val.u.sval->s;
- for(i=n->val.u.sval->len; i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- }
-
- h = b%nhash;
- memset(&cmp, 0, sizeof(cmp));
- for(a=hash[h]; a!=N; a=a->ntest) {
- cmp.op = OEQ;
- cmp.left = n;
- b = 0;
- if(a->op == OCONVIFACE && orign->op == OCONVIFACE) {
- if(eqtype(a->left->type, n->type)) {
- cmp.right = a->left;
- evconst(&cmp);
- b = cmp.val.u.bval;
- }
- } else if(eqtype(a->type, n->type)) {
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
- }
- if(b) {
- yyerror("duplicate key %N in map literal", n);
- return;
- }
- }
- orign->ntest = hash[h];
- hash[h] = orign;
-}
-
-static void
-indexdup(Node *n, Node **hash, ulong nhash)
-{
- uint h;
- Node *a;
- ulong b, c;
-
- if(n->op != OLITERAL)
- fatal("indexdup: not OLITERAL");
-
- b = mpgetfix(n->val.u.xval);
- h = b%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- c = mpgetfix(a->val.u.xval);
- if(b == c) {
- yyerror("duplicate index in array literal: %ld", b);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static int
-prime(ulong h, ulong sr)
-{
- ulong n;
-
- for(n=3; n<=sr; n+=2)
- if(h%n == 0)
- return 0;
- return 1;
-}
-
-static ulong
-inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
-{
- ulong h, sr;
- NodeList *ll;
- int i;
-
- // count the number of entries
- h = 0;
- for(ll=n->list; ll; ll=ll->next)
- h++;
-
- // if the auto hash table is
- // large enough use it.
- if(h <= nautohash) {
- *hash = autohash;
- memset(*hash, 0, nautohash * sizeof(**hash));
- return nautohash;
- }
-
- // make hash size odd and 12% larger than entries
- h += h/8;
- h |= 1;
-
- // calculate sqrt of h
- sr = h/2;
- for(i=0; i<5; i++)
- sr = (sr + h/sr)/2;
-
- // check for primeality
- while(!prime(h, sr))
- h += 2;
-
- // build and return a throw-away hash table
- *hash = mal(h * sizeof(**hash));
- memset(*hash, 0, h * sizeof(**hash));
- return h;
-}
-
-static int
-iscomptype(Type *t)
-{
- switch(t->etype) {
- case TARRAY:
- case TSTRUCT:
- case TMAP:
- return 1;
- case TPTR32:
- case TPTR64:
- switch(t->type->etype) {
- case TARRAY:
- case TSTRUCT:
- case TMAP:
- return 1;
- }
- break;
- }
- return 0;
-}
-
-static void
-pushtype(Node *n, Type *t)
-{
- if(n == N || n->op != OCOMPLIT || !iscomptype(t))
- return;
-
- if(n->right == N) {
- n->right = typenod(t);
- n->implicit = 1; // don't print
- n->right->implicit = 1; // * is okay
- }
- else if(debug['s']) {
- typecheck(&n->right, Etype);
- if(n->right->type != T && eqtype(n->right->type, t))
- print("%L: redundant type: %T\n", n->lineno, t);
- }
-}
-
-static void
-typecheckcomplit(Node **np)
-{
- int bad, i, nerr;
- int64 length;
- Node *l, *n, *norig, *r, **hash;
- NodeList *ll;
- Type *t, *f;
- Sym *s, *s1;
- int32 lno;
- ulong nhash;
- Node *autohash[101];
-
- n = *np;
- lno = lineno;
-
- if(n->right == N) {
- if(n->list != nil)
- setlineno(n->list->n);
- yyerror("missing type in composite literal");
- goto error;
- }
-
- // Save original node (including n->right)
- norig = nod(n->op, N, N);
- *norig = *n;
-
- setlineno(n->right);
- l = typecheck(&n->right /* sic */, Etype|Ecomplit);
- if((t = l->type) == T)
- goto error;
- nerr = nerrors;
- n->type = t;
-
- if(isptr[t->etype]) {
- // For better or worse, we don't allow pointers as the composite literal type,
- // except when using the &T syntax, which sets implicit on the OIND.
- if(!n->right->implicit) {
- yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type);
- goto error;
- }
- // Also, the underlying type must be a struct, map, slice, or array.
- if(!iscomptype(t)) {
- yyerror("invalid pointer type %T for composite literal", t);
- goto error;
- }
- t = t->type;
- }
-
- switch(t->etype) {
- default:
- yyerror("invalid type for composite literal: %T", t);
- n->type = T;
- break;
-
- case TARRAY:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- length = 0;
- i = 0;
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- l = nod(OKEY, nodintconst(i), l);
- l->left->type = types[TINT];
- l->left->typecheck = 1;
- ll->n = l;
- }
-
- typecheck(&l->left, Erv);
- evconst(l->left);
- i = nonnegconst(l->left);
- if(i < 0 && !l->left->diag) {
- yyerror("array index must be non-negative integer constant");
- l->left->diag = 1;
- i = -(1<<30); // stay negative for a while
- }
- if(i >= 0)
- indexdup(l->left, hash, nhash);
- i++;
- if(i > length) {
- length = i;
- if(t->bound >= 0 && length > t->bound) {
- setlineno(l);
- yyerror("array index %lld out of bounds [0:%lld]", length-1, t->bound);
- t->bound = -1; // no more errors
- }
- }
-
- r = l->right;
- pushtype(r, t->type);
- typecheck(&r, Erv);
- defaultlit(&r, t->type);
- l->right = assignconv(r, t->type, "array element");
- }
- if(t->bound == -100)
- t->bound = length;
- if(t->bound < 0)
- n->right = nodintconst(length);
- n->op = OARRAYLIT;
- break;
-
- case TMAP:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- typecheck(&ll->n, Erv);
- yyerror("missing key in map literal");
- continue;
- }
-
- typecheck(&l->left, Erv);
- defaultlit(&l->left, t->down);
- l->left = assignconv(l->left, t->down, "map key");
- if (l->left->op != OCONV)
- keydup(l->left, hash, nhash);
-
- r = l->right;
- pushtype(r, t->type);
- typecheck(&r, Erv);
- defaultlit(&r, t->type);
- l->right = assignconv(r, t->type, "map value");
- }
- n->op = OMAPLIT;
- break;
-
- case TSTRUCT:
- bad = 0;
- if(n->list != nil && nokeys(n->list)) {
- // simple list of variables
- f = t->type;
- for(ll=n->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv);
- if(f == nil) {
- if(!bad++)
- yyerror("too many values in struct initializer");
- continue;
- }
- s = f->sym;
- if(s != nil && !exportname(s->name) && s->pkg != localpkg)
- yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
- // No pushtype allowed here. Must name fields for that.
- ll->n = assignconv(ll->n, f->type, "field value");
- ll->n = nod(OKEY, newname(f->sym), ll->n);
- ll->n->left->type = f;
- ll->n->left->typecheck = 1;
- f = f->down;
- }
- if(f != nil)
- yyerror("too few values in struct initializer");
- } else {
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- // keyed list
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- if(!bad++)
- yyerror("mixture of field:value and value initializers");
- typecheck(&ll->n, Erv);
- continue;
- }
- s = l->left->sym;
- if(s == S) {
- yyerror("invalid field name %N in struct initializer", l->left);
- typecheck(&l->right, Erv);
- continue;
- }
-
- // Sym might have resolved to name in other top-level
- // package, because of import dot. Redirect to correct sym
- // before we do the lookup.
- if(s->pkg != localpkg && exportname(s->name)) {
- s1 = lookup(s->name);
- if(s1->origpkg == s->pkg)
- s = s1;
- }
- f = lookdot1(nil, s, t, t->type, 0);
- if(f == nil) {
- yyerror("unknown %T field '%S' in struct literal", t, s);
- continue;
- }
- l->left = newname(s);
- l->left->typecheck = 1;
- l->left->type = f;
- s = f->sym;
- fielddup(newname(s), hash, nhash);
- r = l->right;
- // No pushtype allowed here. Tried and rejected.
- typecheck(&r, Erv);
- l->right = assignconv(r, f->type, "field value");
- }
- }
- n->op = OSTRUCTLIT;
- break;
- }
- if(nerr != nerrors)
- goto error;
-
- n->orig = norig;
- if(isptr[n->type->etype]) {
- n = nod(OPTRLIT, n, N);
- n->typecheck = 1;
- n->type = n->left->type;
- n->left->type = t;
- n->left->typecheck = 1;
- }
-
- n->orig = norig;
- *np = n;
- lineno = lno;
- return;
-
-error:
- n->type = T;
- *np = n;
- lineno = lno;
-}
-
-/*
- * lvalue etc
- */
-int
-islvalue(Node *n)
-{
- switch(n->op) {
- case OINDEX:
- if(isfixedarray(n->left->type))
- return islvalue(n->left);
- if(n->left->type != T && n->left->type->etype == TSTRING)
- return 0;
- // fall through
- case OIND:
- case ODOTPTR:
- case OCLOSUREVAR:
- case OPARAM:
- return 1;
- case ODOT:
- return islvalue(n->left);
- case ONAME:
- if(n->class == PFUNC)
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-checklvalue(Node *n, char *verb)
-{
- if(!islvalue(n))
- yyerror("cannot %s %N", verb, n);
-}
-
-void
-checkassign(Node *stmt, Node *n)
-{
- Node *r, *l;
-
- // Variables declared in ORANGE are assigned on every iteration.
- if(n->defn != stmt || stmt->op == ORANGE) {
- r = outervalue(n);
- for(l = n; l != r; l = l->left) {
- l->assigned = 1;
- if(l->closure)
- l->closure->assigned = 1;
- }
- l->assigned = 1;
- if(l->closure)
- l->closure->assigned = 1;
- }
-
- if(islvalue(n))
- return;
- if(n->op == OINDEXMAP) {
- n->etype = 1;
- return;
- }
-
- // have already complained about n being undefined
- if(n->op == ONONAME)
- return;
-
- yyerror("cannot assign to %N", n);
-}
-
-static void
-checkassignlist(Node *stmt, NodeList *l)
-{
- for(; l; l=l->next)
- checkassign(stmt, l->n);
-}
-
-// Check whether l and r are the same side effect-free expression,
-// so that it is safe to reuse one instead of computing both.
-int
-samesafeexpr(Node *l, Node *r)
-{
- if(l->op != r->op || !eqtype(l->type, r->type))
- return 0;
-
- switch(l->op) {
- case ONAME:
- case OCLOSUREVAR:
- return l == r;
-
- case ODOT:
- case ODOTPTR:
- return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left);
-
- case OIND:
- return samesafeexpr(l->left, r->left);
-
- case OINDEX:
- return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right);
- }
-
- return 0;
-}
-
-/*
- * type check assignment.
- * if this assignment is the definition of a var on the left side,
- * fill in the var's type.
- */
-
-static void
-typecheckas(Node *n)
-{
- // delicate little dance.
- // the definition of n may refer to this assignment
- // as its definition, in which case it will call typecheckas.
- // in that case, do not call typecheck back, or it will cycle.
- // if the variable has a type (ntype) then typechecking
- // will not look at defn, so it is okay (and desirable,
- // so that the conversion below happens).
- n->left = resolve(n->left);
- if(n->left->defn != n || n->left->ntype)
- typecheck(&n->left, Erv | Easgn);
-
- typecheck(&n->right, Erv);
- checkassign(n, n->left);
- if(n->right && n->right->type != T) {
- if(n->left->type != T)
- n->right = assignconv(n->right, n->left->type, "assignment");
- }
- if(n->left->defn == n && n->left->ntype == N) {
- defaultlit(&n->right, T);
- n->left->type = n->right->type;
- }
-
- // second half of dance.
- // now that right is done, typecheck the left
- // just to get it over with. see dance above.
- n->typecheck = 1;
- if(n->left->typecheck == 0)
- typecheck(&n->left, Erv | Easgn);
-
- // Recognize slices being updated in place, for better code generation later.
- // Don't rewrite if using race detector, to avoid needing to teach race detector
- // about this optimization.
- if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) {
- switch(n->right->op) {
- case OSLICE:
- case OSLICE3:
- case OSLICESTR:
- // For x = x[0:y], x can be updated in place, without touching pointer.
- // TODO(rsc): Reenable once it is actually updated in place without touching the pointer.
- if(0 && samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
- n->right->reslice = 1;
- break;
-
- case OAPPEND:
- // For x = append(x, ...), x can be updated in place when there is capacity,
- // without touching the pointer; otherwise the emitted code to growslice
- // can take care of updating the pointer, and only in that case.
- // TODO(rsc): Reenable once the emitted code does update the pointer.
- if(0 && n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
- n->right->reslice = 1;
- break;
- }
- }
-}
-
-static void
-checkassignto(Type *src, Node *dst)
-{
- char *why;
-
- if(assignop(src, dst->type, &why) == 0) {
- yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why);
- return;
- }
-}
-
-static void
-typecheckas2(Node *n)
-{
- int cl, cr;
- NodeList *ll, *lr;
- Node *l, *r;
- Iter s;
- Type *t;
-
- for(ll=n->list; ll; ll=ll->next) {
- // delicate little dance.
- ll->n = resolve(ll->n);
- if(ll->n->defn != n || ll->n->ntype)
- typecheck(&ll->n, Erv | Easgn);
- }
- cl = count(n->list);
- cr = count(n->rlist);
- if(cl > 1 && cr == 1)
- typecheck(&n->rlist->n, Erv | Efnstruct);
- else
- typechecklist(n->rlist, Erv);
- checkassignlist(n, n->list);
-
- if(cl == cr) {
- // easy
- for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
- if(ll->n->type != T && lr->n->type != T)
- lr->n = assignconv(lr->n, ll->n->type, "assignment");
- if(ll->n->defn == n && ll->n->ntype == N) {
- defaultlit(&lr->n, T);
- ll->n->type = lr->n->type;
- }
- }
- goto out;
- }
-
-
- l = n->list->n;
- r = n->rlist->n;
-
- // x,y,z = f()
- if(cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- if(r->type->etype != TSTRUCT || r->type->funarg == 0)
- break;
- cr = structcount(r->type);
- if(cr != cl)
- goto mismatch;
- n->op = OAS2FUNC;
- t = structfirst(&s, &r->type);
- for(ll=n->list; ll; ll=ll->next) {
- if(t->type != T && ll->n->type != T)
- checkassignto(t->type, ll->n);
- if(ll->n->defn == n && ll->n->ntype == N)
- ll->n->type = t->type;
- t = structnext(&s);
- }
- goto out;
- }
- }
-
- // x, ok = y
- if(cl == 2 && cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OINDEXMAP:
- case ORECV:
- case ODOTTYPE:
- switch(r->op) {
- case OINDEXMAP:
- n->op = OAS2MAPR;
- break;
- case ORECV:
- n->op = OAS2RECV;
- break;
- case ODOTTYPE:
- n->op = OAS2DOTTYPE;
- r->op = ODOTTYPE2;
- break;
- }
- if(l->type != T)
- checkassignto(r->type, l);
- if(l->defn == n)
- l->type = r->type;
- l = n->list->next->n;
- if(l->type != T && l->type->etype != TBOOL)
- checkassignto(types[TBOOL], l);
- if(l->defn == n && l->ntype == N)
- l->type = types[TBOOL];
- goto out;
- }
- }
-
-mismatch:
- yyerror("assignment count mismatch: %d = %d", cl, cr);
-
-out:
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-}
-
-/*
- * type check function definition
- */
-static void
-typecheckfunc(Node *n)
-{
- Type *t, *rcvr;
- NodeList *l;
-
- typecheck(&n->nname, Erv | Easgn);
- if((t = n->nname->type) == T)
- return;
- n->type = t;
- t->nname = n->nname;
- rcvr = getthisx(t)->type;
- if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
- addmethod(n->shortname->sym, t, 1, n->nname->nointerface);
-
- for(l=n->dcl; l; l=l->next)
- if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT))
- l->n->decldepth = 1;
-}
-
-static void
-stringtoarraylit(Node **np)
-{
- int32 i;
- NodeList *l;
- Strlit *s;
- char *p, *ep;
- Rune r;
- Node *nn, *n;
-
- n = *np;
- if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
- fatal("stringtoarraylit %N", n);
-
- s = n->left->val.u.sval;
- l = nil;
- p = s->s;
- ep = s->s + s->len;
- i = 0;
- if(n->type->type->etype == TUINT8) {
- // raw []byte
- while(p < ep)
- l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
- } else {
- // utf-8 []rune
- while(p < ep) {
- p += chartorune(&r, p);
- l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
- }
- }
- nn = nod(OCOMPLIT, N, typenod(n->type));
- nn->list = l;
- typecheck(&nn, Erv);
- *np = nn;
-}
-
-
-static int ntypecheckdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
- Node *nt;
- Type *t;
-
- nt = n->type->nname;
- typecheck(&nt, Etype);
- if(nt->type == T) {
- // type check failed; leave empty func
- n->type->etype = TFUNC;
- n->type->nod = N;
- return;
- }
-
- // If we have
- // type I interface {
- // M(_ int)
- // }
- // then even though I.M looks like it doesn't care about the
- // value of its argument, a specific implementation of I may
- // care. The _ would suppress the assignment to that argument
- // while generating a call, so remove it.
- for(t=getinargx(nt->type)->type; t; t=t->down) {
- if(t->sym != nil && strcmp(t->sym->name, "_") == 0)
- t->sym = nil;
- }
-
- *n->type = *nt->type;
- n->type->nod = N;
- checkwidth(n->type);
-}
-
-static NodeList *mapqueue;
-
-void
-copytype(Node *n, Type *t)
-{
- int maplineno, embedlineno, lno;
- NodeList *l;
-
- if(t->etype == TFORW) {
- // This type isn't computed yet; when it is, update n.
- t->copyto = list(t->copyto, n);
- return;
- }
-
- maplineno = n->type->maplineno;
- embedlineno = n->type->embedlineno;
-
- l = n->type->copyto;
- *n->type = *t;
-
- t = n->type;
- t->sym = n->sym;
- t->local = n->local;
- t->vargen = n->vargen;
- t->siggen = 0;
- t->method = nil;
- t->xmethod = nil;
- t->nod = N;
- t->printed = 0;
- t->deferwidth = 0;
- t->copyto = nil;
-
- // Update nodes waiting on this type.
- for(; l; l=l->next)
- copytype(l->n, t);
-
- // Double-check use of type as embedded type.
- lno = lineno;
- if(embedlineno) {
- lineno = embedlineno;
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- }
- lineno = lno;
-
- // Queue check for map until all the types are done settling.
- if(maplineno) {
- t->maplineno = maplineno;
- mapqueue = list(mapqueue, n);
- }
-}
-
-static void
-typecheckdeftype(Node *n)
-{
- int lno;
- Type *t;
- NodeList *l;
-
- ntypecheckdeftype++;
- lno = lineno;
- setlineno(n);
- n->type->sym = n->sym;
- n->typecheck = 1;
- typecheck(&n->ntype, Etype);
- if((t = n->ntype->type) == T) {
- n->diag = 1;
- n->type = T;
- goto ret;
- }
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
-
- // copy new type and clear fields
- // that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
- copytype(n, t);
-
-ret:
- lineno = lno;
-
- // if there are no type definitions going on, it's safe to
- // try to resolve the method types for the interfaces
- // we just read.
- if(ntypecheckdeftype == 1) {
- while((l = methodqueue) != nil) {
- methodqueue = nil;
- for(; l; l=l->next)
- domethod(l->n);
- }
- for(l=mapqueue; l; l=l->next) {
- lineno = l->n->type->maplineno;
- maptype(l->n->type, types[TBOOL]);
- }
- lineno = lno;
- }
- ntypecheckdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
- if(ntypecheckdeftype == 0) {
- domethod(n);
- return;
- }
- methodqueue = list(methodqueue, n);
-}
-
-Node*
-typecheckdef(Node *n)
-{
- int lno, nerrors0;
- Node *e;
- Type *t;
- NodeList *l;
-
- lno = lineno;
- setlineno(n);
-
- if(n->op == ONONAME) {
- if(!n->diag) {
- n->diag = 1;
- if(n->lineno != 0)
- lineno = n->lineno;
- // Note: adderrorname looks for this string and
- // adds context about the outer expression
- yyerror("undefined: %S", n->sym);
- }
- return n;
- }
-
- if(n->walkdef == 1)
- return n;
-
- l = mal(sizeof *l);
- l->n = n;
- l->next = typecheckdefstack;
- typecheckdefstack = l;
-
- if(n->walkdef == 2) {
- flusherrors();
- print("typecheckdef loop:");
- for(l=typecheckdefstack; l; l=l->next)
- print(" %S", l->n->sym);
- print("\n");
- fatal("typecheckdef loop");
- }
- n->walkdef = 2;
-
- if(n->type != T || n->sym == S) // builtin or no name
- goto ret;
-
- switch(n->op) {
- default:
- fatal("typecheckdef %O", n->op);
-
- case OGOTO:
- case OLABEL:
- // not really syms
- break;
-
- case OLITERAL:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- n->ntype = N;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- e = n->defn;
- n->defn = N;
- if(e == N) {
- lineno = n->lineno;
- dump("typecheckdef nil defn", n);
- yyerror("xxx");
- }
- typecheck(&e, Erv | Eiota);
- if(isconst(e, CTNIL)) {
- yyerror("const initializer cannot be nil");
- goto ret;
- }
- if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
- if(!e->diag) {
- yyerror("const initializer %N is not a constant", e);
- e->diag = 1;
- }
- goto ret;
- }
- t = n->type;
- if(t != T) {
- if(!okforconst[t->etype]) {
- yyerror("invalid constant type %T", t);
- goto ret;
- }
- if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %lN as type %T in const initializer", e, t);
- goto ret;
- }
- convlit(&e, t);
- }
- n->val = e->val;
- n->type = e->type;
- break;
-
- case ONAME:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
-
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- if(n->type != T)
- break;
- if(n->defn == N) {
- if(n->etype != 0) // like OPRINTN
- break;
- if(nsavederrors+nerrors > 0) {
- // Can have undefined variables in x := foo
- // that make x have an n->ndefn == nil.
- // If there are other errors anyway, don't
- // bother adding to the noise.
- break;
- }
- fatal("var without type, init: %S", n->sym);
- }
- if(n->defn->op == ONAME) {
- typecheck(&n->defn, Erv);
- n->type = n->defn->type;
- break;
- }
- typecheck(&n->defn, Etop); // fills in n->type
- break;
-
- case OTYPE:
- if(curfn)
- defercheckwidth();
- n->walkdef = 1;
- n->type = typ(TFORW);
- n->type->sym = n->sym;
- nerrors0 = nerrors;
- typecheckdeftype(n);
- if(n->type->etype == TFORW && nerrors > nerrors0) {
- // Something went wrong during type-checking,
- // but it was reported. Silence future errors.
- n->type->broke = 1;
- }
- if(curfn)
- resumecheckwidth();
- break;
-
- case OPACK:
- // nothing to see here
- break;
- }
-
-ret:
- if(n->op != OLITERAL && n->type != T && isideal(n->type))
- fatal("got %T for %N", n->type, n);
- if(typecheckdefstack->n != n)
- fatal("typecheckdefstack mismatch");
- l = typecheckdefstack;
- typecheckdefstack = l->next;
-
- lineno = lno;
- n->walkdef = 1;
- return n;
-}
-
-static int
-checkmake(Type *t, char *arg, Node *n)
-{
- if(n->op == OLITERAL) {
- switch(n->val.ctype) {
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- n->val = toint(n->val);
- if(mpcmpfixc(n->val.u.xval, 0) < 0) {
- yyerror("negative %s argument in make(%T)", arg, t);
- return -1;
- }
- if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
- yyerror("%s argument too large in make(%T)", arg, t);
- return -1;
- }
-
- // Delay defaultlit until after we've checked range, to avoid
- // a redundant "constant NNN overflows int" error.
- defaultlit(&n, types[TINT]);
- return 0;
- default:
- break;
- }
- }
-
- if(!isint[n->type->etype] && n->type->etype != TIDEAL) {
- yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
- return -1;
- }
-
- // Defaultlit still necessary for non-constant: n might be 1<<k.
- defaultlit(&n, types[TINT]);
-
- return 0;
-}
-
-static void markbreaklist(NodeList*, Node*);
-
-static void
-markbreak(Node *n, Node *implicit)
-{
- Label *lab;
-
- if(n == N)
- return;
-
- switch(n->op) {
- case OBREAK:
- if(n->left == N) {
- if(implicit)
- implicit->hasbreak = 1;
- } else {
- lab = n->left->sym->label;
- if(lab != L)
- lab->def->hasbreak = 1;
- }
- break;
-
- case OFOR:
- case OSWITCH:
- case OTYPESW:
- case OSELECT:
- case ORANGE:
- implicit = n;
- // fall through
-
- default:
- markbreak(n->left, implicit);
- markbreak(n->right, implicit);
- markbreak(n->ntest, implicit);
- markbreak(n->nincr, implicit);
- markbreaklist(n->ninit, implicit);
- markbreaklist(n->nbody, implicit);
- markbreaklist(n->nelse, implicit);
- markbreaklist(n->list, implicit);
- markbreaklist(n->rlist, implicit);
- break;
- }
-}
-
-static void
-markbreaklist(NodeList *l, Node *implicit)
-{
- Node *n;
- Label *lab;
-
- for(; l; l=l->next) {
- n = l->n;
- if(n->op == OLABEL && l->next && n->defn == l->next->n) {
- switch(n->defn->op) {
- case OFOR:
- case OSWITCH:
- case OTYPESW:
- case OSELECT:
- case ORANGE:
- lab = mal(sizeof *lab);
- lab->def = n->defn;
- n->left->sym->label = lab;
- markbreak(n->defn, n->defn);
- n->left->sym->label = L;
- l = l->next;
- continue;
- }
- }
- markbreak(n, implicit);
- }
-}
-
-static int
-isterminating(NodeList *l, int top)
-{
- int def;
- Node *n;
-
- if(l == nil)
- return 0;
- if(top) {
- while(l->next && l->n->op != OLABEL)
- l = l->next;
- markbreaklist(l, nil);
- }
- while(l->next)
- l = l->next;
- n = l->n;
-
- if(n == N)
- return 0;
-
- switch(n->op) {
- // NOTE: OLABEL is treated as a separate statement,
- // not a separate prefix, so skipping to the last statement
- // in the block handles the labeled statement case by
- // skipping over the label. No case OLABEL here.
-
- case OBLOCK:
- return isterminating(n->list, 0);
-
- case OGOTO:
- case ORETURN:
- case ORETJMP:
- case OPANIC:
- case OXFALL:
- return 1;
-
- case OFOR:
- if(n->ntest != N)
- return 0;
- if(n->hasbreak)
- return 0;
- return 1;
-
- case OIF:
- return isterminating(n->nbody, 0) && isterminating(n->nelse, 0);
-
- case OSWITCH:
- case OTYPESW:
- case OSELECT:
- if(n->hasbreak)
- return 0;
- def = 0;
- for(l=n->list; l; l=l->next) {
- if(!isterminating(l->n->nbody, 0))
- return 0;
- if(l->n->list == nil) // default
- def = 1;
- }
- if(n->op != OSELECT && !def)
- return 0;
- return 1;
- }
-
- return 0;
-}
-
-void
-checkreturn(Node *fn)
-{
- if(fn->type->outtuple && fn->nbody != nil)
- if(!isterminating(fn->nbody, 1))
- yyerrorl(fn->endlineno, "missing return at end of function");
-}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
deleted file mode 100644
index 95d212e92b..0000000000
--- a/src/cmd/gc/unsafe.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * look for
- * unsafe.Sizeof
- * unsafe.Offsetof
- * unsafe.Alignof
- * rewrite with a constant
- */
-Node*
-unsafenmagic(Node *nn)
-{
- Node *r, *n, *base, *r1;
- Sym *s;
- Type *t, *tr;
- vlong v;
- Val val;
- Node *fn;
- NodeList *args;
-
- fn = nn->left;
- args = nn->list;
-
- if(safemode || fn == N || fn->op != ONAME)
- goto no;
- if((s = fn->sym) == S)
- goto no;
- if(s->pkg != unsafepkg)
- goto no;
-
- if(args == nil) {
- yyerror("missing argument for %S", s);
- goto no;
- }
- r = args->n;
-
- if(strcmp(s->name, "Sizeof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
- dowidth(tr);
- v = tr->width;
- goto yes;
- }
- if(strcmp(s->name, "Offsetof") == 0) {
- // must be a selector.
- if(r->op != OXDOT)
- goto bad;
- // Remember base of selector to find it back after dot insertion.
- // Since r->left may be mutated by typechecking, check it explicitly
- // first to track it correctly.
- typecheck(&r->left, Erv);
- base = r->left;
- typecheck(&r, Erv);
- switch(r->op) {
- case ODOT:
- case ODOTPTR:
- break;
- case OCALLPART:
- yyerror("invalid expression %N: argument is a method value", nn);
- v = 0;
- goto ret;
- default:
- goto bad;
- }
- v = 0;
- // add offsets for inserted dots.
- for(r1=r; r1->left!=base; r1=r1->left) {
- switch(r1->op) {
- case ODOT:
- v += r1->xoffset;
- break;
- case ODOTPTR:
- yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
- goto ret;
- default:
- dump("unsafenmagic", r);
- fatal("impossible %#O node after dot insertion", r1->op);
- goto bad;
- }
- }
- v += r1->xoffset;
- goto yes;
- }
- if(strcmp(s->name, "Alignof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
-
- // make struct { byte; T; }
- t = typ(TSTRUCT);
- t->type = typ(TFIELD);
- t->type->type = types[TUINT8];
- t->type->down = typ(TFIELD);
- t->type->down->type = tr;
- // compute struct widths
- dowidth(t);
-
- // the offset of T is its required alignment
- v = t->type->down->width;
- goto yes;
- }
-
-no:
- return N;
-
-bad:
- yyerror("invalid expression %N", nn);
- v = 0;
- goto ret;
-
-yes:
- if(args->next != nil)
- yyerror("extra arguments for %S", s);
-ret:
- // any side effects disappear; ignore init
- val.ctype = CTINT;
- val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(val.u.xval, v);
- n = nod(OLITERAL, N, N);
- n->orig = nn;
- n->val = val;
- n->type = types[TUINTPTR];
- nn->type = types[TUINTPTR];
- return n;
-}
-
-int
-isunsafebuiltin(Node *n)
-{
- if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg)
- return 0;
- if(strcmp(n->sym->name, "Sizeof") == 0)
- return 1;
- if(strcmp(n->sym->name, "Offsetof") == 0)
- return 1;
- if(strcmp(n->sym->name, "Alignof") == 0)
- return 1;
- return 0;
-}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
deleted file mode 100644
index c3c627815a..0000000000
--- a/src/cmd/gc/unsafe.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-// +build ignore
-
-package PACKAGE
-
-type Pointer uintptr // not really; filled in by compiler
-
-// return types here are ignored; see unsafe.c
-func Offsetof(any) uintptr
-func Sizeof(any) uintptr
-func Alignof(any) uintptr
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
deleted file mode 100644
index 50dae8ca68..0000000000
--- a/src/cmd/gc/walk.c
+++ /dev/null
@@ -1,4189 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-#include "../../runtime/mgc0.h"
-
-static Node* walkprint(Node*, NodeList**);
-static Node* writebarrierfn(char*, Type*, Type*);
-static Node* applywritebarrier(Node*, NodeList**);
-static Node* mapfn(char*, Type*);
-static Node* mapfndel(char*, Type*);
-static Node* ascompatee1(int, Node*, Node*, NodeList**);
-static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
-static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
-static NodeList* ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**);
-static Node* convas(Node*, NodeList**);
-static void heapmoves(void);
-static NodeList* paramstoheap(Type **argin, int out);
-static NodeList* reorder1(NodeList*);
-static NodeList* reorder3(NodeList*);
-static Node* addstr(Node*, NodeList**);
-static Node* appendslice(Node*, NodeList**);
-static Node* append(Node*, NodeList**);
-static Node* copyany(Node*, NodeList**, int);
-static Node* sliceany(Node*, NodeList**);
-static void walkcompare(Node**, NodeList**);
-static void walkrotate(Node**);
-static void walkmul(Node**, NodeList**);
-static void walkdiv(Node**, NodeList**);
-static int bounded(Node*, int64);
-static Mpint mpzero;
-static void walkprintfunc(Node**, NodeList**);
-
-// The constant is known to runtime.
-enum
-{
- tmpstringbufsize = 32,
-};
-
-void
-walk(Node *fn)
-{
- char s[50];
- NodeList *l;
- int lno;
-
- curfn = fn;
-
- if(debug['W']) {
- snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
-
- lno = lineno;
-
- // Final typecheck for any unused variables.
- // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
- for(l=fn->dcl; l; l=l->next)
- if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
- typecheck(&l->n, Erv | Easgn);
-
- // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
- for(l=fn->dcl; l; l=l->next)
- if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
- l->n->defn->left->used++;
-
- for(l=fn->dcl; l; l=l->next) {
- if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
- continue;
- if(l->n->defn && l->n->defn->op == OTYPESW) {
- if(l->n->defn->left->used)
- continue;
- lineno = l->n->defn->left->lineno;
- yyerror("%S declared and not used", l->n->sym);
- l->n->defn->left->used = 1; // suppress repeats
- } else {
- lineno = l->n->lineno;
- yyerror("%S declared and not used", l->n->sym);
- }
- }
-
- lineno = lno;
- if(nerrors != 0)
- return;
- walkstmtlist(curfn->nbody);
- if(debug['W']) {
- snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
- heapmoves();
- if(debug['W'] && curfn->enter != nil) {
- snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
- dumplist(s, curfn->enter);
- }
-}
-
-
-void
-walkstmtlist(NodeList *l)
-{
- for(; l; l=l->next)
- walkstmt(&l->n);
-}
-
-static int
-samelist(NodeList *a, NodeList *b)
-{
- for(; a && b; a=a->next, b=b->next)
- if(a->n != b->n)
- return 0;
- return a == b;
-}
-
-static int
-paramoutheap(Node *fn)
-{
- NodeList *l;
-
- for(l=fn->dcl; l; l=l->next) {
- switch(l->n->class) {
- case PPARAMOUT:
- case PPARAMOUT|PHEAP:
- return l->n->addrtaken;
- case PAUTO:
- case PAUTO|PHEAP:
- // stop early - parameters are over
- return 0;
- }
- }
- return 0;
-}
-
-// adds "adjust" to all the argument locations for the call n.
-// n must be a defer or go node that has already been walked.
-static void
-adjustargs(Node *n, int adjust)
-{
- Node *callfunc, *arg, *lhs;
- NodeList *args;
-
- callfunc = n->left;
- for(args = callfunc->list; args != 0; args = args->next) {
- arg = args->n;
- if(arg->op != OAS)
- yyerror("call arg not assignment");
- lhs = arg->left;
- if(lhs->op == ONAME) {
- // This is a temporary introduced by reorder1.
- // The real store to the stack appears later in the arg list.
- continue;
- }
- if(lhs->op != OINDREG) {
- yyerror("call argument store does not use OINDREG");
- }
- // can't really check this in machine-indep code.
- //if(lhs->val.u.reg != D_SP)
- // yyerror("call arg assign not indreg(SP)");
- lhs->xoffset += adjust;
- }
-}
-
-void
-walkstmt(Node **np)
-{
- NodeList *init;
- NodeList *ll, *rl;
- int cl;
- Node *n, *f;
-
- n = *np;
- if(n == N)
- return;
- if(n->dodata == 2) // don't walk, generated by anylit.
- return;
-
- setlineno(n);
-
- walkstmtlist(n->ninit);
-
- switch(n->op) {
- default:
- if(n->op == ONAME)
- yyerror("%S is not a top level statement", n->sym);
- else
- yyerror("%O is not a top level statement", n->op);
- dump("nottop", n);
- break;
-
- case OAS:
- case OASOP:
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2RECV:
- case OAS2FUNC:
- case OAS2MAPR:
- case OCLOSE:
- case OCOPY:
- case OCALLMETH:
- case OCALLINTER:
- case OCALL:
- case OCALLFUNC:
- case ODELETE:
- case OSEND:
- case OPRINT:
- case OPRINTN:
- case OPANIC:
- case OEMPTY:
- case ORECOVER:
- if(n->typecheck == 0)
- fatal("missing typecheck: %+N", n);
- init = n->ninit;
- n->ninit = nil;
- walkexpr(&n, &init);
- addinit(&n, init);
- if((*np)->op == OCOPY && n->op == OCONVNOP)
- n->op = OEMPTY; // don't leave plain values as statements.
- break;
-
- case ORECV:
- // special case for a receive where we throw away
- // the value received.
- if(n->typecheck == 0)
- fatal("missing typecheck: %+N", n);
- init = n->ninit;
- n->ninit = nil;
-
- walkexpr(&n->left, &init);
- n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil());
- walkexpr(&n, &init);
-
- addinit(&n, init);
- break;
-
- case OBREAK:
- case ODCL:
- case OCONTINUE:
- case OFALL:
- case OGOTO:
- case OLABEL:
- case ODCLCONST:
- case ODCLTYPE:
- case OCHECKNIL:
- case OVARKILL:
- break;
-
- case OBLOCK:
- walkstmtlist(n->list);
- break;
-
- case OXCASE:
- yyerror("case statement out of place");
- n->op = OCASE;
- case OCASE:
- walkstmt(&n->right);
- break;
-
- case ODEFER:
- hasdefer = 1;
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkprintfunc(&n->left, &n->ninit);
- break;
- case OCOPY:
- n->left = copyany(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- // make room for size & fn arguments.
- adjustargs(n, 2 * widthptr);
- break;
-
- case OFOR:
- if(n->ntest != N) {
- walkstmtlist(n->ntest->ninit);
- init = n->ntest->ninit;
- n->ntest->ninit = nil;
- walkexpr(&n->ntest, &init);
- addinit(&n->ntest, init);
- }
- walkstmt(&n->nincr);
- walkstmtlist(n->nbody);
- break;
-
- case OIF:
- walkexpr(&n->ntest, &n->ninit);
- walkstmtlist(n->nbody);
- walkstmtlist(n->nelse);
- break;
-
- case OPROC:
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkprintfunc(&n->left, &n->ninit);
- break;
- case OCOPY:
- n->left = copyany(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- // make room for size & fn arguments.
- adjustargs(n, 2 * widthptr);
- break;
-
- case ORETURN:
- walkexprlist(n->list, &n->ninit);
- if(n->list == nil)
- break;
- if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
- // assign to the function out parameters,
- // so that reorder3 can fix up conflicts
- rl = nil;
- for(ll=curfn->dcl; ll != nil; ll=ll->next) {
- cl = ll->n->class & ~PHEAP;
- if(cl == PAUTO)
- break;
- if(cl == PPARAMOUT)
- rl = list(rl, ll->n);
- }
- if(samelist(rl, n->list)) {
- // special return in disguise
- n->list = nil;
- break;
- }
- if(count(n->list) == 1 && count(rl) > 1) {
- // OAS2FUNC in disguise
- f = n->list->n;
- if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
- fatal("expected return of call, have %N", f);
- n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
- break;
- }
-
- // move function calls out, to make reorder3's job easier.
- walkexprlistsafe(n->list, &n->ninit);
- ll = ascompatee(n->op, rl, n->list, &n->ninit);
- n->list = reorder3(ll);
- break;
- }
- ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
- n->list = ll;
- break;
-
- case ORETJMP:
- break;
-
- case OSELECT:
- walkselect(n);
- break;
-
- case OSWITCH:
- walkswitch(n);
- break;
-
- case ORANGE:
- walkrange(n);
- break;
-
- case OXFALL:
- yyerror("fallthrough statement out of place");
- n->op = OFALL;
- break;
- }
-
- if(n->op == ONAME)
- fatal("walkstmt ended up with name: %+N", n);
-
- *np = n;
-}
-
-
-/*
- * walk the whole tree of the body of an
- * expression or simple statement.
- * the types expressions are calculated.
- * compile-time constants are evaluated.
- * complex side effects like statements are appended to init
- */
-
-void
-walkexprlist(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next)
- walkexpr(&l->n, init);
-}
-
-void
-walkexprlistsafe(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next) {
- l->n = safeexpr(l->n, init);
- walkexpr(&l->n, init);
- }
-}
-
-void
-walkexprlistcheap(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next) {
- l->n = cheapexpr(l->n, init);
- walkexpr(&l->n, init);
- }
-}
-
-void
-walkexpr(Node **np, NodeList **init)
-{
- Node *r, *l, *var, *a, *ok;
- Node *map, *key;
- NodeList *ll, *lr;
- Type *t;
- int et, old_safemode;
- int64 v;
- int32 lno;
- Node *n, *fn, *n1, *n2;
- Sym *sym;
- char buf[100], *p, *from, *to;
-
- n = *np;
-
- if(n == N)
- return;
-
- if(init == &n->ninit) {
- // not okay to use n->ninit when walking n,
- // because we might replace n with some other node
- // and would lose the init list.
- fatal("walkexpr init == &n->ninit");
- }
-
- if(n->ninit != nil) {
- walkstmtlist(n->ninit);
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- }
-
- // annoying case - not typechecked
- if(n->op == OKEY) {
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- return;
- }
-
- lno = setlineno(n);
-
- if(debug['w'] > 1)
- dump("walk-before", n);
-
- if(n->typecheck != 1)
- fatal("missed typecheck: %+N\n", n);
-
- switch(n->op) {
- default:
- dump("walk", n);
- fatal("walkexpr: switch 1 unknown op %+hN", n);
- break;
-
- case OTYPE:
- case ONONAME:
- case OINDREG:
- case OEMPTY:
- case OPARAM:
- goto ret;
-
- case ONOT:
- case OMINUS:
- case OPLUS:
- case OCOM:
- case OREAL:
- case OIMAG:
- case ODOTMETH:
- case ODOTINTER:
- walkexpr(&n->left, init);
- goto ret;
-
- case OIND:
- walkexpr(&n->left, init);
- goto ret;
-
- case ODOT:
- usefield(n);
- walkexpr(&n->left, init);
- goto ret;
-
- case ODOTPTR:
- usefield(n);
- if(n->op == ODOTPTR && n->left->type->type->width == 0) {
- // No actual copy will be generated, so emit an explicit nil check.
- n->left = cheapexpr(n->left, init);
- checknil(n->left, init);
- }
- walkexpr(&n->left, init);
- goto ret;
-
- case OEFACE:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- goto ret;
-
- case OSPTR:
- case OITAB:
- walkexpr(&n->left, init);
- goto ret;
-
- case OLEN:
- case OCAP:
- walkexpr(&n->left, init);
-
- // replace len(*[10]int) with 10.
- // delayed until now to preserve side effects.
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
- if(isfixedarray(t)) {
- safeexpr(n->left, init);
- nodconst(n, n->type, t->bound);
- n->typecheck = 1;
- }
- goto ret;
-
- case OLSH:
- case ORSH:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- t = n->left->type;
- n->bounded = bounded(n->right, 8*t->width);
- if(debug['m'] && n->etype && !isconst(n->right, CTINT))
- warn("shift bounds check elided");
- goto ret;
-
- case OAND:
- case OSUB:
- case OHMUL:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OADD:
- case OCOMPLEX:
- case OLROT:
- // Use results from call expression as arguments for complex.
- if(n->op == OCOMPLEX && n->left == N && n->right == N) {
- n->left = n->list->n;
- n->right = n->list->next->n;
- }
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- goto ret;
-
- case OOR:
- case OXOR:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- walkrotate(&n);
- goto ret;
-
- case OEQ:
- case ONE:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- // Disable safemode while compiling this code: the code we
- // generate internally can refer to unsafe.Pointer.
- // In this case it can happen if we need to generate an ==
- // for a struct containing a reflect.Value, which itself has
- // an unexported field of type unsafe.Pointer.
- old_safemode = safemode;
- safemode = 0;
- walkcompare(&n, init);
- safemode = old_safemode;
- goto ret;
-
- case OANDAND:
- case OOROR:
- walkexpr(&n->left, init);
- // cannot put side effects from n->right on init,
- // because they cannot run before n->left is checked.
- // save elsewhere and store on the eventual n->right.
- ll = nil;
- walkexpr(&n->right, &ll);
- addinit(&n->right, ll);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->list, init);
- n = walkprint(n, init);
- goto ret;
-
- case OPANIC:
- n = mkcall("gopanic", T, init, n->left);
- goto ret;
-
- case ORECOVER:
- n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N));
- goto ret;
-
- case OLITERAL:
- n->addable = 1;
- goto ret;
-
- case OCLOSUREVAR:
- case OCFUNC:
- n->addable = 1;
- goto ret;
-
- case ONAME:
- if(!(n->class & PHEAP) && n->class != PPARAMREF)
- n->addable = 1;
- goto ret;
-
- case OCALLINTER:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- goto ret;
-
- case OCALLFUNC:
- if(n->left->op == OCLOSURE) {
- // Transform direct call of a closure to call of a normal function.
- // transformclosure already did all preparation work.
-
- // Append captured variables to argument list.
- n->list = concat(n->list, n->left->enter);
- n->left->enter = nil;
- // Replace OCLOSURE with ONAME/PFUNC.
- n->left = n->left->closure->nname;
- // Update type of OCALLFUNC node.
- // Output arguments had not changed, but their offsets could.
- if(n->left->type->outtuple == 1) {
- t = getoutargx(n->left->type)->type;
- if(t->etype == TFIELD)
- t = t->type;
- n->type = t;
- } else
- n->type = getoutargx(n->left->type);
- }
-
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
-
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
-
- ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- goto ret;
-
- case OCALLMETH:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init);
- lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
- ll = concat(ll, lr);
- n->left->left = N;
- ullmancalc(n->left);
- n->list = reorder1(ll);
- goto ret;
-
- case OAS:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
-
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
-
- if(oaslit(n, init))
- goto ret;
-
- if(n->right == N || iszero(n->right) && !flag_race)
- goto ret;
-
- switch(n->right->op) {
- default:
- walkexpr(&n->right, init);
- break;
-
- case ODOTTYPE:
- // x = i.(T); n->left is x, n->right->left is i.
- // orderstmt made sure x is addressable.
- walkexpr(&n->right->left, init);
- n1 = nod(OADDR, n->left, N);
- r = n->right; // i.(T)
-
- from = "I";
- to = "T";
- if(isnilinter(r->left->type))
- from = "E";
- if(isnilinter(r->type))
- to = "E";
- else if(isinter(r->type))
- to = "I";
-
- snprint(buf, sizeof buf, "assert%s2%s", from, to);
-
- fn = syslook(buf, 1);
- argtype(fn, r->left->type);
- argtype(fn, r->type);
-
- n = mkcall1(fn, T, init, typename(r->type), r->left, n1);
- walkexpr(&n, init);
- goto ret;
-
- case ORECV:
- // x = <-c; n->left is x, n->right->left is c.
- // orderstmt made sure x is addressable.
- walkexpr(&n->right->left, init);
- n1 = nod(OADDR, n->left, N);
- r = n->right->left; // the channel
- n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1);
- walkexpr(&n, init);
- goto ret;
- }
-
- if(n->left != N && n->right != N) {
- r = convas(nod(OAS, n->left, n->right), init);
- r->dodata = n->dodata;
- n = r;
- n = applywritebarrier(n, init);
- }
-
- goto ret;
-
- case OAS2:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexprlistsafe(n->list, init);
- walkexprlistsafe(n->rlist, init);
- ll = ascompatee(OAS, n->list, n->rlist, init);
- ll = reorder3(ll);
- for(lr = ll; lr != nil; lr = lr->next)
- lr->n = applywritebarrier(lr->n, init);
- n = liststmt(ll);
- goto ret;
-
- case OAS2FUNC:
- // a,b,... = fn()
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r, init);
-
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- for(lr = ll; lr != nil; lr = lr->next)
- lr->n = applywritebarrier(lr->n, init);
- n = liststmt(concat(list1(r), ll));
- goto ret;
-
- case OAS2RECV:
- // x, y = <-c
- // orderstmt made sure x is addressable.
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- if(isblank(n->list->n))
- n1 = nodnil();
- else
- n1 = nod(OADDR, n->list->n, N);
- n1->etype = 1; // addr does not escape
- fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1);
- n = nod(OAS, n->list->next->n, r);
- typecheck(&n, Etop);
- goto ret;
-
- case OAS2MAPR:
- // a,b = m[i];
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- walkexpr(&r->right, init);
- t = r->left->type;
- p = nil;
- if(t->type->width <= 128) { // Check ../../runtime/hashmap.go:maxValueSize before changing.
- switch(simsimtype(t->down)) {
- case TINT32:
- case TUINT32:
- p = "mapaccess2_fast32";
- break;
- case TINT64:
- case TUINT64:
- p = "mapaccess2_fast64";
- break;
- case TSTRING:
- p = "mapaccess2_faststr";
- break;
- }
- }
- if(p != nil) {
- // fast versions take key by value
- key = r->right;
- } else {
- // standard version takes key by reference
- // orderexpr made sure key is addressable.
- key = nod(OADDR, r->right, N);
- p = "mapaccess2";
- }
-
- // from:
- // a,b = m[i]
- // to:
- // var,b = mapaccess2*(t, m, i)
- // a = *var
- a = n->list->n;
- fn = mapfn(p, t);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
-
- // mapaccess2* returns a typed bool, but due to spec changes,
- // the boolean result of i.(T) is now untyped so we make it the
- // same type as the variable on the lhs.
- if(!isblank(n->list->next->n))
- r->type->type->down->type = n->list->next->n->type;
- n->rlist = list1(r);
- n->op = OAS2FUNC;
-
- // don't generate a = *var if a is _
- if(!isblank(a)) {
- var = temp(ptrto(t->type));
- var->typecheck = 1;
- n->list->n = var;
- walkexpr(&n, init);
- *init = list(*init, n);
- n = nod(OAS, a, nod(OIND, var, N));
- }
-
- typecheck(&n, Etop);
- walkexpr(&n, init);
- // mapaccess needs a zero value to be at least this big.
- if(zerosize < t->type->width)
- zerosize = t->type->width;
- // TODO: ptr is always non-nil, so disable nil check for this OIND op.
- goto ret;
-
- case ODELETE:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- map = n->list->n;
- key = n->list->next->n;
- walkexpr(&map, init);
- walkexpr(&key, init);
- // orderstmt made sure key is addressable.
- key = nod(OADDR, key, N);
- t = map->type;
- n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key);
- goto ret;
-
- case OAS2DOTTYPE:
- // a,b = i.(T)
- // orderstmt made sure a is addressable.
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- if(isblank(n->list->n))
- n1 = nodnil();
- else
- n1 = nod(OADDR, n->list->n, N);
- n1->etype = 1; // addr does not escape
-
- from = "I";
- to = "T";
- if(isnilinter(r->left->type))
- from = "E";
- if(isnilinter(r->type))
- to = "E";
- else if(isinter(r->type))
- to = "I";
- snprint(buf, sizeof buf, "assert%s2%s2", from, to);
-
- fn = syslook(buf, 1);
- argtype(fn, r->left->type);
- argtype(fn, r->type);
-
- t = types[TBOOL];
- ok = n->list->next->n;
- if(!isblank(ok))
- t = ok->type;
- r = mkcall1(fn, t, init, typename(r->type), r->left, n1);
- n = nod(OAS, ok, r);
- typecheck(&n, Etop);
- goto ret;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- fatal("walkexpr ODOTTYPE"); // should see inside OAS or OAS2 only
-
- case OCONVIFACE:
- walkexpr(&n->left, init);
-
- // Optimize convT2E as a two-word copy when T is pointer-shaped.
- if(isnilinter(n->type) && isdirectiface(n->left->type)) {
- l = nod(OEFACE, typename(n->left->type), n->left);
- l->type = n->type;
- l->typecheck = n->typecheck;
- n = l;
- goto ret;
- }
-
- // Build name of function: convI2E etc.
- // Not all names are possible
- // (e.g., we'll never generate convE2E or convE2I).
- from = "T";
- to = "I";
- if(isnilinter(n->left->type))
- from = "E";
- else if(isinter(n->left->type))
- from = "I";
- if(isnilinter(n->type))
- to = "E";
- snprint(buf, sizeof buf, "conv%s2%s", from, to);
-
- fn = syslook(buf, 1);
- ll = nil;
- if(!isinter(n->left->type))
- ll = list(ll, typename(n->left->type));
- if(!isnilinter(n->type))
- ll = list(ll, typename(n->type));
- if(!isinter(n->left->type) && !isnilinter(n->type)){
- sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg);
- if(sym->def == N) {
- l = nod(ONAME, N, N);
- l->sym = sym;
- l->type = ptrto(types[TUINT8]);
- l->addable = 1;
- l->class = PEXTERN;
- l->xoffset = 0;
- sym->def = l;
- ggloblsym(sym, widthptr, DUPOK|NOPTR);
- }
- l = nod(OADDR, sym->def, N);
- l->addable = 1;
- ll = list(ll, l);
-
- if(isdirectiface(n->left->type)) {
- /* For pointer types, we can make a special form of optimization
- *
- * These statements are put onto the expression init list:
- * Itab *tab = atomicloadtype(&cache);
- * if(tab == nil)
- * tab = typ2Itab(type, itype, &cache);
- *
- * The CONVIFACE expression is replaced with this:
- * OEFACE{tab, ptr};
- */
- l = temp(ptrto(types[TUINT8]));
-
- n1 = nod(OAS, l, sym->def);
- typecheck(&n1, Etop);
- *init = list(*init, n1);
-
- fn = syslook("typ2Itab", 1);
- n1 = nod(OCALL, fn, N);
- n1->list = ll;
- typecheck(&n1, Erv);
- walkexpr(&n1, init);
-
- n2 = nod(OIF, N, N);
- n2->ntest = nod(OEQ, l, nodnil());
- n2->nbody = list1(nod(OAS, l, n1));
- n2->likely = -1;
- typecheck(&n2, Etop);
- *init = list(*init, n2);
-
- l = nod(OEFACE, l, n->left);
- l->typecheck = n->typecheck;
- l->type = n->type;
- n = l;
- goto ret;
- }
- }
- if(isinter(n->left->type)) {
- ll = list(ll, n->left);
- } else {
- // regular types are passed by reference to avoid C vararg calls
- // orderexpr arranged for n->left to be a temporary for all
- // the conversions it could see. comparison of an interface
- // with a non-interface, especially in a switch on interface value
- // with non-interface cases, is not visible to orderstmt, so we
- // have to fall back on allocating a temp here.
- if(islvalue(n->left))
- ll = list(ll, nod(OADDR, n->left, N));
- else
- ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N));
- }
- argtype(fn, n->left->type);
- argtype(fn, n->type);
- dowidth(fn->type);
- n = nod(OCALL, fn, N);
- n->list = ll;
- typecheck(&n, Erv);
- walkexpr(&n, init);
- goto ret;
-
- case OCONV:
- case OCONVNOP:
- if(thearch.thechar == '5') {
- if(isfloat[n->left->type->etype]) {
- if(n->type->etype == TINT64) {
- n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- if(n->type->etype == TUINT64) {
- n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- }
- if(isfloat[n->type->etype]) {
- if(n->left->type->etype == TINT64) {
- n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
- goto ret;
- }
- if(n->left->type->etype == TUINT64) {
- n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
- goto ret;
- }
- }
- }
- walkexpr(&n->left, init);
- goto ret;
-
- case OANDNOT:
- walkexpr(&n->left, init);
- n->op = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- walkexpr(&n->right, init);
- goto ret;
-
- case OMUL:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- walkmul(&n, init);
- goto ret;
-
- case ODIV:
- case OMOD:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- /*
- * rewrite complex div into function call.
- */
- et = n->left->type->etype;
- if(iscomplex[et] && n->op == ODIV) {
- t = n->type;
- n = mkcall("complex128div", types[TCOMPLEX128], init,
- conv(n->left, types[TCOMPLEX128]),
- conv(n->right, types[TCOMPLEX128]));
- n = conv(n, t);
- goto ret;
- }
- // Nothing to do for float divisions.
- if(isfloat[et])
- goto ret;
-
- // Try rewriting as shifts or magic multiplies.
- walkdiv(&n, init);
-
- /*
- * rewrite 64-bit div and mod into function calls
- * on 32-bit architectures.
- */
- switch(n->op) {
- case OMOD:
- case ODIV:
- if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
- goto ret;
- if(et == TINT64)
- strcpy(namebuf, "int64");
- else
- strcpy(namebuf, "uint64");
- if(n->op == ODIV)
- strcat(namebuf, "div");
- else
- strcat(namebuf, "mod");
- n = mkcall(namebuf, n->type, init,
- conv(n->left, types[et]), conv(n->right, types[et]));
- break;
- default:
- break;
- }
- goto ret;
-
- case OINDEX:
- walkexpr(&n->left, init);
- // save the original node for bounds checking elision.
- // If it was a ODIV/OMOD walk might rewrite it.
- r = n->right;
- walkexpr(&n->right, init);
-
- // if range of type cannot exceed static array bound,
- // disable bounds check.
- if(n->bounded)
- goto ret;
- t = n->left->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t)) {
- n->bounded = bounded(r, t->bound);
- if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
- warn("index bounds check elided");
- if(smallintconst(n->right) && !n->bounded)
- yyerror("index out of bounds");
- } else if(isconst(n->left, CTSTR)) {
- n->bounded = bounded(r, n->left->val.u.sval->len);
- if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
- warn("index bounds check elided");
- if(smallintconst(n->right)) {
- if(!n->bounded)
- yyerror("index out of bounds");
- else {
- // replace "abc"[1] with 'b'.
- // delayed until now because "abc"[1] is not
- // an ideal constant.
- v = mpgetfix(n->right->val.u.xval);
- nodconst(n, n->type, n->left->val.u.sval->s[v]);
- n->typecheck = 1;
- }
- }
- }
-
- if(isconst(n->right, CTINT))
- if(mpcmpfixfix(n->right->val.u.xval, &mpzero) < 0 ||
- mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
- yyerror("index out of bounds");
- goto ret;
-
- case OINDEXMAP:
- if(n->etype == 1)
- goto ret;
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
-
- t = n->left->type;
- p = nil;
- if(t->type->width <= 128) { // Check ../../runtime/hashmap.go:maxValueSize before changing.
- switch(simsimtype(t->down)) {
- case TINT32:
- case TUINT32:
- p = "mapaccess1_fast32";
- break;
- case TINT64:
- case TUINT64:
- p = "mapaccess1_fast64";
- break;
- case TSTRING:
- p = "mapaccess1_faststr";
- break;
- }
- }
- if(p != nil) {
- // fast versions take key by value
- key = n->right;
- } else {
- // standard version takes key by reference.
- // orderexpr made sure key is addressable.
- key = nod(OADDR, n->right, N);
- p = "mapaccess1";
- }
- n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key);
- n = nod(OIND, n, N);
- n->type = t->type;
- n->typecheck = 1;
- // mapaccess needs a zero value to be at least this big.
- if(zerosize < t->type->width)
- zerosize = t->type->width;
- goto ret;
-
- case ORECV:
- fatal("walkexpr ORECV"); // should see inside OAS only
-
- case OSLICE:
- if(n->right != N && n->right->left == N && n->right->right == N) { // noop
- walkexpr(&n->left, init);
- n = n->left;
- goto ret;
- }
- // fallthrough
- case OSLICEARR:
- case OSLICESTR:
- if(n->right == N) // already processed
- goto ret;
-
- walkexpr(&n->left, init);
- // cgen_slice can't handle string literals as source
- // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
- if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
- n->left = copyexpr(n->left, n->left->type, init);
- else
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right, init);
- n->right->right = safeexpr(n->right->right, init);
- n = sliceany(n, init); // chops n->right, sets n->list
- goto ret;
-
- case OSLICE3:
- case OSLICE3ARR:
- if(n->right == N) // already processed
- goto ret;
-
- walkexpr(&n->left, init);
- // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
- // TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
- if(n->left->op == OINDEX)
- n->left = copyexpr(n->left, n->left->type, init);
- else
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right->left, init);
- n->right->right->left = safeexpr(n->right->right->left, init);
- walkexpr(&n->right->right->right, init);
- n->right->right->right = safeexpr(n->right->right->right, init);
- n = sliceany(n, init); // chops n->right, sets n->list
- goto ret;
-
- case OADDR:
- walkexpr(&n->left, init);
- goto ret;
-
- case ONEW:
- if(n->esc == EscNone && n->type->type->width < (1<<16)) {
- r = temp(n->type->type);
- r = nod(OAS, r, N); // zero temp
- typecheck(&r, Etop);
- *init = list(*init, r);
- r = nod(OADDR, r->left, N);
- typecheck(&r, Erv);
- n = r;
- } else {
- n = callnew(n->type->type);
- }
- goto ret;
-
- case OCMPSTR:
- // If one argument to the comparison is an empty string,
- // comparing the lengths instead will yield the same result
- // without the function call.
- if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
- (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
- r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
- n = r;
- goto ret;
- }
-
- // s + "badgerbadgerbadger" == "badgerbadgerbadger"
- if((n->etype == OEQ || n->etype == ONE) &&
- isconst(n->right, CTSTR) &&
- n->left->op == OADDSTR && count(n->left->list) == 2 &&
- isconst(n->left->list->next->n, CTSTR) &&
- cmpslit(n->right, n->left->list->next->n) == 0) {
- r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
- n = r;
- goto ret;
- }
-
- if(n->etype == OEQ || n->etype == ONE) {
- // prepare for rewrite below
- n->left = cheapexpr(n->left, init);
- n->right = cheapexpr(n->right, init);
-
- r = mkcall("eqstring", types[TBOOL], init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
-
- // quick check of len before full compare for == or !=
- // eqstring assumes that the lengths are equal
- if(n->etype == OEQ) {
- // len(left) == len(right) && eqstring(left, right)
- r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- } else {
- // len(left) != len(right) || !eqstring(left, right)
- r = nod(ONOT, r, N);
- r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- }
- typecheck(&r, Erv);
- walkexpr(&r, nil);
- } else {
- // sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types[TINT], init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
- r = nod(n->etype, r, nodintconst(0));
- }
-
- typecheck(&r, Erv);
- if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
- r->type = n->type;
- n = r;
- goto ret;
-
- case OADDSTR:
- n = addstr(n, init);
- goto ret;
-
- case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init); // also works for append(slice, string).
- else
- n = append(n, init);
- goto ret;
-
- case OCOPY:
- n = copyany(n, init, flag_race);
- goto ret;
-
- case OCLOSE:
- // cannot use chanfn - closechan takes any, not chan any
- fn = syslook("closechan", 1);
- argtype(fn, n->left->type);
- n = mkcall1(fn, T, init, n->left);
- goto ret;
-
- case OMAKECHAN:
- n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
- typename(n->type),
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OMAKEMAP:
- t = n->type;
-
- fn = syslook("makemap", 1);
-
- a = nodnil(); // hmap buffer
- r = nodnil(); // bucket buffer
- if(n->esc == EscNone) {
- // Allocate hmap buffer on stack.
- var = temp(hmap(t));
- a = nod(OAS, var, N); // zero temp
- typecheck(&a, Etop);
- *init = list(*init, a);
- a = nod(OADDR, var, N);
-
- // Allocate one bucket on stack.
- // Maximum key/value size is 128 bytes, larger objects
- // are stored with an indirection. So max bucket size is 2048+eps.
- var = temp(mapbucket(t));
- r = nod(OAS, var, N); // zero temp
- typecheck(&r, Etop);
- *init = list(*init, r);
- r = nod(OADDR, var, N);
- }
-
- argtype(fn, hmap(t)); // hmap buffer
- argtype(fn, mapbucket(t)); // bucket buffer
- argtype(fn, t->down); // key type
- argtype(fn, t->type); // value type
- n = mkcall1(fn, n->type, init, typename(n->type), conv(n->left, types[TINT64]), a, r);
- goto ret;
-
- case OMAKESLICE:
- l = n->left;
- r = n->right;
- if(r == nil)
- l = r = safeexpr(l, init);
- t = n->type;
- if(n->esc == EscNone
- && smallintconst(l) && smallintconst(r)
- && (t->type->width == 0 || mpgetfix(r->val.u.xval) < (1ULL<<16) / t->type->width)) {
- // var arr [r]T
- // n = arr[:l]
- t = aindex(r, t->type); // [r]T
- var = temp(t);
- a = nod(OAS, var, N); // zero temp
- typecheck(&a, Etop);
- *init = list(*init, a);
- r = nod(OSLICE, var, nod(OKEY, N, l)); // arr[:l]
- r = conv(r, n->type); // in case n->type is named.
- typecheck(&r, Erv);
- walkexpr(&r, init);
- n = r;
- } else {
- // makeslice(t *Type, nel int64, max int64) (ary []any)
- fn = syslook("makeslice", 1);
- argtype(fn, t->type); // any-1
- n = mkcall1(fn, n->type, init,
- typename(n->type),
- conv(l, types[TINT64]),
- conv(r, types[TINT64]));
- }
- goto ret;
-
- case ORUNESTR:
- a = nodnil();
- if(n->esc == EscNone) {
- t = aindex(nodintconst(4), types[TUINT8]);
- var = temp(t);
- a = nod(OADDR, var, N);
- }
- // intstring(*[4]byte, rune)
- n = mkcall("intstring", n->type, init, a, conv(n->left, types[TINT64]));
- goto ret;
-
- case OARRAYBYTESTR:
- a = nodnil();
- if(n->esc == EscNone) {
- // Create temporary buffer for string on stack.
- t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
- a = nod(OADDR, temp(t), N);
- }
- // slicebytetostring(*[32]byte, []byte) string;
- n = mkcall("slicebytetostring", n->type, init, a, n->left);
- goto ret;
-
- case OARRAYBYTESTRTMP:
- // slicebytetostringtmp([]byte) string;
- n = mkcall("slicebytetostringtmp", n->type, init, n->left);
- goto ret;
-
- case OARRAYRUNESTR:
- // slicerunetostring(*[32]byte, []rune) string;
- a = nodnil();
- if(n->esc == EscNone) {
- // Create temporary buffer for string on stack.
- t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
- a = nod(OADDR, temp(t), N);
- }
- n = mkcall("slicerunetostring", n->type, init, a, n->left);
- goto ret;
-
- case OSTRARRAYBYTE:
- // stringtoslicebyte(*32[byte], string) []byte;
- a = nodnil();
- if(n->esc == EscNone) {
- // Create temporary buffer for slice on stack.
- t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
- a = nod(OADDR, temp(t), N);
- }
- n = mkcall("stringtoslicebyte", n->type, init, a, conv(n->left, types[TSTRING]));
- goto ret;
-
- case OSTRARRAYBYTETMP:
- // stringtoslicebytetmp(string) []byte;
- n = mkcall("stringtoslicebytetmp", n->type, init, conv(n->left, types[TSTRING]));
- goto ret;
-
- case OSTRARRAYRUNE:
- // stringtoslicerune(*[32]rune, string) []rune
- a = nodnil();
- if(n->esc == EscNone) {
- // Create temporary buffer for slice on stack.
- t = aindex(nodintconst(tmpstringbufsize), types[TINT32]);
- a = nod(OADDR, temp(t), N);
- }
- n = mkcall("stringtoslicerune", n->type, init, a, n->left);
- goto ret;
-
- case OCMPIFACE:
- // ifaceeq(i1 any-1, i2 any-2) (ret bool);
- if(!eqtype(n->left->type, n->right->type))
- fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
- if(isnilinter(n->left->type))
- fn = syslook("efaceeq", 1);
- else
- fn = syslook("ifaceeq", 1);
-
- n->right = cheapexpr(n->right, init);
- n->left = cheapexpr(n->left, init);
- argtype(fn, n->right->type);
- argtype(fn, n->left->type);
- r = mkcall1(fn, n->type, init, n->left, n->right);
- if(n->etype == ONE)
- r = nod(ONOT, r, N);
-
- // check itable/type before full compare.
- if(n->etype == OEQ)
- r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
- else
- r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
- n = r;
- goto ret;
-
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- case OPTRLIT:
- var = temp(n->type);
- anylit(0, n, var, init);
- n = var;
- goto ret;
-
- case OSEND:
- n1 = n->right;
- n1 = assignconv(n1, n->left->type->type, "chan send");
- walkexpr(&n1, init);
- n1 = nod(OADDR, n1, N);
- n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1);
- goto ret;
-
- case OCLOSURE:
- n = walkclosure(n, init);
- goto ret;
-
- case OCALLPART:
- n = walkpartialcall(n, init);
- goto ret;
- }
- fatal("missing switch %O", n->op);
-
-ret:
- // Expressions that are constant at run time but not
- // considered const by the language spec are not turned into
- // constants until walk. For example, if n is y%1 == 0, the
- // walk of y%1 may have replaced it by 0.
- // Check whether n with its updated args is itself now a constant.
- t = n->type;
- evconst(n);
- n->type = t;
- if(n->op == OLITERAL)
- typecheck(&n, Erv);
-
- ullmancalc(n);
-
- if(debug['w'] && n != N)
- dump("walk", n);
-
- lineno = lno;
- *np = n;
-}
-
-static Node*
-ascompatee1(int op, Node *l, Node *r, NodeList **init)
-{
- Node *n;
- USED(op);
-
- // convas will turn map assigns into function calls,
- // making it impossible for reorder3 to work.
- n = nod(OAS, l, r);
- if(l->op == OINDEXMAP)
- return n;
-
- return convas(n, init);
-}
-
-static NodeList*
-ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
-{
- NodeList *ll, *lr, *nn;
-
- /*
- * check assign expression list to
- * a expression list. called in
- * expr-list = expr-list
- */
-
- // ensure order of evaluation for function calls
- for(ll=nl; ll; ll=ll->next)
- ll->n = safeexpr(ll->n, init);
- for(lr=nr; lr; lr=lr->next)
- lr->n = safeexpr(lr->n, init);
-
- nn = nil;
- for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) {
- // Do not generate 'x = x' during return. See issue 4014.
- if(op == ORETURN && ll->n == lr->n)
- continue;
- nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
- }
-
- // cannot happen: caller checked that lists had same length
- if(ll || lr)
- yyerror("error in shape across %+H %O %+H / %d %d [%s]", nl, op, nr, count(nl), count(nr), curfn->nname->sym->name);
- return nn;
-}
-
-/*
- * l is an lv and rt is the type of an rv
- * return 1 if this implies a function call
- * evaluating the lv or a function call
- * in the conversion of the types
- */
-static int
-fncall(Node *l, Type *rt)
-{
- Node r;
-
- if(l->ullman >= UINF || l->op == OINDEXMAP)
- return 1;
- memset(&r, 0, sizeof r);
- if(needwritebarrier(l, &r))
- return 1;
- if(eqtype(l->type, rt))
- return 0;
- return 1;
-}
-
-static NodeList*
-ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
-{
- Node *l, *tmp, *a;
- NodeList *ll;
- Type *r;
- Iter saver;
- int ucount;
- NodeList *nn, *mm;
-
- USED(op);
-
- /*
- * check assign type list to
- * a expression list. called in
- * expr-list = func()
- */
- r = structfirst(&saver, nr);
- nn = nil;
- mm = nil;
- ucount = 0;
- for(ll=nl; ll; ll=ll->next) {
- if(r == T)
- break;
- l = ll->n;
- if(isblank(l)) {
- r = structnext(&saver);
- continue;
- }
-
- // any lv that causes a fn call must be
- // deferred until all the return arguments
- // have been pulled from the output arguments
- if(fncall(l, r->type)) {
- tmp = temp(r->type);
- typecheck(&tmp, Erv);
- a = nod(OAS, l, tmp);
- a = convas(a, init);
- mm = list(mm, a);
- l = tmp;
- }
-
- a = nod(OAS, l, nodarg(r, fp));
- a = convas(a, init);
- ullmancalc(a);
- if(a->ullman >= UINF) {
- dump("ascompatet ucount", a);
- ucount++;
- }
- nn = list(nn, a);
- r = structnext(&saver);
- }
-
- if(ll != nil || r != T)
- yyerror("ascompatet: assignment count mismatch: %d = %d",
- count(nl), structcount(*nr));
-
- if(ucount)
- fatal("ascompatet: too many function calls evaluating parameters");
- return concat(nn, mm);
-}
-
- /*
- * package all the arguments that match a ... T parameter into a []T.
- */
-static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd)
-{
- Node *a, *n;
- Type *tslice;
- int esc;
-
- esc = EscUnknown;
- if(ddd != nil)
- esc = ddd->esc;
-
- tslice = typ(TARRAY);
- tslice->type = l->type->type;
- tslice->bound = -1;
-
- if(count(lr0) == 0) {
- n = nodnil();
- n->type = tslice;
- } else {
- n = nod(OCOMPLIT, N, typenod(tslice));
- if(ddd != nil)
- n->alloc = ddd->alloc; // temporary to use
- n->list = lr0;
- n->esc = esc;
- typecheck(&n, Erv);
- if(n->type == T)
- fatal("mkdotargslice: typecheck failed");
- walkexpr(&n, init);
- }
-
- a = nod(OAS, nodarg(l, fp), n);
- nn = list(nn, convas(a, init));
- return nn;
-}
-
-/*
- * helpers for shape errors
- */
-static char*
-dumptypes(Type **nl, char *what)
-{
- int first;
- Type *l;
- Iter savel;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- first = 1;
- for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", l);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-static char*
-dumpnodetypes(NodeList *l, char *what)
-{
- int first;
- Node *r;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- first = 1;
- for(; l; l=l->next) {
- r = l->n;
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", r->type);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-/*
- * check assign expression list to
- * a type list. called in
- * return expr-list
- * func(expr-list)
- */
-static NodeList*
-ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
-{
- Type *l, *ll;
- Node *r, *a;
- NodeList *nn, *lr0, *alist;
- Iter savel;
- char *l1, *l2;
-
- lr0 = lr;
- l = structfirst(&savel, nl);
- r = N;
- if(lr)
- r = lr->n;
- nn = nil;
-
- // f(g()) where g has multiple return values
- if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
- // optimization - can do block copy
- if(eqtypenoname(r->type, *nl)) {
- a = nodarg(*nl, fp);
- r = nod(OCONVNOP, r, N);
- r->type = a->type;
- nn = list1(convas(nod(OAS, a, r), init));
- goto ret;
- }
-
- // conversions involved.
- // copy into temporaries.
- alist = nil;
- for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
- a = temp(l->type);
- alist = list(alist, a);
- }
- a = nod(OAS2, N, N);
- a->list = alist;
- a->rlist = lr;
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- lr = alist;
- r = lr->n;
- l = structfirst(&savel, nl);
- }
-
-loop:
- if(l != T && l->isddd) {
- // the ddd parameter must be last
- ll = structnext(&savel);
- if(ll != T)
- yyerror("... must be last argument");
-
- // special case --
- // only if we are assigning a single ddd
- // argument to a ddd parameter then it is
- // passed thru unencapsulated
- if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
- goto ret;
- }
-
- // normal case -- make a slice of all
- // remaining arguments and pass it to
- // the ddd parameter.
- nn = mkdotargslice(lr, nn, l, fp, init, call->right);
- goto ret;
- }
-
- if(l == T || r == N) {
- if(l != T || r != N) {
- l1 = dumptypes(nl, "expected");
- l2 = dumpnodetypes(lr0, "given");
- if(l != T)
- yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
- else
- yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
- }
- goto ret;
- }
-
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
-
- l = structnext(&savel);
- r = N;
- lr = lr->next;
- if(lr != nil)
- r = lr->n;
- goto loop;
-
-ret:
- for(lr=nn; lr; lr=lr->next)
- lr->n->typecheck = 1;
- return nn;
-}
-
-// generate code for print
-static Node*
-walkprint(Node *nn, NodeList **init)
-{
- Node *r;
- Node *n;
- NodeList *l, *all;
- Node *on;
- Type *t;
- int notfirst, et, op;
- NodeList *calls;
-
- op = nn->op;
- all = nn->list;
- calls = nil;
- notfirst = 0;
-
- // Hoist all the argument evaluation up before the lock.
- walkexprlistcheap(all, init);
-
- calls = list(calls, mkcall("printlock", T, init));
-
- for(l=all; l; l=l->next) {
- if(notfirst) {
- calls = list(calls, mkcall("printsp", T, init));
- }
- notfirst = op == OPRINTN;
-
- n = l->n;
- if(n->op == OLITERAL) {
- switch(n->val.ctype) {
- case CTRUNE:
- defaultlit(&n, runetype);
- break;
- case CTINT:
- defaultlit(&n, types[TINT64]);
- break;
- case CTFLT:
- defaultlit(&n, types[TFLOAT64]);
- break;
- }
- }
- if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
- defaultlit(&n, types[TINT64]);
- defaultlit(&n, nil);
- l->n = n;
- if(n->type == T || n->type->etype == TFORW)
- continue;
-
- t = n->type;
- et = n->type->etype;
- if(isinter(n->type)) {
- if(isnilinter(n->type))
- on = syslook("printeface", 1);
- else
- on = syslook("printiface", 1);
- argtype(on, n->type); // any-1
- } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
- on = syslook("printpointer", 1);
- argtype(on, n->type); // any-1
- } else if(isslice(n->type)) {
- on = syslook("printslice", 1);
- argtype(on, n->type); // any-1
- } else if(isint[et]) {
- if(et == TUINT64) {
- if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
- on = syslook("printhex", 0);
- else
- on = syslook("printuint", 0);
- } else
- on = syslook("printint", 0);
- } else if(isfloat[et]) {
- on = syslook("printfloat", 0);
- } else if(iscomplex[et]) {
- on = syslook("printcomplex", 0);
- } else if(et == TBOOL) {
- on = syslook("printbool", 0);
- } else if(et == TSTRING) {
- on = syslook("printstring", 0);
- } else {
- badtype(OPRINT, n->type, T);
- continue;
- }
-
- t = *getinarg(on->type);
- if(t != nil)
- t = t->type;
- if(t != nil)
- t = t->type;
-
- if(!eqtype(t, n->type)) {
- n = nod(OCONV, n, N);
- n->type = t;
- }
-
- r = nod(OCALL, on, N);
- r->list = list1(n);
- calls = list(calls, r);
- }
-
- if(op == OPRINTN)
- calls = list(calls, mkcall("printnl", T, nil));
-
- calls = list(calls, mkcall("printunlock", T, init));
-
- typechecklist(calls, Etop);
- walkexprlist(calls, init);
-
- r = nod(OEMPTY, N, N);
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->ninit = calls;
- return r;
-}
-
-Node*
-callnew(Type *t)
-{
- Node *fn;
-
- dowidth(t);
- fn = syslook("newobject", 1);
- argtype(fn, t);
- return mkcall1(fn, ptrto(t), nil, typename(t));
-}
-
-static int
-isstack(Node *n)
-{
- Node *defn;
-
- n = outervalue(n);
-
- // If n is *autotmp and autotmp = &foo, replace n with foo.
- // We introduce such temps when initializing struct literals.
- if(n->op == OIND && n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0) {
- defn = n->left->defn;
- if(defn != N && defn->op == OAS && defn->right->op == OADDR)
- n = defn->right->left;
- }
-
- switch(n->op) {
- case OINDREG:
- // OINDREG only ends up in walk if it's indirect of SP.
- return 1;
-
- case ONAME:
- switch(n->class) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- return 1;
- }
- break;
- }
-
- return 0;
-}
-
-static int
-isglobal(Node *n)
-{
- n = outervalue(n);
-
- switch(n->op) {
- case ONAME:
- switch(n->class) {
- case PEXTERN:
- return 1;
- }
- break;
- }
-
- return 0;
-}
-
-// Do we need a write barrier for the assignment l = r?
-int
-needwritebarrier(Node *l, Node *r)
-{
- if(!use_writebarrier)
- return 0;
-
- if(l == N || isblank(l))
- return 0;
-
- // No write barrier for write of non-pointers.
- dowidth(l->type);
- if(!haspointers(l->type))
- return 0;
-
- // No write barrier for write to stack.
- if(isstack(l))
- return 0;
-
- // No write barrier for implicit or explicit zeroing.
- if(r == N || iszero(r))
- return 0;
-
- // No write barrier for initialization to constant.
- if(r->op == OLITERAL)
- return 0;
-
- // No write barrier for storing static (read-only) data.
- if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0)
- return 0;
-
- // No write barrier for storing address of stack values,
- // which are guaranteed only to be written to the stack.
- if(r->op == OADDR && isstack(r->left))
- return 0;
-
- // No write barrier for storing address of global, which
- // is live no matter what.
- if(r->op == OADDR && isglobal(r->left))
- return 0;
-
- // No write barrier for reslice: x = x[0:y] or x = append(x, ...).
- // Both are compiled to modify x directly.
- // In the case of append, a write barrier may still be needed
- // if the underlying array grows, but the append code can
- // generate the write barrier directly in that case.
- // (It does not yet, but the cost of the write barrier will be
- // small compared to the cost of the allocation.)
- if(r->reslice) {
- switch(r->op) {
- case OSLICE:
- case OSLICE3:
- case OSLICESTR:
- case OAPPEND:
- break;
- default:
- dump("bad reslice-l", l);
- dump("bad reslice-r", r);
- break;
- }
- return 0;
- }
-
- // Otherwise, be conservative and use write barrier.
- return 1;
-}
-
-// TODO(rsc): Perhaps componentgen should run before this.
-static Node*
-applywritebarrier(Node *n, NodeList **init)
-{
- Node *l, *r;
- Type *t;
- vlong x;
- static Bvec *bv;
- char name[32];
-
- if(n->left && n->right && needwritebarrier(n->left, n->right)) {
- if(curfn && curfn->nowritebarrier)
- yyerror("write barrier prohibited");
- t = n->left->type;
- l = nod(OADDR, n->left, N);
- l->etype = 1; // addr does not escape
- if(t->width == widthptr) {
- n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
- l, n->right);
- } else if(t->etype == TSTRING) {
- n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
- l, n->right);
- } else if(isslice(t)) {
- n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
- l, n->right);
- } else if(isinter(t)) {
- n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
- l, n->right);
- } else if(t->width <= 4*widthptr) {
- x = 0;
- if(bv == nil)
- bv = bvalloc(BitsPerPointer*4);
- bvresetall(bv);
- twobitwalktype1(t, &x, bv);
- // The bvgets are looking for BitsPointer in successive slots.
- enum {
- PtrBit = 1,
- };
- if(BitsPointer != (1<<PtrBit))
- fatal("wrong PtrBit");
- switch(t->width/widthptr) {
- default:
- fatal("found writebarrierfat for %d-byte object of type %T", (int)t->width, t);
- case 2:
- snprint(name, sizeof name, "writebarrierfat%d%d",
- bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit));
- break;
- case 3:
- snprint(name, sizeof name, "writebarrierfat%d%d%d",
- bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit));
- break;
- case 4:
- snprint(name, sizeof name, "writebarrierfat%d%d%d%d",
- bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit), bvget(bv, 3*BitsPerPointer+PtrBit));
- break;
- }
- n = mkcall1(writebarrierfn(name, t, n->right->type), T, init,
- l, nodnil(), n->right);
- } else {
- r = n->right;
- while(r->op == OCONVNOP)
- r = r->left;
- r = nod(OADDR, r, N);
- r->etype = 1; // addr does not escape
- //warnl(n->lineno, "typedmemmove %T %N", t, r);
- n = mkcall1(writebarrierfn("typedmemmove", t, r->left->type), T, init,
- typename(t), l, r);
- }
- }
- return n;
-}
-
-static Node*
-convas(Node *n, NodeList **init)
-{
- Type *lt, *rt;
- Node *map, *key, *val;
-
- if(n->op != OAS)
- fatal("convas: not OAS %O", n->op);
-
- n->typecheck = 1;
-
- if(n->left == N || n->right == N)
- goto out;
-
- lt = n->left->type;
- rt = n->right->type;
- if(lt == T || rt == T)
- goto out;
-
- if(isblank(n->left)) {
- defaultlit(&n->right, T);
- goto out;
- }
-
- if(n->left->op == OINDEXMAP) {
- map = n->left->left;
- key = n->left->right;
- val = n->right;
- walkexpr(&map, init);
- walkexpr(&key, init);
- walkexpr(&val, init);
- // orderexpr made sure key and val are addressable.
- key = nod(OADDR, key, N);
- val = nod(OADDR, val, N);
- n = mkcall1(mapfn("mapassign1", map->type), T, init,
- typename(map->type), map, key, val);
- goto out;
- }
-
- if(!eqtype(lt, rt)) {
- n->right = assignconv(n->right, lt, "assignment");
- walkexpr(&n->right, init);
- }
-
-out:
- ullmancalc(n);
- return n;
-}
-
-/*
- * from ascompat[te]
- * evaluating actual function arguments.
- * f(a,b)
- * if there is exactly one function expr,
- * then it is done first. otherwise must
- * make temp variables
- */
-static NodeList*
-reorder1(NodeList *all)
-{
- Node *f, *a, *n;
- NodeList *l, *r, *g;
- int c, d, t;
-
- c = 0; // function calls
- t = 0; // total parameters
-
- for(l=all; l; l=l->next) {
- n = l->n;
- t++;
- ullmancalc(n);
- if(n->ullman >= UINF)
- c++;
- }
- if(c == 0 || t == 1)
- return all;
-
- g = nil; // fncalls assigned to tempnames
- f = N; // last fncall assigned to stack
- r = nil; // non fncalls and tempnames assigned to stack
- d = 0;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->ullman < UINF) {
- r = list(r, n);
- continue;
- }
- d++;
- if(d == c) {
- f = n;
- continue;
- }
-
- // make assignment of fncall to tempname
- a = temp(n->right->type);
- a = nod(OAS, a, n->right);
- g = list(g, a);
-
- // put normal arg assignment on list
- // with fncall replaced by tempname
- n->right = a->left;
- r = list(r, n);
- }
-
- if(f != N)
- g = list(g, f);
- return concat(g, r);
-}
-
-static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
-static int aliased(Node*, NodeList*, NodeList*);
-
-/*
- * from ascompat[ee]
- * a,b = c,d
- * simultaneous assignment. there cannot
- * be later use of an earlier lvalue.
- *
- * function calls have been removed.
- */
-static NodeList*
-reorder3(NodeList *all)
-{
- NodeList *list, *early, *mapinit;
- Node *l;
-
- // If a needed expression may be affected by an
- // earlier assignment, make an early copy of that
- // expression and use the copy instead.
- early = nil;
- mapinit = nil;
- for(list=all; list; list=list->next) {
- l = list->n->left;
-
- // Save subexpressions needed on left side.
- // Drill through non-dereferences.
- for(;;) {
- if(l->op == ODOT || l->op == OPAREN) {
- l = l->left;
- continue;
- }
- if(l->op == OINDEX && isfixedarray(l->left->type)) {
- reorder3save(&l->right, all, list, &early);
- l = l->left;
- continue;
- }
- break;
- }
- switch(l->op) {
- default:
- fatal("reorder3 unexpected lvalue %#O", l->op);
- case ONAME:
- break;
- case OINDEX:
- case OINDEXMAP:
- reorder3save(&l->left, all, list, &early);
- reorder3save(&l->right, all, list, &early);
- if(l->op == OINDEXMAP)
- list->n = convas(list->n, &mapinit);
- break;
- case OIND:
- case ODOTPTR:
- reorder3save(&l->left, all, list, &early);
- }
-
- // Save expression on right side.
- reorder3save(&list->n->right, all, list, &early);
- }
-
- early = concat(mapinit, early);
- return concat(early, all);
-}
-
-static int vmatch2(Node*, Node*);
-static int varexpr(Node*);
-
-/*
- * if the evaluation of *np would be affected by the
- * assignments in all up to but not including stop,
- * copy into a temporary during *early and
- * replace *np with that temp.
- */
-static void
-reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
-{
- Node *n, *q;
-
- n = *np;
- if(!aliased(n, all, stop))
- return;
-
- q = temp(n->type);
- q = nod(OAS, q, n);
- typecheck(&q, Etop);
- *early = list(*early, q);
- *np = q->left;
-}
-
-/*
- * what's the outer value that a write to n affects?
- * outer value means containing struct or array.
- */
-Node*
-outervalue(Node *n)
-{
- for(;;) {
- if(n->op == OXDOT)
- fatal("OXDOT in walk");
- if(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP) {
- n = n->left;
- continue;
- }
- if(n->op == OINDEX && isfixedarray(n->left->type)) {
- n = n->left;
- continue;
- }
- break;
- }
- return n;
-}
-
-/*
- * Is it possible that the computation of n might be
- * affected by writes in as up to but not including stop?
- */
-static int
-aliased(Node *n, NodeList *all, NodeList *stop)
-{
- int memwrite, varwrite;
- Node *a;
- NodeList *l;
-
- if(n == N)
- return 0;
-
- // Look for obvious aliasing: a variable being assigned
- // during the all list and appearing in n.
- // Also record whether there are any writes to main memory.
- // Also record whether there are any writes to variables
- // whose addresses have been taken.
- memwrite = 0;
- varwrite = 0;
- for(l=all; l!=stop; l=l->next) {
- a = outervalue(l->n->left);
- if(a->op != ONAME) {
- memwrite = 1;
- continue;
- }
- switch(n->class) {
- default:
- varwrite = 1;
- continue;
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- if(n->addrtaken) {
- varwrite = 1;
- continue;
- }
- if(vmatch2(a, n)) {
- // Direct hit.
- return 1;
- }
- }
- }
-
- // The variables being written do not appear in n.
- // However, n might refer to computed addresses
- // that are being written.
-
- // If no computed addresses are affected by the writes, no aliasing.
- if(!memwrite && !varwrite)
- return 0;
-
- // If n does not refer to computed addresses
- // (that is, if n only refers to variables whose addresses
- // have not been taken), no aliasing.
- if(varexpr(n))
- return 0;
-
- // Otherwise, both the writes and n refer to computed memory addresses.
- // Assume that they might conflict.
- return 1;
-}
-
-/*
- * does the evaluation of n only refer to variables
- * whose addresses have not been taken?
- * (and no other memory)
- */
-static int
-varexpr(Node *n)
-{
- if(n == N)
- return 1;
-
- switch(n->op) {
- case OLITERAL:
- return 1;
- case ONAME:
- switch(n->class) {
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- if(!n->addrtaken)
- return 1;
- }
- return 0;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- case OMUL:
- case ODIV:
- case OMOD:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- case OPLUS:
- case OMINUS:
- case OCOM:
- case OPAREN:
- case OANDAND:
- case OOROR:
- case ODOT: // but not ODOTPTR
- case OCONV:
- case OCONVNOP:
- case OCONVIFACE:
- case ODOTTYPE:
- return varexpr(n->left) && varexpr(n->right);
- }
-
- // Be conservative.
- return 0;
-}
-
-/*
- * is the name l mentioned in r?
- */
-static int
-vmatch2(Node *l, Node *r)
-{
- NodeList *ll;
-
- if(r == N)
- return 0;
- switch(r->op) {
- case ONAME:
- // match each right given left
- return l == r;
- case OLITERAL:
- return 0;
- }
- if(vmatch2(l, r->left))
- return 1;
- if(vmatch2(l, r->right))
- return 1;
- for(ll=r->list; ll; ll=ll->next)
- if(vmatch2(l, ll->n))
- return 1;
- return 0;
-}
-
-/*
- * is any name mentioned in l also mentioned in r?
- * called by sinit.c
- */
-int
-vmatch1(Node *l, Node *r)
-{
- NodeList *ll;
-
- /*
- * isolate all left sides
- */
- if(l == N || r == N)
- return 0;
- switch(l->op) {
- case ONAME:
- switch(l->class) {
- case PPARAM:
- case PPARAMREF:
- case PAUTO:
- break;
- default:
- // assignment to non-stack variable
- // must be delayed if right has function calls.
- if(r->ullman >= UINF)
- return 1;
- break;
- }
- return vmatch2(l, r);
- case OLITERAL:
- return 0;
- }
- if(vmatch1(l->left, r))
- return 1;
- if(vmatch1(l->right, r))
- return 1;
- for(ll=l->list; ll; ll=ll->next)
- if(vmatch1(ll->n, r))
- return 1;
- return 0;
-}
-
-/*
- * walk through argin parameters.
- * generate and return code to allocate
- * copies of escaped parameters to the heap.
- */
-static NodeList*
-paramstoheap(Type **argin, int out)
-{
- Type *t;
- Iter savet;
- Node *v, *as;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
- v = N;
- // For precise stacks, the garbage collector assumes results
- // are always live, so zero them always.
- if(out) {
- // Defer might stop a panic and show the
- // return values as they exist at the time of panic.
- // Make sure to zero them on entry to the function.
- nn = list(nn, nod(OAS, nodarg(t, 1), N));
- }
- if(v == N || !(v->class & PHEAP))
- continue;
-
- // generate allocation & copying code
- if(compiling_runtime)
- yyerror("%N escapes to heap, not allowed in runtime.", v);
- if(v->alloc == nil)
- v->alloc = callnew(v->type);
- nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
- if((v->class & ~PHEAP) != PPARAMOUT) {
- as = nod(OAS, v, v->stackparam);
- v->stackparam->typecheck = 1;
- typecheck(&as, Etop);
- as = applywritebarrier(as, &nn);
- nn = list(nn, as);
- }
- }
- return nn;
-}
-
-/*
- * walk through argout parameters copying back to stack
- */
-static NodeList*
-returnsfromheap(Type **argin)
-{
- Type *t;
- Iter savet;
- Node *v;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v == N || v->class != (PHEAP|PPARAMOUT))
- continue;
- nn = list(nn, nod(OAS, v->stackparam, v));
- }
- return nn;
-}
-
-/*
- * take care of migrating any function in/out args
- * between the stack and the heap. adds code to
- * curfn's before and after lists.
- */
-static void
-heapmoves(void)
-{
- NodeList *nn;
- int32 lno;
-
- lno = lineno;
- lineno = curfn->lineno;
- nn = paramstoheap(getthis(curfn->type), 0);
- nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
- nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
- curfn->enter = concat(curfn->enter, nn);
- lineno = curfn->endlineno;
- curfn->exit = returnsfromheap(getoutarg(curfn->type));
- lineno = lno;
-}
-
-static Node*
-vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
-{
- int i, n;
- Node *r;
- NodeList *args;
-
- if(fn->type == T || fn->type->etype != TFUNC)
- fatal("mkcall %N %T", fn, fn->type);
-
- args = nil;
- n = fn->type->intuple;
- for(i=0; i<n; i++)
- args = list(args, va_arg(va, Node*));
-
- r = nod(OCALL, fn, N);
- r->list = args;
- if(fn->type->outtuple > 0)
- typecheck(&r, Erv | Efnstruct);
- else
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->type = t;
- return r;
-}
-
-Node*
-mkcall(char *name, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(syslook(name, 0), t, init, va);
- va_end(va);
- return r;
-}
-
-Node*
-mkcall1(Node *fn, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(fn, t, init, va);
- va_end(va);
- return r;
-}
-
-Node*
-conv(Node *n, Type *t)
-{
- if(eqtype(n->type, t))
- return n;
- n = nod(OCONV, n, N);
- n->type = t;
- typecheck(&n, Erv);
- return n;
-}
-
-Node*
-chanfn(char *name, int n, Type *t)
-{
- Node *fn;
- int i;
-
- if(t->etype != TCHAN)
- fatal("chanfn %T", t);
- fn = syslook(name, 1);
- for(i=0; i<n; i++)
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-mapfn(char *name, Type *t)
-{
- Node *fn;
-
- if(t->etype != TMAP)
- fatal("mapfn %T", t);
- fn = syslook(name, 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, t->down);
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-mapfndel(char *name, Type *t)
-{
- Node *fn;
-
- if(t->etype != TMAP)
- fatal("mapfn %T", t);
- fn = syslook(name, 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, t->down);
- return fn;
-}
-
-static Node*
-writebarrierfn(char *name, Type *l, Type *r)
-{
- Node *fn;
-
- fn = syslook(name, 1);
- argtype(fn, l);
- argtype(fn, r);
- return fn;
-}
-
-static Node*
-addstr(Node *n, NodeList **init)
-{
- Node *r, *cat, *slice, *buf;
- NodeList *args, *l;
- int c;
- vlong sz;
- Type *t;
-
- // orderexpr rewrote OADDSTR to have a list of strings.
- c = count(n->list);
- if(c < 2)
- yyerror("addstr count %d too small", c);
-
- buf = nodnil();
- if(n->esc == EscNone) {
- sz = 0;
- for(l=n->list; l != nil; l=l->next) {
- if(n->op == OLITERAL)
- sz += n->val.u.sval->len;
- }
- // Don't allocate the buffer if the result won't fit.
- if(sz < tmpstringbufsize) {
- // Create temporary buffer for result string on stack.
- t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
- buf = nod(OADDR, temp(t), N);
- }
- }
-
- // build list of string arguments
- args = list1(buf);
- for(l=n->list; l != nil; l=l->next)
- args = list(args, conv(l->n, types[TSTRING]));
-
- if(c <= 5) {
- // small numbers of strings use direct runtime helpers.
- // note: orderexpr knows this cutoff too.
- snprint(namebuf, sizeof(namebuf), "concatstring%d", c);
- } else {
- // large numbers of strings are passed to the runtime as a slice.
- strcpy(namebuf, "concatstrings");
- t = typ(TARRAY);
- t->type = types[TSTRING];
- t->bound = -1;
- slice = nod(OCOMPLIT, N, typenod(t));
- slice->alloc = n->alloc;
- slice->list = args->next; // skip buf arg
- args = list1(buf);
- args = list(args, slice);
- slice->esc = EscNone;
- }
- cat = syslook(namebuf, 1);
- r = nod(OCALL, cat, N);
- r->list = args;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
-
- return r;
-}
-
-// expand append(l1, l2...) to
-// init {
-// s := l1
-// if n := len(l1) + len(l2) - cap(s); n > 0 {
-// s = growslice(s, n)
-// }
-// s = s[:len(l1)+len(l2)]
-// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
-// }
-// s
-//
-// l2 is allowed to be a string.
-static Node*
-appendslice(Node *n, NodeList **init)
-{
- NodeList *l;
- Node *l1, *l2, *nt, *nif, *fn;
- Node *nptr1, *nptr2, *nwid;
- Node *s;
-
- walkexprlistsafe(n->list, init);
-
- // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
- // and n are name or literal, but those may index the slice we're
- // modifying here. Fix explicitly.
- for(l=n->list; l; l=l->next)
- l->n = cheapexpr(l->n, init);
-
- l1 = n->list->n;
- l2 = n->list->next->n;
-
- s = temp(l1->type); // var s []T
- l = nil;
- l = list(l, nod(OAS, s, l1)); // s = l1
-
- nt = temp(types[TINT]);
- nif = nod(OIF, N, N);
- // n := len(s) + len(l2) - cap(s)
- nif->ninit = list1(nod(OAS, nt,
- nod(OSUB, nod(OADD, nod(OLEN, s, N), nod(OLEN, l2, N)), nod(OCAP, s, N))));
- nif->ntest = nod(OGT, nt, nodintconst(0));
- // instantiate growslice(Type*, []any, int64) []any
- fn = syslook("growslice", 1);
- argtype(fn, s->type->type);
- argtype(fn, s->type->type);
-
- // s = growslice(T, s, n)
- nif->nbody = list1(nod(OAS, s, mkcall1(fn, s->type, &nif->ninit,
- typename(s->type),
- s,
- conv(nt, types[TINT64]))));
-
- l = list(l, nif);
-
- if(haspointers(l1->type->type)) {
- // copy(s[len(l1):len(l1)+len(l2)], l2)
- nptr1 = nod(OSLICE, s, nod(OKEY,
- nod(OLEN, l1, N),
- nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N))));
- nptr1->etype = 1;
- nptr2 = l2;
- fn = syslook("typedslicecopy", 1);
- argtype(fn, l1->type);
- argtype(fn, l2->type);
- nt = mkcall1(fn, types[TINT], &l,
- typename(l1->type->type),
- nptr1, nptr2);
- l = list(l, nt);
- } else if(flag_race) {
- // rely on runtime to instrument copy.
- // copy(s[len(l1):len(l1)+len(l2)], l2)
- nptr1 = nod(OSLICE, s, nod(OKEY,
- nod(OLEN, l1, N),
- nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N))));
- nptr1->etype = 1;
- nptr2 = l2;
- if(l2->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("slicecopy", 1);
- argtype(fn, l1->type);
- argtype(fn, l2->type);
- nt = mkcall1(fn, types[TINT], &l,
- nptr1, nptr2,
- nodintconst(s->type->type->width));
- l = list(l, nt);
- } else {
- // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
- nptr1 = nod(OINDEX, s, nod(OLEN, l1, N));
- nptr1->bounded = 1;
- nptr1 = nod(OADDR, nptr1, N);
-
- nptr2 = nod(OSPTR, l2, N);
-
- fn = syslook("memmove", 1);
- argtype(fn, s->type->type); // 1 old []any
- argtype(fn, s->type->type); // 2 ret []any
-
- nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
- nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
- nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
- l = list(l, nt);
- }
-
- // s = s[:len(l1)+len(l2)]
- nt = nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N));
- nt = nod(OSLICE, s, nod(OKEY, N, nt));
- nt->etype = 1;
- l = list(l, nod(OAS, s, nt));
-
- typechecklist(l, Etop);
- walkstmtlist(l);
- *init = concat(*init, l);
- return s;
-}
-
-// expand append(src, a [, b]* ) to
-//
-// init {
-// s := src
-// const argc = len(args) - 1
-// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
-// }
-// n := len(s)
-// s = s[:n+argc]
-// s[n] = a
-// s[n+1] = b
-// ...
-// }
-// s
-static Node*
-append(Node *n, NodeList **init)
-{
- NodeList *l, *a;
- Node *nsrc, *ns, *nn, *na, *nx, *fn;
- int argc;
-
- walkexprlistsafe(n->list, init);
-
- // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
- // and n are name or literal, but those may index the slice we're
- // modifying here. Fix explicitly.
- for(l=n->list; l; l=l->next)
- l->n = cheapexpr(l->n, init);
-
- nsrc = n->list->n;
-
- // Resolve slice type of multi-valued return.
- if(istype(nsrc->type, TSTRUCT))
- nsrc->type = nsrc->type->type->type;
- argc = count(n->list) - 1;
- if (argc < 1) {
- return nsrc;
- }
-
- l = nil;
-
- ns = temp(nsrc->type);
- l = list(l, nod(OAS, ns, nsrc)); // s = src
-
- na = nodintconst(argc); // const argc
- nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
- nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
-
- fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
- argtype(fn, ns->type->type); // 1 old []any
- argtype(fn, ns->type->type); // 2 ret []any
-
- nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
- typename(ns->type),
- ns,
- conv(na, types[TINT64]))));
- l = list(l, nx);
-
- nn = temp(types[TINT]);
- l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
-
- nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
- nx->etype = 1;
- l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
-
- for (a = n->list->next; a != nil; a = a->next) {
- nx = nod(OINDEX, ns, nn); // s[n] ...
- nx->bounded = 1;
- l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
- if (a->next != nil)
- l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
- }
-
- typechecklist(l, Etop);
- walkstmtlist(l);
- *init = concat(*init, l);
- return ns;
-}
-
-// Lower copy(a, b) to a memmove call or a runtime call.
-//
-// init {
-// n := len(a)
-// if n > len(b) { n = len(b) }
-// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
-// }
-// n;
-//
-// Also works if b is a string.
-//
-static Node*
-copyany(Node *n, NodeList **init, int runtimecall)
-{
- Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
- NodeList *l;
-
- if(haspointers(n->left->type->type)) {
- fn = writebarrierfn("typedslicecopy", n->left->type, n->right->type);
- return mkcall1(fn, n->type, init, typename(n->left->type->type), n->left, n->right);
- }
-
- if(runtimecall) {
- if(n->right->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("slicecopy", 1);
- argtype(fn, n->left->type);
- argtype(fn, n->right->type);
- return mkcall1(fn, n->type, init,
- n->left, n->right,
- nodintconst(n->left->type->type->width));
- }
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- nl = temp(n->left->type);
- nr = temp(n->right->type);
- l = nil;
- l = list(l, nod(OAS, nl, n->left));
- l = list(l, nod(OAS, nr, n->right));
-
- nfrm = nod(OSPTR, nr, N);
- nto = nod(OSPTR, nl, N);
-
- nlen = temp(types[TINT]);
- // n = len(to)
- l = list(l, nod(OAS, nlen, nod(OLEN, nl, N)));
- // if n > len(frm) { n = len(frm) }
- nif = nod(OIF, N, N);
- nif->ntest = nod(OGT, nlen, nod(OLEN, nr, N));
- nif->nbody = list(nif->nbody,
- nod(OAS, nlen, nod(OLEN, nr, N)));
- l = list(l, nif);
-
- // Call memmove.
- fn = syslook("memmove", 1);
- argtype(fn, nl->type->type);
- argtype(fn, nl->type->type);
- nwid = temp(types[TUINTPTR]);
- l = list(l, nod(OAS, nwid, conv(nlen, types[TUINTPTR])));
- nwid = nod(OMUL, nwid, nodintconst(nl->type->type->width));
- l = list(l, mkcall1(fn, T, init, nto, nfrm, nwid));
-
- typechecklist(l, Etop);
- walkstmtlist(l);
- *init = concat(*init, l);
- return nlen;
-}
-
-// Generate frontend part for OSLICE[3][ARR|STR]
-//
-static Node*
-sliceany(Node* n, NodeList **init)
-{
- int bounded, slice3;
- Node *src, *lb, *hb, *cb, *bound, *chk, *chk0, *chk1, *chk2;
- int64 lbv, hbv, cbv, bv, w;
- Type *bt;
-
-// print("before sliceany: %+N\n", n);
-
- src = n->left;
- lb = n->right->left;
- slice3 = n->op == OSLICE3 || n->op == OSLICE3ARR;
- if(slice3) {
- hb = n->right->right->left;
- cb = n->right->right->right;
- } else {
- hb = n->right->right;
- cb = N;
- }
-
- bounded = n->etype;
-
- if(n->op == OSLICESTR)
- bound = nod(OLEN, src, N);
- else
- bound = nod(OCAP, src, N);
-
- typecheck(&bound, Erv);
- walkexpr(&bound, init); // if src is an array, bound will be a const now.
-
- // static checks if possible
- bv = 1LL<<50;
- if(isconst(bound, CTINT)) {
- if(!smallintconst(bound))
- yyerror("array len too large");
- else
- bv = mpgetfix(bound->val.u.xval);
- }
-
- if(isconst(cb, CTINT)) {
- cbv = mpgetfix(cb->val.u.xval);
- if(cbv < 0 || cbv > bv)
- yyerror("slice index out of bounds");
- }
- if(isconst(hb, CTINT)) {
- hbv = mpgetfix(hb->val.u.xval);
- if(hbv < 0 || hbv > bv)
- yyerror("slice index out of bounds");
- }
- if(isconst(lb, CTINT)) {
- lbv = mpgetfix(lb->val.u.xval);
- if(lbv < 0 || lbv > bv) {
- yyerror("slice index out of bounds");
- lbv = -1;
- }
- if(lbv == 0)
- lb = N;
- }
-
- // Checking src[lb:hb:cb] or src[lb:hb].
- // if chk0 || chk1 || chk2 { panicslice() }
- chk = N;
- chk0 = N; // cap(src) < cb
- chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
- chk2 = N; // hb < lb
-
- // All comparisons are unsigned to avoid testing < 0.
- bt = types[simtype[TUINT]];
- if(cb != N && cb->type->width > 4)
- bt = types[TUINT64];
- if(hb != N && hb->type->width > 4)
- bt = types[TUINT64];
- if(lb != N && lb->type->width > 4)
- bt = types[TUINT64];
-
- bound = cheapexpr(conv(bound, bt), init);
-
- if(cb != N) {
- cb = cheapexpr(conv(cb, bt), init);
- if(!bounded)
- chk0 = nod(OLT, bound, cb);
- } else if(slice3) {
- // When we figure out what this means, implement it.
- fatal("slice3 with cb == N"); // rejected by parser
- }
-
- if(hb != N) {
- hb = cheapexpr(conv(hb, bt), init);
- if(!bounded) {
- if(cb != N)
- chk1 = nod(OLT, cb, hb);
- else
- chk1 = nod(OLT, bound, hb);
- }
- } else if(slice3) {
- // When we figure out what this means, implement it.
- fatal("slice3 with hb == N"); // rejected by parser
- } else if(n->op == OSLICEARR) {
- hb = bound;
- } else {
- hb = nod(OLEN, src, N);
- typecheck(&hb, Erv);
- walkexpr(&hb, init);
- hb = cheapexpr(conv(hb, bt), init);
- }
-
- if(lb != N) {
- lb = cheapexpr(conv(lb, bt), init);
- if(!bounded)
- chk2 = nod(OLT, hb, lb);
- }
-
- if(chk0 != N || chk1 != N || chk2 != N) {
- chk = nod(OIF, N, N);
- chk->nbody = list1(mkcall("panicslice", T, init));
- chk->likely = -1;
- if(chk0 != N)
- chk->ntest = chk0;
- if(chk1 != N) {
- if(chk->ntest == N)
- chk->ntest = chk1;
- else
- chk->ntest = nod(OOROR, chk->ntest, chk1);
- }
- if(chk2 != N) {
- if(chk->ntest == N)
- chk->ntest = chk2;
- else
- chk->ntest = nod(OOROR, chk->ntest, chk2);
- }
- typecheck(&chk, Etop);
- walkstmt(&chk);
- *init = concat(*init, chk->ninit);
- chk->ninit = nil;
- *init = list(*init, chk);
- }
-
- // prepare new cap, len and offs for backend cgen_slice
- // cap = bound [ - lo ]
- n->right = N;
- n->list = nil;
- if(!slice3)
- cb = bound;
- if(lb == N)
- bound = conv(cb, types[simtype[TUINT]]);
- else
- bound = nod(OSUB, conv(cb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
- typecheck(&bound, Erv);
- walkexpr(&bound, init);
- n->list = list(n->list, bound);
-
- // len = hi [ - lo]
- if(lb == N)
- hb = conv(hb, types[simtype[TUINT]]);
- else
- hb = nod(OSUB, conv(hb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
- typecheck(&hb, Erv);
- walkexpr(&hb, init);
- n->list = list(n->list, hb);
-
- // offs = [width *] lo, but omit if zero
- if(lb != N) {
- if(n->op == OSLICESTR)
- w = 1;
- else
- w = n->type->type->width;
- lb = conv(lb, types[TUINTPTR]);
- if(w > 1)
- lb = nod(OMUL, nodintconst(w), lb);
- typecheck(&lb, Erv);
- walkexpr(&lb, init);
- n->list = list(n->list, lb);
- }
-
-// print("after sliceany: %+N\n", n);
-
- return n;
-}
-
-static Node*
-eqfor(Type *t, int *needsize)
-{
- int a;
- Node *n;
- Node *ntype;
- Sym *sym;
-
- // Should only arrive here with large memory or
- // a struct/array containing a non-memory field/element.
- // Small memory is handled inline, and single non-memory
- // is handled during type check (OCMPSTR etc).
- a = algtype1(t, nil);
- if(a != AMEM && a != -1)
- fatal("eqfor %T", t);
-
- if(a == AMEM) {
- n = syslook("memequal", 1);
- argtype(n, t);
- argtype(n, t);
- *needsize = 1;
- return n;
- }
-
- sym = typesymprefix(".eq", t);
- n = newname(sym);
- n->class = PFUNC;
- ntype = nod(OTFUNC, N, N);
- ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
- ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
- ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
- typecheck(&ntype, Etype);
- n->type = ntype->type;
- *needsize = 0;
- return n;
-}
-
-static int
-countfield(Type *t)
-{
- Type *t1;
- int n;
-
- n = 0;
- for(t1=t->type; t1!=T; t1=t1->down)
- n++;
- return n;
-}
-
-static void
-walkcompare(Node **np, NodeList **init)
-{
- Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
- Node *x, *ok;
- int andor, i, needsize;
- Type *t, *t1;
-
- n = *np;
-
- // Given interface value l and concrete value r, rewrite
- // l == r
- // to
- // x, ok := l.(type(r)); ok && x == r
- // Handle != similarly.
- // This avoids the allocation that would be required
- // to convert r to l for comparison.
- l = N;
- r = N;
- if(isinter(n->left->type) && !isinter(n->right->type)) {
- l = n->left;
- r = n->right;
- } else if(!isinter(n->left->type) && isinter(n->right->type)) {
- l = n->right;
- r = n->left;
- }
- if(l != N) {
- x = temp(r->type);
- ok = temp(types[TBOOL]);
-
- // l.(type(r))
- a = nod(ODOTTYPE, l, N);
- a->type = r->type;
-
- // x, ok := l.(type(r))
- expr = nod(OAS2, N, N);
- expr->list = list1(x);
- expr->list = list(expr->list, ok);
- expr->rlist = list1(a);
- typecheck(&expr, Etop);
- walkexpr(&expr, init);
-
- if(n->op == OEQ)
- r = nod(OANDAND, ok, nod(OEQ, x, r));
- else
- r = nod(OOROR, nod(ONOT, ok, N), nod(ONE, x, r));
- *init = list(*init, expr);
- goto ret;
- }
-
- // Must be comparison of array or struct.
- // Otherwise back end handles it.
- t = n->left->type;
- switch(t->etype) {
- default:
- return;
- case TARRAY:
- if(isslice(t))
- return;
- break;
- case TSTRUCT:
- break;
- }
-
- cmpl = n->left;
- while(cmpl != N && cmpl->op == OCONVNOP)
- cmpl = cmpl->left;
- cmpr = n->right;
- while(cmpr != N && cmpr->op == OCONVNOP)
- cmpr = cmpr->left;
-
- if(!islvalue(cmpl) || !islvalue(cmpr)) {
- fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
- }
-
- l = temp(ptrto(t));
- a = nod(OAS, l, nod(OADDR, cmpl, N));
- a->right->etype = 1; // addr does not escape
- typecheck(&a, Etop);
- *init = list(*init, a);
-
- r = temp(ptrto(t));
- a = nod(OAS, r, nod(OADDR, cmpr, N));
- a->right->etype = 1; // addr does not escape
- typecheck(&a, Etop);
- *init = list(*init, a);
-
- expr = N;
- andor = OANDAND;
- if(n->op == ONE)
- andor = OOROR;
-
- if(t->etype == TARRAY &&
- t->bound <= 4 &&
- issimple[t->type->etype]) {
- // Four or fewer elements of a basic type.
- // Unroll comparisons.
- for(i=0; i<t->bound; i++) {
- li = nod(OINDEX, l, nodintconst(i));
- ri = nod(OINDEX, r, nodintconst(i));
- a = nod(n->op, li, ri);
- if(expr == N)
- expr = a;
- else
- expr = nod(andor, expr, a);
- }
- if(expr == N)
- expr = nodbool(n->op == OEQ);
- r = expr;
- goto ret;
- }
-
- if(t->etype == TSTRUCT && countfield(t) <= 4) {
- // Struct of four or fewer fields.
- // Inline comparisons.
- for(t1=t->type; t1; t1=t1->down) {
- if(isblanksym(t1->sym))
- continue;
- li = nod(OXDOT, l, newname(t1->sym));
- ri = nod(OXDOT, r, newname(t1->sym));
- a = nod(n->op, li, ri);
- if(expr == N)
- expr = a;
- else
- expr = nod(andor, expr, a);
- }
- if(expr == N)
- expr = nodbool(n->op == OEQ);
- r = expr;
- goto ret;
- }
-
- // Chose not to inline. Call equality function directly.
- call = nod(OCALL, eqfor(t, &needsize), N);
- call->list = list(call->list, l);
- call->list = list(call->list, r);
- if(needsize)
- call->list = list(call->list, nodintconst(t->width));
- r = call;
- if(n->op != OEQ)
- r = nod(ONOT, r, N);
- goto ret;
-
-ret:
- typecheck(&r, Erv);
- walkexpr(&r, init);
- if(r->type != n->type) {
- r = nod(OCONVNOP, r, N);
- r->type = n->type;
- r->typecheck = 1;
- }
- *np = r;
- return;
-}
-
-static int
-samecheap(Node *a, Node *b)
-{
- Node *ar, *br;
- while(a != N && b != N && a->op == b->op) {
- switch(a->op) {
- default:
- return 0;
- case ONAME:
- return a == b;
- case ODOT:
- case ODOTPTR:
- ar = a->right;
- br = b->right;
- if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym)
- return 0;
- break;
- case OINDEX:
- ar = a->right;
- br = b->right;
- if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0)
- return 0;
- break;
- }
- a = a->left;
- b = b->left;
- }
- return 0;
-}
-
-static void
-walkrotate(Node **np)
-{
- int w, sl, sr, s;
- Node *l, *r;
- Node *n;
-
- if(thearch.thechar == '9')
- return;
-
- n = *np;
-
- // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
- l = n->left;
- r = n->right;
- if((n->op != OOR && n->op != OXOR) ||
- (l->op != OLSH && l->op != ORSH) ||
- (r->op != OLSH && r->op != ORSH) ||
- n->type == T || issigned[n->type->etype] ||
- l->op == r->op) {
- return;
- }
-
- // Want same, side effect-free expression on lhs of both shifts.
- if(!samecheap(l->left, r->left))
- return;
-
- // Constants adding to width?
- w = l->type->width * 8;
- if(smallintconst(l->right) && smallintconst(r->right)) {
- if((sl=mpgetfix(l->right->val.u.xval)) >= 0 && (sr=mpgetfix(r->right->val.u.xval)) >= 0 && sl+sr == w)
- goto yes;
- return;
- }
-
- // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
- return;
-
-yes:
- // Rewrite left shift half to left rotate.
- if(l->op == OLSH)
- n = l;
- else
- n = r;
- n->op = OLROT;
-
- // Remove rotate 0 and rotate w.
- s = mpgetfix(n->right->val.u.xval);
- if(s == 0 || s == w)
- n = n->left;
-
- *np = n;
- return;
-}
-
-/*
- * walkmul rewrites integer multiplication by powers of two as shifts.
- */
-static void
-walkmul(Node **np, NodeList **init)
-{
- Node *n, *nl, *nr;
- int pow, neg, w;
-
- n = *np;
- if(!isint[n->type->etype])
- return;
-
- if(n->right->op == OLITERAL) {
- nl = n->left;
- nr = n->right;
- } else if(n->left->op == OLITERAL) {
- nl = n->right;
- nr = n->left;
- } else
- return;
-
- neg = 0;
-
- // x*0 is 0 (and side effects of x).
- if(mpgetfix(nr->val.u.xval) == 0) {
- cheapexpr(nl, init);
- nodconst(n, n->type, 0);
- goto ret;
- }
-
- // nr is a constant.
- pow = powtwo(nr);
- if(pow < 0)
- return;
- if(pow >= 1000) {
- // negative power of 2, like -16
- neg = 1;
- pow -= 1000;
- }
-
- w = nl->type->width*8;
- if(pow+1 >= w)// too big, shouldn't happen
- return;
-
- nl = cheapexpr(nl, init);
-
- if(pow == 0) {
- // x*1 is x
- n = nl;
- goto ret;
- }
-
- n = nod(OLSH, nl, nodintconst(pow));
-
-ret:
- if(neg)
- n = nod(OMINUS, n, N);
-
- typecheck(&n, Erv);
- walkexpr(&n, init);
- *np = n;
-}
-
-/*
- * walkdiv rewrites division by a constant as less expensive
- * operations.
- */
-static void
-walkdiv(Node **np, NodeList **init)
-{
- Node *n, *nl, *nr, *nc;
- Node *n1, *n2, *n3, *n4;
- int pow; // if >= 0, nr is 1<<pow
- int s; // 1 if nr is negative.
- int w;
- Type *twide;
- Magic m;
-
- // TODO(minux)
- if(thearch.thechar == '9')
- return;
-
- n = *np;
- if(n->right->op != OLITERAL)
- return;
- // nr is a constant.
- nl = cheapexpr(n->left, init);
- nr = n->right;
-
- // special cases of mod/div
- // by a constant
- w = nl->type->width*8;
- s = 0;
- pow = powtwo(nr);
- if(pow >= 1000) {
- // negative power of 2
- s = 1;
- pow -= 1000;
- }
-
- if(pow+1 >= w) {
- // divisor too large.
- return;
- }
- if(pow < 0) {
- goto divbymul;
- }
-
- switch(pow) {
- case 0:
- if(n->op == OMOD) {
- // nl % 1 is zero.
- nodconst(n, n->type, 0);
- } else if(s) {
- // divide by -1
- n->op = OMINUS;
- n->right = N;
- } else {
- // divide by 1
- n = nl;
- }
- break;
- default:
- if(issigned[n->type->etype]) {
- if(n->op == OMOD) {
- // signed modulo 2^pow is like ANDing
- // with the last pow bits, but if nl < 0,
- // nl & (2^pow-1) is (nl+1)%2^pow - 1.
- nc = nod(OXXX, N, N);
- nodconst(nc, types[simtype[TUINT]], w-1);
- n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
- if(pow == 1) {
- typecheck(&n1, Erv);
- n1 = cheapexpr(n1, init);
- // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
- n2 = nod(OSUB, nl, n1);
- nc = nod(OXXX, N, N);
- nodconst(nc, nl->type, 1);
- n3 = nod(OAND, n2, nc);
- n = nod(OADD, n3, n1);
- } else {
- // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
- nc = nod(OXXX, N, N);
- nodconst(nc, nl->type, (1LL<<pow)-1);
- n2 = nod(OAND, n1, nc); // n2 = 2^pow-1 iff nl<0.
- typecheck(&n2, Erv);
- n2 = cheapexpr(n2, init);
-
- n3 = nod(OADD, nl, n2);
- n4 = nod(OAND, n3, nc);
- n = nod(OSUB, n4, n2);
- }
- break;
- } else {
- // arithmetic right shift does not give the correct rounding.
- // if nl >= 0, nl >> n == nl / nr
- // if nl < 0, we want to add 2^n-1 first.
- nc = nod(OXXX, N, N);
- nodconst(nc, types[simtype[TUINT]], w-1);
- n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
- if(pow == 1) {
- // nl+1 is nl-(-1)
- n->left = nod(OSUB, nl, n1);
- } else {
- // Do a logical right right on -1 to keep pow bits.
- nc = nod(OXXX, N, N);
- nodconst(nc, types[simtype[TUINT]], w-pow);
- n2 = nod(ORSH, conv(n1, tounsigned(nl->type)), nc);
- n->left = nod(OADD, nl, conv(n2, nl->type));
- }
- // n = (nl + 2^pow-1) >> pow
- n->op = ORSH;
- nc = nod(OXXX, N, N);
- nodconst(nc, types[simtype[TUINT]], pow);
- n->right = nc;
- n->typecheck = 0;
- }
- if(s)
- n = nod(OMINUS, n, N);
- break;
- }
- nc = nod(OXXX, N, N);
- if(n->op == OMOD) {
- // n = nl & (nr-1)
- n->op = OAND;
- nodconst(nc, nl->type, mpgetfix(nr->val.u.xval)-1);
- } else {
- // n = nl >> pow
- n->op = ORSH;
- nodconst(nc, types[simtype[TUINT]], pow);
- }
- n->typecheck = 0;
- n->right = nc;
- break;
- }
- goto ret;
-
-divbymul:
- // try to do division by multiply by (2^w)/d
- // see hacker's delight chapter 10
- // TODO: support 64-bit magic multiply here.
- m.w = w;
- if(issigned[nl->type->etype]) {
- m.sd = mpgetfix(nr->val.u.xval);
- smagic(&m);
- } else {
- m.ud = mpgetfix(nr->val.u.xval);
- umagic(&m);
- }
- if(m.bad)
- return;
-
- // We have a quick division method so use it
- // for modulo too.
- if(n->op == OMOD)
- goto longmod;
-
- switch(simtype[nl->type->etype]) {
- default:
- return;
-
- case TUINT8:
- case TUINT16:
- case TUINT32:
- // n1 = nl * magic >> w (HMUL)
- nc = nod(OXXX, N, N);
- nodconst(nc, nl->type, m.um);
- n1 = nod(OMUL, nl, nc);
- typecheck(&n1, Erv);
- n1->op = OHMUL;
- if(m.ua) {
- // Select a Go type with (at least) twice the width.
- switch(simtype[nl->type->etype]) {
- default:
- return;
- case TUINT8:
- case TUINT16:
- twide = types[TUINT32];
- break;
- case TUINT32:
- twide = types[TUINT64];
- break;
- case TINT8:
- case TINT16:
- twide = types[TINT32];
- break;
- case TINT32:
- twide = types[TINT64];
- break;
- }
-
- // add numerator (might overflow).
- // n2 = (n1 + nl)
- n2 = nod(OADD, conv(n1, twide), conv(nl, twide));
-
- // shift by m.s
- nc = nod(OXXX, N, N);
- nodconst(nc, types[TUINT], m.s);
- n = conv(nod(ORSH, n2, nc), nl->type);
- } else {
- // n = n1 >> m.s
- nc = nod(OXXX, N, N);
- nodconst(nc, types[TUINT], m.s);
- n = nod(ORSH, n1, nc);
- }
- break;
-
- case TINT8:
- case TINT16:
- case TINT32:
- // n1 = nl * magic >> w
- nc = nod(OXXX, N, N);
- nodconst(nc, nl->type, m.sm);
- n1 = nod(OMUL, nl, nc);
- typecheck(&n1, Erv);
- n1->op = OHMUL;
- if(m.sm < 0) {
- // add the numerator.
- n1 = nod(OADD, n1, nl);
- }
- // shift by m.s
- nc = nod(OXXX, N, N);
- nodconst(nc, types[TUINT], m.s);
- n2 = conv(nod(ORSH, n1, nc), nl->type);
- // add 1 iff n1 is negative.
- nc = nod(OXXX, N, N);
- nodconst(nc, types[TUINT], w-1);
- n3 = nod(ORSH, nl, nc); // n4 = -1 iff n1 is negative.
- n = nod(OSUB, n2, n3);
- // apply sign.
- if(m.sd < 0)
- n = nod(OMINUS, n, N);
- break;
- }
- goto ret;
-
-longmod:
- // rewrite as A%B = A - (A/B*B).
- n1 = nod(ODIV, nl, nr);
- n2 = nod(OMUL, n1, nr);
- n = nod(OSUB, nl, n2);
- goto ret;
-
-ret:
- typecheck(&n, Erv);
- walkexpr(&n, init);
- *np = n;
-}
-
-// return 1 if integer n must be in range [0, max), 0 otherwise
-static int
-bounded(Node *n, int64 max)
-{
- int64 v;
- int32 bits;
- int sign;
-
- if(n->type == T || !isint[n->type->etype])
- return 0;
-
- sign = issigned[n->type->etype];
- bits = 8*n->type->width;
-
- if(smallintconst(n)) {
- v = mpgetfix(n->val.u.xval);
- return 0 <= v && v < max;
- }
-
- switch(n->op) {
- case OAND:
- v = -1;
- if(smallintconst(n->left)) {
- v = mpgetfix(n->left->val.u.xval);
- } else if(smallintconst(n->right)) {
- v = mpgetfix(n->right->val.u.xval);
- }
- if(0 <= v && v < max)
- return 1;
- break;
-
- case OMOD:
- if(!sign && smallintconst(n->right)) {
- v = mpgetfix(n->right->val.u.xval);
- if(0 <= v && v <= max)
- return 1;
- }
- break;
-
- case ODIV:
- if(!sign && smallintconst(n->right)) {
- v = mpgetfix(n->right->val.u.xval);
- while(bits > 0 && v >= 2) {
- bits--;
- v >>= 1;
- }
- }
- break;
-
- case ORSH:
- if(!sign && smallintconst(n->right)) {
- v = mpgetfix(n->right->val.u.xval);
- if(v > bits)
- return 1;
- bits -= v;
- }
- break;
- }
-
- if(!sign && bits <= 62 && (1LL<<bits) <= max)
- return 1;
-
- return 0;
-}
-
-void
-usefield(Node *n)
-{
- Type *field, *l;
-
- if(!fieldtrack_enabled)
- return;
-
- switch(n->op) {
- default:
- fatal("usefield %O", n->op);
- case ODOT:
- case ODOTPTR:
- break;
- }
-
- field = n->paramfld;
- if(field == T)
- fatal("usefield %T %S without paramfld", n->left->type, n->right->sym);
- if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil)
- return;
-
- // dedup on list
- if(field->lastfn == curfn)
- return;
- field->lastfn = curfn;
- field->outer = n->left->type;
- if(isptr[field->outer->etype])
- field->outer = field->outer->type;
- if(field->outer->sym == S)
- yyerror("tracked field must be in named struct type");
- if(!exportname(field->sym->name))
- yyerror("tracked field must be exported (upper case)");
-
- l = typ(0);
- l->type = field;
- l->down = curfn->paramfld;
- curfn->paramfld = l;
-}
-
-static int
-candiscardlist(NodeList *l)
-{
- for(; l; l=l->next)
- if(!candiscard(l->n))
- return 0;
- return 1;
-}
-
-int
-candiscard(Node *n)
-{
- if(n == N)
- return 1;
-
- switch(n->op) {
- default:
- return 0;
-
- case ONAME:
- case ONONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- case OADDSTR:
- case OADDR:
- case OANDAND:
- case OARRAYBYTESTR:
- case OARRAYRUNESTR:
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- case OCAP:
- case OCMPIFACE:
- case OCMPSTR:
- case OCOMPLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- case OARRAYLIT:
- case OPTRLIT:
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case ODOT:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGT:
- case OGE:
- case OKEY:
- case OLEN:
- case OMUL:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- case ONEW:
- case ONOT:
- case OCOM:
- case OPLUS:
- case OMINUS:
- case OOROR:
- case OPAREN:
- case ORUNESTR:
- case OREAL:
- case OIMAG:
- case OCOMPLEX:
- // Discardable as long as the subpieces are.
- break;
-
- case ODIV:
- case OMOD:
- // Discardable as long as we know it's not division by zero.
- if(isconst(n->right, CTINT) && mpcmpfixc(n->right->val.u.xval, 0) != 0)
- break;
- if(isconst(n->right, CTFLT) && mpcmpfltc(n->right->val.u.fval, 0) != 0)
- break;
- return 0;
-
- case OMAKECHAN:
- case OMAKEMAP:
- // Discardable as long as we know it won't fail because of a bad size.
- if(isconst(n->left, CTINT) && mpcmpfixc(n->left->val.u.xval, 0) == 0)
- break;
- return 0;
-
- case OMAKESLICE:
- // Difficult to tell what sizes are okay.
- return 0;
- }
-
- if(!candiscard(n->left) ||
- !candiscard(n->right) ||
- !candiscard(n->ntest) ||
- !candiscard(n->nincr) ||
- !candiscardlist(n->ninit) ||
- !candiscardlist(n->nbody) ||
- !candiscardlist(n->nelse) ||
- !candiscardlist(n->list) ||
- !candiscardlist(n->rlist)) {
- return 0;
- }
-
- return 1;
-}
-
-// rewrite
-// print(x, y, z)
-// into
-// func(a1, a2, a3) {
-// print(a1, a2, a3)
-// }(x, y, z)
-// and same for println.
-static void
-walkprintfunc(Node **np, NodeList **init)
-{
- Node *n;
- Node *a, *fn, *t, *oldfn;
- NodeList *l, *printargs;
- int num;
- char buf[100];
- static int prgen;
-
- n = *np;
-
- if(n->ninit != nil) {
- walkstmtlist(n->ninit);
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- }
-
- t = nod(OTFUNC, N, N);
- num = 0;
- printargs = nil;
- for(l=n->list; l != nil; l=l->next) {
- snprint(buf, sizeof buf, "a%d", num++);
- a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
- t->list = list(t->list, a);
- printargs = list(printargs, a->left);
- }
-
- fn = nod(ODCLFUNC, N, N);
- snprint(buf, sizeof buf, "print·%d", ++prgen);
- fn->nname = newname(lookup(buf));
- fn->nname->defn = fn;
- fn->nname->ntype = t;
- declare(fn->nname, PFUNC);
-
- oldfn = curfn;
- curfn = nil;
- funchdr(fn);
-
- a = nod(n->op, N, N);
- a->list = printargs;
- typecheck(&a, Etop);
- walkstmt(&a);
-
- fn->nbody = list1(a);
-
- funcbody(fn);
-
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
- xtop = list(xtop, fn);
- curfn = oldfn;
-
- a = nod(OCALL, N, N);
- a->left = fn->nname;
- a->list = n->list;
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *np = a;
-}
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
deleted file mode 100644
index d45623a3e6..0000000000
--- a/src/cmd/gc/y.tab.c
+++ /dev/null
@@ -1,5134 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LLITERAL = 258,
- LASOP = 259,
- LCOLAS = 260,
- LBREAK = 261,
- LCASE = 262,
- LCHAN = 263,
- LCONST = 264,
- LCONTINUE = 265,
- LDDD = 266,
- LDEFAULT = 267,
- LDEFER = 268,
- LELSE = 269,
- LFALL = 270,
- LFOR = 271,
- LFUNC = 272,
- LGO = 273,
- LGOTO = 274,
- LIF = 275,
- LIMPORT = 276,
- LINTERFACE = 277,
- LMAP = 278,
- LNAME = 279,
- LPACKAGE = 280,
- LRANGE = 281,
- LRETURN = 282,
- LSELECT = 283,
- LSTRUCT = 284,
- LSWITCH = 285,
- LTYPE = 286,
- LVAR = 287,
- LANDAND = 288,
- LANDNOT = 289,
- LBODY = 290,
- LCOMM = 291,
- LDEC = 292,
- LEQ = 293,
- LGE = 294,
- LGT = 295,
- LIGNORE = 296,
- LINC = 297,
- LLE = 298,
- LLSH = 299,
- LLT = 300,
- LNE = 301,
- LOROR = 302,
- LRSH = 303,
- NotPackage = 304,
- NotParen = 305,
- PreferToRightParen = 306
- };
-#endif
-/* Tokens. */
-#define LLITERAL 258
-#define LASOP 259
-#define LCOLAS 260
-#define LBREAK 261
-#define LCASE 262
-#define LCHAN 263
-#define LCONST 264
-#define LCONTINUE 265
-#define LDDD 266
-#define LDEFAULT 267
-#define LDEFER 268
-#define LELSE 269
-#define LFALL 270
-#define LFOR 271
-#define LFUNC 272
-#define LGO 273
-#define LGOTO 274
-#define LIF 275
-#define LIMPORT 276
-#define LINTERFACE 277
-#define LMAP 278
-#define LNAME 279
-#define LPACKAGE 280
-#define LRANGE 281
-#define LRETURN 282
-#define LSELECT 283
-#define LSTRUCT 284
-#define LSWITCH 285
-#define LTYPE 286
-#define LVAR 287
-#define LANDAND 288
-#define LANDNOT 289
-#define LBODY 290
-#define LCOMM 291
-#define LDEC 292
-#define LEQ 293
-#define LGE 294
-#define LGT 295
-#define LIGNORE 296
-#define LINC 297
-#define LLE 298
-#define LLSH 299
-#define LLT 300
-#define LNE 301
-#define LOROR 302
-#define LRSH 303
-#define NotPackage 304
-#define NotParen 305
-#define PreferToRightParen 306
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 20 "go.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 28 "go.y"
-{
- Node* node;
- NodeList* list;
- Type* type;
- Sym* sym;
- struct Val val;
- int i;
-}
-/* Line 193 of yacc.c. */
-#line 216 "y.tab.c"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 229 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 4
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 2201
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 76
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 142
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 352
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 669
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 306
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 69, 2, 2, 64, 55, 56, 2,
- 59, 60, 53, 49, 75, 50, 63, 54, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 66, 62,
- 2, 65, 2, 73, 74, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 71, 2, 72, 52, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 67, 51, 68, 70, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 57, 58, 61
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 8, 9, 13, 14, 18, 19, 23,
- 26, 32, 36, 40, 43, 45, 49, 51, 54, 57,
- 62, 63, 65, 66, 71, 72, 74, 76, 78, 80,
- 83, 89, 93, 96, 102, 110, 114, 117, 123, 127,
- 129, 132, 137, 141, 146, 150, 152, 155, 157, 159,
- 162, 164, 168, 172, 176, 179, 182, 186, 192, 198,
- 201, 202, 207, 208, 212, 213, 216, 217, 222, 227,
- 232, 235, 241, 243, 245, 248, 249, 253, 255, 259,
- 260, 261, 262, 271, 272, 278, 279, 282, 283, 286,
- 287, 288, 296, 297, 303, 305, 309, 313, 317, 321,
- 325, 329, 333, 337, 341, 345, 349, 353, 357, 361,
- 365, 369, 373, 377, 381, 385, 387, 390, 393, 396,
- 399, 402, 405, 408, 411, 415, 421, 428, 430, 432,
- 436, 442, 448, 453, 460, 469, 471, 477, 483, 489,
- 497, 499, 500, 504, 506, 511, 513, 518, 520, 524,
- 526, 528, 530, 532, 534, 536, 538, 539, 541, 543,
- 545, 547, 552, 557, 559, 561, 563, 566, 568, 570,
- 572, 574, 576, 580, 582, 584, 586, 589, 591, 593,
- 595, 597, 601, 603, 605, 607, 609, 611, 613, 615,
- 617, 619, 623, 628, 633, 636, 640, 646, 648, 650,
- 653, 657, 663, 667, 673, 677, 681, 687, 696, 702,
- 711, 717, 718, 722, 723, 725, 729, 731, 736, 739,
- 740, 744, 746, 750, 752, 756, 758, 762, 764, 768,
- 770, 774, 778, 781, 786, 790, 796, 802, 804, 808,
- 810, 813, 815, 819, 824, 826, 829, 832, 834, 836,
- 840, 841, 844, 845, 847, 849, 851, 853, 855, 857,
- 859, 861, 863, 864, 869, 871, 874, 877, 880, 883,
- 886, 889, 891, 895, 897, 901, 903, 907, 909, 913,
- 915, 919, 921, 923, 927, 931, 932, 935, 936, 938,
- 939, 941, 942, 944, 945, 947, 948, 950, 951, 953,
- 954, 956, 957, 959, 960, 962, 967, 972, 978, 985,
- 990, 995, 997, 999, 1001, 1003, 1005, 1007, 1009, 1011,
- 1013, 1017, 1022, 1028, 1033, 1038, 1041, 1044, 1049, 1053,
- 1057, 1063, 1067, 1072, 1076, 1082, 1084, 1085, 1087, 1091,
- 1093, 1095, 1098, 1100, 1102, 1108, 1109, 1112, 1114, 1118,
- 1120, 1124, 1126
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int16 yyrhs[] =
-{
- 77, 0, -1, 79, 78, 81, 166, -1, -1, 25,
- 141, 62, -1, -1, 80, 86, 88, -1, -1, 81,
- 82, 62, -1, 21, 83, -1, 21, 59, 84, 190,
- 60, -1, 21, 59, 60, -1, 85, 86, 88, -1,
- 85, 88, -1, 83, -1, 84, 62, 83, -1, 3,
- -1, 141, 3, -1, 63, 3, -1, 25, 24, 87,
- 62, -1, -1, 24, -1, -1, 89, 214, 64, 64,
- -1, -1, 91, -1, 158, -1, 181, -1, 1, -1,
- 32, 93, -1, 32, 59, 167, 190, 60, -1, 32,
- 59, 60, -1, 92, 94, -1, 92, 59, 94, 190,
- 60, -1, 92, 59, 94, 62, 168, 190, 60, -1,
- 92, 59, 60, -1, 31, 97, -1, 31, 59, 169,
- 190, 60, -1, 31, 59, 60, -1, 9, -1, 185,
- 146, -1, 185, 146, 65, 186, -1, 185, 65, 186,
- -1, 185, 146, 65, 186, -1, 185, 65, 186, -1,
- 94, -1, 185, 146, -1, 185, -1, 141, -1, 96,
- 146, -1, 126, -1, 126, 4, 126, -1, 186, 65,
- 186, -1, 186, 5, 186, -1, 126, 42, -1, 126,
- 37, -1, 7, 187, 66, -1, 7, 187, 65, 126,
- 66, -1, 7, 187, 5, 126, 66, -1, 12, 66,
- -1, -1, 67, 101, 183, 68, -1, -1, 99, 103,
- 183, -1, -1, 104, 102, -1, -1, 35, 106, 183,
- 68, -1, 186, 65, 26, 126, -1, 186, 5, 26,
- 126, -1, 26, 126, -1, 194, 62, 194, 62, 194,
- -1, 194, -1, 107, -1, 108, 105, -1, -1, 16,
- 111, 109, -1, 194, -1, 194, 62, 194, -1, -1,
- -1, -1, 20, 114, 112, 115, 105, 116, 119, 120,
- -1, -1, 14, 20, 118, 112, 105, -1, -1, 119,
- 117, -1, -1, 14, 100, -1, -1, -1, 30, 122,
- 112, 123, 35, 104, 68, -1, -1, 28, 125, 35,
- 104, 68, -1, 127, -1, 126, 47, 126, -1, 126,
- 33, 126, -1, 126, 38, 126, -1, 126, 46, 126,
- -1, 126, 45, 126, -1, 126, 43, 126, -1, 126,
- 39, 126, -1, 126, 40, 126, -1, 126, 49, 126,
- -1, 126, 50, 126, -1, 126, 51, 126, -1, 126,
- 52, 126, -1, 126, 53, 126, -1, 126, 54, 126,
- -1, 126, 55, 126, -1, 126, 56, 126, -1, 126,
- 34, 126, -1, 126, 44, 126, -1, 126, 48, 126,
- -1, 126, 36, 126, -1, 134, -1, 53, 127, -1,
- 56, 127, -1, 49, 127, -1, 50, 127, -1, 69,
- 127, -1, 70, 127, -1, 52, 127, -1, 36, 127,
- -1, 134, 59, 60, -1, 134, 59, 187, 191, 60,
- -1, 134, 59, 187, 11, 191, 60, -1, 3, -1,
- 143, -1, 134, 63, 141, -1, 134, 63, 59, 135,
- 60, -1, 134, 63, 59, 31, 60, -1, 134, 71,
- 126, 72, -1, 134, 71, 192, 66, 192, 72, -1,
- 134, 71, 192, 66, 192, 66, 192, 72, -1, 128,
- -1, 149, 59, 126, 191, 60, -1, 150, 137, 130,
- 189, 68, -1, 129, 67, 130, 189, 68, -1, 59,
- 135, 60, 67, 130, 189, 68, -1, 165, -1, -1,
- 126, 66, 133, -1, 126, -1, 67, 130, 189, 68,
- -1, 126, -1, 67, 130, 189, 68, -1, 129, -1,
- 59, 135, 60, -1, 126, -1, 147, -1, 146, -1,
- 35, -1, 67, -1, 141, -1, 141, -1, -1, 138,
- -1, 24, -1, 142, -1, 73, -1, 74, 3, 63,
- 24, -1, 74, 3, 63, 73, -1, 141, -1, 138,
- -1, 11, -1, 11, 146, -1, 155, -1, 161, -1,
- 153, -1, 154, -1, 152, -1, 59, 146, 60, -1,
- 155, -1, 161, -1, 153, -1, 53, 147, -1, 161,
- -1, 153, -1, 154, -1, 152, -1, 59, 146, 60,
- -1, 161, -1, 153, -1, 153, -1, 155, -1, 161,
- -1, 153, -1, 154, -1, 152, -1, 143, -1, 143,
- 63, 141, -1, 71, 192, 72, 146, -1, 71, 11,
- 72, 146, -1, 8, 148, -1, 8, 36, 146, -1,
- 23, 71, 146, 72, 146, -1, 156, -1, 157, -1,
- 53, 146, -1, 36, 8, 146, -1, 29, 137, 170,
- 190, 68, -1, 29, 137, 68, -1, 22, 137, 171,
- 190, 68, -1, 22, 137, 68, -1, 17, 159, 162,
- -1, 141, 59, 179, 60, 163, -1, 59, 179, 60,
- 141, 59, 179, 60, 163, -1, 200, 59, 195, 60,
- 210, -1, 59, 215, 60, 141, 59, 195, 60, 210,
- -1, 17, 59, 179, 60, 163, -1, -1, 67, 183,
- 68, -1, -1, 151, -1, 59, 179, 60, -1, 161,
- -1, 164, 137, 183, 68, -1, 164, 1, -1, -1,
- 166, 90, 62, -1, 93, -1, 167, 62, 93, -1,
- 95, -1, 168, 62, 95, -1, 97, -1, 169, 62,
- 97, -1, 172, -1, 170, 62, 172, -1, 175, -1,
- 171, 62, 175, -1, 184, 146, 198, -1, 174, 198,
- -1, 59, 174, 60, 198, -1, 53, 174, 198, -1,
- 59, 53, 174, 60, 198, -1, 53, 59, 174, 60,
- 198, -1, 24, -1, 24, 63, 141, -1, 173, -1,
- 138, 176, -1, 173, -1, 59, 173, 60, -1, 59,
- 179, 60, 163, -1, 136, -1, 141, 136, -1, 141,
- 145, -1, 145, -1, 177, -1, 178, 75, 177, -1,
- -1, 178, 191, -1, -1, 100, -1, 91, -1, 181,
- -1, 1, -1, 98, -1, 110, -1, 121, -1, 124,
- -1, 113, -1, -1, 144, 66, 182, 180, -1, 15,
- -1, 6, 140, -1, 10, 140, -1, 18, 128, -1,
- 13, 128, -1, 19, 138, -1, 27, 193, -1, 180,
- -1, 183, 62, 180, -1, 138, -1, 184, 75, 138,
- -1, 139, -1, 185, 75, 139, -1, 126, -1, 186,
- 75, 126, -1, 135, -1, 187, 75, 135, -1, 131,
- -1, 132, -1, 188, 75, 131, -1, 188, 75, 132,
- -1, -1, 188, 191, -1, -1, 62, -1, -1, 75,
- -1, -1, 126, -1, -1, 186, -1, -1, 98, -1,
- -1, 215, -1, -1, 216, -1, -1, 217, -1, -1,
- 3, -1, 21, 24, 3, 62, -1, 32, 200, 202,
- 62, -1, 9, 200, 65, 213, 62, -1, 9, 200,
- 202, 65, 213, 62, -1, 31, 201, 202, 62, -1,
- 17, 160, 162, 62, -1, 142, -1, 200, -1, 204,
- -1, 205, -1, 206, -1, 204, -1, 206, -1, 142,
- -1, 24, -1, 71, 72, 202, -1, 71, 3, 72,
- 202, -1, 23, 71, 202, 72, 202, -1, 29, 67,
- 196, 68, -1, 22, 67, 197, 68, -1, 53, 202,
- -1, 8, 203, -1, 8, 59, 205, 60, -1, 8,
- 36, 202, -1, 36, 8, 202, -1, 17, 59, 195,
- 60, 210, -1, 141, 202, 198, -1, 141, 11, 202,
- 198, -1, 141, 202, 198, -1, 141, 59, 195, 60,
- 210, -1, 202, -1, -1, 211, -1, 59, 195, 60,
- -1, 202, -1, 3, -1, 50, 3, -1, 141, -1,
- 212, -1, 59, 212, 49, 212, 60, -1, -1, 214,
- 199, -1, 207, -1, 215, 75, 207, -1, 208, -1,
- 216, 62, 208, -1, 209, -1, 217, 62, 209, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 124, 124, 133, 139, 150, 150, 165, 166, 169,
- 170, 171, 174, 211, 222, 223, 226, 233, 240, 249,
- 263, 264, 271, 271, 284, 288, 289, 293, 298, 304,
- 308, 312, 316, 322, 328, 334, 339, 343, 347, 353,
- 359, 363, 367, 373, 377, 383, 384, 388, 394, 403,
- 409, 427, 432, 444, 460, 466, 474, 494, 512, 521,
- 540, 539, 554, 553, 585, 588, 595, 594, 605, 611,
- 618, 625, 636, 642, 645, 653, 652, 663, 669, 681,
- 685, 690, 680, 711, 710, 723, 726, 732, 735, 747,
- 751, 746, 769, 768, 784, 785, 789, 793, 797, 801,
- 805, 809, 813, 817, 821, 825, 829, 833, 837, 841,
- 845, 849, 853, 857, 862, 868, 869, 873, 884, 888,
- 892, 896, 901, 905, 915, 919, 924, 932, 936, 937,
- 948, 952, 956, 960, 964, 972, 973, 979, 986, 992,
- 999, 1002, 1009, 1015, 1032, 1039, 1040, 1047, 1048, 1067,
- 1068, 1071, 1074, 1078, 1089, 1098, 1104, 1107, 1110, 1117,
- 1118, 1124, 1137, 1152, 1160, 1172, 1177, 1183, 1184, 1185,
- 1186, 1187, 1188, 1194, 1195, 1196, 1197, 1203, 1204, 1205,
- 1206, 1207, 1213, 1214, 1217, 1220, 1221, 1222, 1223, 1224,
- 1227, 1228, 1241, 1245, 1250, 1255, 1260, 1264, 1265, 1268,
- 1274, 1281, 1287, 1294, 1300, 1311, 1327, 1356, 1394, 1419,
- 1437, 1446, 1449, 1457, 1461, 1465, 1472, 1478, 1483, 1495,
- 1498, 1510, 1511, 1517, 1518, 1524, 1528, 1534, 1535, 1541,
- 1545, 1551, 1574, 1579, 1585, 1591, 1598, 1607, 1616, 1631,
- 1637, 1642, 1646, 1653, 1666, 1667, 1673, 1679, 1682, 1686,
- 1692, 1695, 1704, 1707, 1708, 1712, 1713, 1719, 1720, 1721,
- 1722, 1723, 1725, 1724, 1739, 1745, 1749, 1753, 1757, 1761,
- 1766, 1785, 1791, 1799, 1803, 1809, 1813, 1819, 1823, 1829,
- 1833, 1842, 1846, 1850, 1854, 1860, 1863, 1871, 1872, 1874,
- 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, 1899, 1902,
- 1905, 1908, 1911, 1914, 1917, 1923, 1927, 1931, 1935, 1939,
- 1943, 1963, 1970, 1981, 1982, 1983, 1986, 1987, 1990, 1994,
- 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2034, 2040, 2048,
- 2056, 2062, 2069, 2085, 2107, 2111, 2117, 2120, 2123, 2127,
- 2137, 2141, 2160, 2168, 2169, 2181, 2182, 2185, 2189, 2195,
- 2199, 2205, 2209
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-const char *yytname[] =
-{
- "$end", "error", "$undefined", "LLITERAL", "LASOP", "LCOLAS", "LBREAK",
- "LCASE", "LCHAN", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER",
- "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT",
- "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN",
- "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT",
- "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE",
- "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'",
- "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
- "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
- "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
- "package", "loadsys", "@1", "imports", "import", "import_stmt",
- "import_stmt_list", "import_here", "import_package", "import_safety",
- "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl",
- "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case",
- "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body",
- "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6",
- "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list",
- "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr",
- "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval",
- "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
- "name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym",
- "hidden_importsym", "name", "labelname", "dotdotdot", "ntype",
- "non_expr_type", "non_recvchantype", "convtype", "comptype",
- "fnret_type", "dotname", "othertype", "ptrtype", "recvchantype",
- "structtype", "interfacetype", "xfndcl", "fndcl", "hidden_fndcl",
- "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral", "xdcl_list",
- "vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list",
- "interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl",
- "indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt",
- "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list",
- "expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list",
- "osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt",
- "ohidden_funarg_list", "ohidden_structdcl_list",
- "ohidden_interfacedcl_list", "oliteral", "hidden_import",
- "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type",
- "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan",
- "hidden_type_func", "hidden_funarg", "hidden_structdcl",
- "hidden_interfacedcl", "ohidden_funres", "hidden_funres",
- "hidden_literal", "hidden_constant", "hidden_import_list",
- "hidden_funarg_list", "hidden_structdcl_list",
- "hidden_interfacedcl_list", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 43,
- 45, 124, 94, 42, 47, 37, 38, 304, 305, 40,
- 41, 306, 59, 46, 36, 61, 58, 123, 125, 33,
- 126, 91, 93, 63, 64, 44
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 76, 77, 78, 78, 80, 79, 81, 81, 82,
- 82, 82, 83, 83, 84, 84, 85, 85, 85, 86,
- 87, 87, 89, 88, 90, 90, 90, 90, 90, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 92,
- 93, 93, 93, 94, 94, 95, 95, 95, 96, 97,
- 98, 98, 98, 98, 98, 98, 99, 99, 99, 99,
- 101, 100, 103, 102, 104, 104, 106, 105, 107, 107,
- 107, 108, 108, 108, 109, 111, 110, 112, 112, 114,
- 115, 116, 113, 118, 117, 119, 119, 120, 120, 122,
- 123, 121, 125, 124, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 128, 128, 128, 129, 129, 129,
- 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
- 129, 130, 131, 132, 132, 133, 133, 134, 134, 135,
- 135, 136, 137, 137, 138, 139, 140, 140, 141, 141,
- 141, 142, 142, 143, 144, 145, 145, 146, 146, 146,
- 146, 146, 146, 147, 147, 147, 147, 148, 148, 148,
- 148, 148, 149, 149, 150, 151, 151, 151, 151, 151,
- 152, 152, 153, 153, 153, 153, 153, 153, 153, 154,
- 155, 156, 156, 157, 157, 158, 159, 159, 160, 160,
- 161, 162, 162, 163, 163, 163, 164, 165, 165, 166,
- 166, 167, 167, 168, 168, 169, 169, 170, 170, 171,
- 171, 172, 172, 172, 172, 172, 172, 173, 173, 174,
- 175, 175, 175, 176, 177, 177, 177, 177, 178, 178,
- 179, 179, 180, 180, 180, 180, 180, 181, 181, 181,
- 181, 181, 182, 181, 181, 181, 181, 181, 181, 181,
- 181, 183, 183, 184, 184, 185, 185, 186, 186, 187,
- 187, 188, 188, 188, 188, 189, 189, 190, 190, 191,
- 191, 192, 192, 193, 193, 194, 194, 195, 195, 196,
- 196, 197, 197, 198, 198, 199, 199, 199, 199, 199,
- 199, 200, 201, 202, 202, 202, 203, 203, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204, 204, 205,
- 206, 207, 207, 208, 209, 209, 210, 210, 211, 211,
- 212, 212, 212, 213, 213, 214, 214, 215, 215, 216,
- 216, 217, 217
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 4, 0, 3, 0, 3, 0, 3, 2,
- 5, 3, 3, 2, 1, 3, 1, 2, 2, 4,
- 0, 1, 0, 4, 0, 1, 1, 1, 1, 2,
- 5, 3, 2, 5, 7, 3, 2, 5, 3, 1,
- 2, 4, 3, 4, 3, 1, 2, 1, 1, 2,
- 1, 3, 3, 3, 2, 2, 3, 5, 5, 2,
- 0, 4, 0, 3, 0, 2, 0, 4, 4, 4,
- 2, 5, 1, 1, 2, 0, 3, 1, 3, 0,
- 0, 0, 8, 0, 5, 0, 2, 0, 2, 0,
- 0, 7, 0, 5, 1, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 1, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 5, 6, 1, 1, 3,
- 5, 5, 4, 6, 8, 1, 5, 5, 5, 7,
- 1, 0, 3, 1, 4, 1, 4, 1, 3, 1,
- 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 1, 4, 4, 1, 1, 1, 2, 1, 1, 1,
- 1, 1, 3, 1, 1, 1, 2, 1, 1, 1,
- 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 3, 4, 4, 2, 3, 5, 1, 1, 2,
- 3, 5, 3, 5, 3, 3, 5, 8, 5, 8,
- 5, 0, 3, 0, 1, 3, 1, 4, 2, 0,
- 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
- 3, 3, 2, 4, 3, 5, 5, 1, 3, 1,
- 2, 1, 3, 4, 1, 2, 2, 1, 1, 3,
- 0, 2, 0, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 0, 4, 1, 2, 2, 2, 2, 2,
- 2, 1, 3, 1, 3, 1, 3, 1, 3, 1,
- 3, 1, 1, 3, 3, 0, 2, 0, 1, 0,
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
- 1, 0, 1, 0, 1, 4, 4, 5, 6, 4,
- 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 4, 5, 4, 4, 2, 2, 4, 3, 3,
- 5, 3, 4, 3, 5, 1, 0, 1, 3, 1,
- 1, 2, 1, 1, 5, 0, 2, 1, 3, 1,
- 3, 1, 3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint16 yydefact[] =
-{
- 5, 0, 3, 0, 1, 0, 7, 0, 22, 158,
- 160, 0, 0, 159, 219, 20, 6, 345, 0, 4,
- 0, 0, 0, 21, 0, 0, 0, 16, 0, 0,
- 9, 22, 0, 8, 28, 127, 156, 0, 39, 156,
- 0, 264, 75, 0, 0, 0, 79, 0, 0, 293,
- 92, 0, 89, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 291, 0, 25, 0, 257, 258,
- 261, 259, 260, 50, 94, 135, 147, 115, 164, 163,
- 128, 0, 0, 0, 184, 197, 198, 26, 216, 0,
- 140, 27, 0, 19, 0, 0, 0, 0, 0, 0,
- 346, 161, 162, 11, 14, 287, 18, 22, 13, 17,
- 157, 265, 154, 0, 0, 0, 0, 163, 190, 194,
- 180, 178, 179, 177, 266, 135, 0, 295, 250, 0,
- 211, 135, 269, 295, 152, 153, 0, 0, 277, 294,
- 270, 0, 0, 295, 0, 0, 36, 48, 0, 29,
- 275, 155, 0, 123, 118, 119, 122, 116, 117, 0,
- 0, 149, 0, 150, 175, 173, 174, 120, 121, 0,
- 292, 0, 220, 0, 32, 0, 0, 0, 0, 0,
- 55, 0, 0, 0, 54, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 141,
- 0, 0, 291, 262, 0, 141, 218, 0, 0, 0,
- 0, 311, 0, 0, 211, 0, 0, 312, 0, 0,
- 23, 288, 0, 12, 250, 0, 0, 195, 171, 169,
- 170, 167, 168, 199, 0, 0, 0, 296, 73, 0,
- 76, 0, 72, 165, 244, 163, 247, 151, 248, 289,
- 0, 250, 0, 205, 80, 77, 158, 0, 204, 0,
- 287, 241, 229, 0, 64, 0, 0, 202, 273, 287,
- 227, 239, 303, 0, 90, 38, 225, 287, 49, 31,
- 221, 287, 0, 0, 40, 0, 176, 148, 0, 0,
- 35, 287, 0, 0, 51, 96, 111, 114, 97, 101,
- 102, 100, 112, 99, 98, 95, 113, 103, 104, 105,
- 106, 107, 108, 109, 110, 285, 124, 279, 289, 0,
- 129, 292, 0, 0, 289, 285, 256, 60, 254, 253,
- 271, 255, 0, 53, 52, 278, 0, 0, 0, 0,
- 319, 0, 0, 0, 0, 0, 318, 0, 313, 314,
- 315, 0, 347, 0, 0, 297, 0, 0, 0, 15,
- 10, 0, 0, 0, 181, 191, 70, 66, 74, 0,
- 0, 295, 166, 245, 246, 290, 251, 213, 0, 0,
- 0, 295, 0, 237, 0, 250, 240, 288, 0, 0,
- 0, 0, 303, 0, 0, 288, 0, 304, 232, 0,
- 303, 0, 288, 0, 288, 0, 42, 276, 0, 0,
- 0, 200, 171, 169, 170, 168, 141, 193, 192, 288,
- 0, 44, 0, 141, 143, 281, 282, 289, 0, 289,
- 290, 0, 0, 0, 132, 291, 263, 290, 0, 0,
- 0, 0, 217, 0, 0, 326, 316, 317, 297, 301,
- 0, 299, 0, 325, 340, 0, 0, 342, 343, 0,
- 0, 0, 0, 0, 303, 0, 0, 310, 0, 298,
- 305, 309, 306, 213, 172, 0, 0, 0, 0, 249,
- 250, 163, 214, 189, 187, 188, 185, 186, 210, 213,
- 212, 81, 78, 238, 242, 0, 230, 203, 196, 0,
- 0, 93, 62, 65, 0, 234, 0, 303, 228, 201,
- 274, 231, 64, 226, 37, 222, 30, 41, 0, 285,
- 45, 223, 287, 47, 33, 43, 285, 0, 290, 286,
- 138, 0, 280, 125, 131, 130, 0, 136, 137, 0,
- 272, 328, 0, 0, 319, 0, 318, 0, 335, 351,
- 302, 0, 0, 0, 349, 300, 329, 341, 0, 307,
- 0, 320, 0, 303, 331, 0, 348, 336, 0, 69,
- 68, 295, 0, 250, 206, 85, 213, 0, 59, 0,
- 303, 303, 233, 0, 172, 0, 288, 0, 46, 0,
- 141, 145, 142, 283, 284, 126, 291, 133, 61, 327,
- 336, 297, 324, 0, 0, 303, 323, 0, 0, 321,
- 308, 332, 297, 297, 339, 208, 337, 67, 71, 215,
- 0, 87, 243, 0, 0, 56, 0, 63, 236, 235,
- 91, 139, 224, 34, 144, 285, 0, 330, 0, 352,
- 322, 333, 350, 0, 0, 0, 213, 0, 86, 82,
- 0, 0, 0, 134, 336, 344, 336, 338, 207, 83,
- 88, 58, 57, 146, 334, 209, 295, 0, 84
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 6, 2, 3, 14, 21, 30, 105, 31,
- 8, 24, 16, 17, 65, 328, 67, 149, 520, 521,
- 145, 146, 68, 502, 329, 440, 503, 579, 390, 368,
- 475, 238, 239, 240, 69, 127, 254, 70, 133, 380,
- 575, 648, 666, 621, 649, 71, 143, 401, 72, 141,
- 73, 74, 75, 76, 315, 425, 426, 592, 77, 317,
- 244, 136, 78, 150, 111, 117, 13, 80, 81, 246,
- 247, 163, 119, 82, 83, 482, 228, 84, 230, 231,
- 85, 86, 87, 130, 214, 88, 253, 488, 89, 90,
- 22, 281, 522, 277, 269, 260, 270, 271, 272, 262,
- 386, 248, 249, 250, 330, 331, 323, 332, 273, 152,
- 92, 318, 427, 428, 222, 376, 171, 140, 255, 468,
- 553, 547, 398, 100, 212, 218, 614, 445, 348, 349,
- 350, 352, 554, 549, 615, 616, 458, 459, 25, 469,
- 555, 550
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -473
-static const yytype_int16 yypact[] =
-{
- -473, 65, 22, 49, -473, 261, -473, 64, -473, -473,
- -473, 95, 52, -473, 143, 145, -473, -473, 104, -473,
- 68, 128, 1049, -473, 142, 305, 16, -473, 56, 204,
- -473, 49, 220, -473, -473, -473, 261, 974, -473, 261,
- 562, -473, -473, 288, 562, 261, -473, 14, 147, 1615,
- -473, 14, -473, 395, 401, 1615, 1615, 1615, 1615, 1615,
- 1615, 1658, 1615, 1615, 737, 168, -473, 414, -473, -473,
- -473, -473, -473, 649, -473, -473, 165, 122, -473, 169,
- -473, 177, 218, 14, 219, -473, -473, -473, 235, 89,
- -473, -473, 34, -473, 206, 124, 286, 206, 206, 260,
- -473, -473, -473, -473, -473, 265, -473, -473, -473, -473,
- -473, -473, -473, 270, 1803, 1803, 1803, -473, 269, -473,
- -473, -473, -473, -473, -473, 39, 122, 882, 1777, 283,
- 277, 230, -473, 1615, -473, -473, 292, 1803, 2097, 280,
- -473, 332, 315, 1615, 215, 1803, -473, -473, 244, -473,
- -473, -473, 949, -473, -473, -473, -473, -473, -473, 1701,
- 1658, 2097, 298, -473, 9, -473, 59, -473, -473, 303,
- 2097, 319, -473, 330, -473, 1744, 1615, 1615, 1615, 1615,
- -473, 1615, 1615, 1615, -473, 1615, 1615, 1615, 1615, 1615,
- 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, -473,
- 1297, 455, 1615, -473, 1615, -473, -473, 1225, 1615, 1615,
- 1615, -473, 594, 261, 277, 328, 403, -473, 1308, 1308,
- -473, 152, 352, -473, 1777, 405, 1803, -473, -473, -473,
- -473, -473, -473, -473, 354, 261, 1615, -473, -473, 382,
- -473, 47, 360, 1803, -473, 1777, -473, -473, -473, 351,
- 367, 1777, 1225, -473, -473, 366, 84, 407, -473, 374,
- 373, -473, -473, 372, -473, 138, 42, -473, -473, 377,
- -473, -473, 442, 1769, -473, -473, -473, 384, -473, -473,
- -473, 389, 1615, 261, 391, 1830, -473, 394, 1803, 1803,
- -473, 409, 1615, 411, 2097, 1935, -473, 2121, 1080, 1080,
- 1080, 1080, -473, 1080, 1080, 2145, -473, 503, 503, 503,
- 503, -473, -473, -473, -473, 1352, -473, -473, 27, 1407,
- -473, 1995, 412, 1147, 1962, 1352, -473, -473, -473, -473,
- -473, -473, 7, 280, 280, 2097, 698, 418, 415, 413,
- -473, 416, 477, 1308, 188, 31, -473, 425, -473, -473,
- -473, 1897, -473, 221, 433, 261, 434, 436, 439, -473,
- -473, 432, 1803, 452, -473, -473, 2097, -473, -473, 1462,
- 1517, 1615, -473, -473, -473, 1777, -473, 1856, 453, 91,
- 382, 1615, 261, 454, 456, 1777, -473, 475, 451, 1803,
- 133, 407, 442, 407, 460, 326, 462, -473, -473, 261,
- 442, 467, 261, 478, 261, 486, 280, -473, 1615, 1864,
- 1803, -473, 26, 248, 264, 430, -473, -473, -473, 261,
- 492, 280, 1615, -473, 2025, -473, -473, 485, 493, 487,
- 1658, 504, 506, 508, -473, 1615, -473, -473, 512, 505,
- 1225, 1147, -473, 1308, 517, -473, -473, -473, 261, 1889,
- 1308, 261, 1308, -473, -473, 571, 155, -473, -473, 514,
- 509, 1308, 188, 1308, 442, 261, 261, -473, 518, 507,
- -473, -473, -473, 1856, -473, 1225, 1615, 1615, 521, -473,
- 1777, 528, -473, -473, -473, -473, -473, -473, -473, 1856,
- -473, -473, -473, -473, -473, 520, -473, -473, -473, 1658,
- 522, -473, -473, -473, 530, -473, 532, 442, -473, -473,
- -473, -473, -473, -473, -473, -473, -473, 280, 535, 1352,
- -473, -473, 536, 1744, -473, 280, 1352, 1560, 1352, -473,
- -473, 539, -473, -473, -473, -473, 247, -473, -473, 308,
- -473, -473, 541, 543, 545, 546, 547, 544, -473, -473,
- 551, 548, 1308, 554, -473, 557, -473, -473, 576, -473,
- 1308, -473, 564, 442, -473, 568, -473, 1923, 318, 2097,
- 2097, 1615, 569, 1777, -473, -473, 1856, 156, -473, 1147,
- 442, 442, -473, 243, 483, 563, 261, 577, 411, 570,
- -473, 2097, -473, -473, -473, -473, 1615, -473, -473, -473,
- 1923, 261, -473, 1889, 1308, 442, -473, 261, 155, -473,
- -473, -473, 261, 261, -473, -473, -473, -473, -473, -473,
- 579, 627, -473, 1615, 1615, -473, 1658, 580, -473, -473,
- -473, -473, -473, -473, -473, 1352, 572, -473, 583, -473,
- -473, -473, -473, 585, 586, 590, 1856, 77, -473, -473,
- 2049, 2073, 584, -473, 1923, -473, 1923, -473, -473, -473,
- -473, -473, -473, -473, -473, -473, 1615, 382, -473
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -473, -473, -473, -473, -473, -473, -473, -12, -473, -473,
- 624, -473, -1, -473, -473, 635, -473, -137, -48, 74,
- -473, -130, -112, -473, 11, -473, -473, -473, 149, -372,
- -473, -473, -473, -473, -473, -473, -140, -473, -473, -473,
- -473, -473, -473, -473, -473, -473, -473, -473, -473, -473,
- 662, 448, 257, -473, -196, 135, 139, -473, 262, -59,
- 424, -16, -3, 387, 632, 427, 313, 20, -473, 428,
- -89, 524, -473, -473, -473, -473, -36, -37, -31, -49,
- -473, -473, -473, -473, -473, -32, 458, -472, -473, -473,
- -473, -473, -473, -473, -473, -473, 279, -108, -211, 290,
- -473, 306, -473, -214, -291, 658, -473, -230, -473, -63,
- -6, 191, -473, -302, -219, -254, -195, -473, -107, -435,
- -473, -473, -347, -473, 323, -473, 72, -473, 371, 268,
- 380, 242, 102, 110, -468, -473, -438, 255, -473, 515,
- -473, -473
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -278
-static const yytype_int16 yytable[] =
-{
- 121, 120, 162, 274, 175, 123, 122, 322, 491, 325,
- 361, 280, 165, 543, 276, 237, 104, 574, 558, 174,
- 242, 237, 379, 439, 164, 227, 233, 234, 261, 166,
- 108, 237, 436, 110, 460, 142, 110, 378, 429, 208,
- 101, 388, 132, 139, -184, 505, -268, 5, 263, 134,
- 396, -268, 369, 511, 392, 394, 278, 118, 403, 27,
- -216, -180, 405, 284, 431, 4, 383, 205, -183, 441,
- 438, 27, 420, 207, 7, 442, -184, 229, 229, 229,
- 9, 135, 232, 232, 232, -180, 293, -237, 15, 102,
- 206, 229, 9, -180, -216, 393, 232, 659, 18, 209,
- 229, -268, 430, 461, 622, 232, 223, -268, 229, 210,
- 175, 165, 370, 232, 19, 229, 103, 564, -182, 29,
- 232, 241, 210, 164, 134, 291, -216, 28, 166, 10,
- 11, 29, 637, 259, 118, 118, 118, 363, 229, 268,
- 499, 10, 11, 232, 327, 500, -237, 382, 118, 384,
- 540, 165, -237, 441, 372, 27, 135, 118, 454, 490,
- 582, 623, 383, 164, 20, 118, 638, 26, 166, 23,
- 643, 495, 118, 529, 658, 531, 9, 644, 645, 9,
- 504, 200, 506, 213, 400, 201, 664, 229, 665, 229,
- 33, 454, 232, 202, 232, 118, 411, 391, 11, 417,
- 418, 501, 333, 334, 93, 455, 229, 106, 229, 359,
- 539, 232, 9, 232, 229, 29, 611, 585, 137, 232,
- 519, 624, 625, 109, 589, 10, 11, 526, 10, 11,
- 172, 626, 199, 628, 629, -154, 229, -267, 455, 9,
- 536, 232, -267, 203, 118, 568, 118, 456, 413, 412,
- 499, 229, 229, 415, 414, 500, 232, 232, 641, 237,
- 433, 10, 11, 118, 478, 118, 572, 515, 9, 237,
- 165, 118, 513, 411, 492, 275, 406, 204, -183, 261,
- 11, 465, 164, -178, 347, 9, 421, 166, 10, 11,
- 357, 358, -267, 118, -182, 668, 466, 125, -267, -179,
- 498, 131, 126, 587, 279, 118, 126, -178, 118, 118,
- 216, 630, 9, 596, 94, -178, 256, 10, 11, 597,
- 227, 518, 95, -179, 220, 229, 96, 221, 486, 224,
- 232, -179, 235, 652, 10, 11, 97, 98, 229, 256,
- 484, 483, 251, 232, 252, 487, 485, 128, 229, 627,
- 256, 257, 229, 232, 9, 210, 523, 232, 287, 620,
- 258, 10, 11, 333, 334, 10, 11, 264, 265, 99,
- 441, 532, 229, 229, 266, 288, 598, 232, 232, 265,
- 441, 165, 118, 267, 259, 266, 617, 355, 10, 11,
- 290, 289, 268, 164, 635, 118, 510, 118, 166, 10,
- 11, 636, 517, 10, 11, 118, 356, 211, 211, 118,
- 211, 211, 360, 362, 364, 453, 525, 367, 215, 9,
- 217, 219, 371, 464, 486, 9, 375, 377, 381, 118,
- 118, 383, 12, 385, 588, 387, 484, 483, 9, 395,
- 486, 487, 485, 229, 389, 397, 402, 32, 232, 79,
- 165, 404, 484, 483, 144, 32, 408, 487, 485, 237,
- 148, 416, 164, 112, 618, -177, 112, 166, 10, 11,
- 129, 419, 112, 173, 10, 11, 422, 448, 435, 9,
- 147, 151, 449, 451, 450, 452, 229, 10, 11, -177,
- 462, 232, 473, 118, 151, 467, 470, -177, 471, 256,
- 118, 472, 512, 153, 154, 155, 156, 157, 158, 118,
- 167, 168, 474, 489, 319, 541, 494, 382, -181, 497,
- 507, 548, 551, 523, 556, 346, 667, 486, 10, 11,
- 509, 346, 346, 561, 257, 563, 229, 178, 514, 484,
- 483, 232, -181, 118, 487, 485, 516, 186, 10, 11,
- -181, 190, 524, 342, 237, 245, 195, 196, 197, 198,
- 528, 530, 437, 112, 533, 35, 534, 532, 535, 112,
- 37, 147, 537, 538, 557, 151, 559, 165, 567, 113,
- 576, 560, 466, 571, 47, 48, 9, 573, 578, 164,
- 580, 51, 581, 118, 166, 584, 118, 486, 586, 595,
- 151, 599, 336, 600, -158, 601, -159, 153, 157, 484,
- 483, 337, 602, 603, 487, 485, 338, 339, 340, 607,
- 604, 61, 606, 341, 605, 608, 610, 612, 320, 619,
- 342, 631, 609, 64, 79, 10, 11, 633, 634, 646,
- 351, 647, 441, 654, 653, 655, 656, 343, 32, 346,
- 657, 245, 663, 176, -277, 107, 346, 66, 660, 344,
- 632, 583, 365, 593, 346, 345, 118, 594, 11, 373,
- 407, 124, 354, 374, 508, 548, 640, 496, 245, 79,
- 91, 479, 177, 178, 286, 179, 180, 181, 182, 183,
- 577, 184, 185, 186, 187, 188, 189, 190, 191, 192,
- 193, 194, 195, 196, 197, 198, 336, 446, 566, 642,
- 151, 138, 542, 639, -277, 337, 447, 562, 0, 0,
- 338, 339, 340, 161, -277, 0, 170, 341, 353, 0,
- 0, 0, 0, 0, 443, 0, 0, 0, 0, 0,
- 35, 0, 0, 0, 0, 37, 0, 0, 169, 0,
- 79, 343, 0, 0, 113, 0, 346, 444, 0, 47,
- 48, 9, 546, 346, 0, 346, 51, 0, 0, 345,
- 0, 457, 11, 55, 346, 0, 346, 0, 0, 0,
- 0, 0, 351, 0, 0, 0, 56, 57, 0, 58,
- 59, 0, 0, 60, 0, 0, 61, 0, 0, 0,
- 0, 0, 245, 0, 481, 0, 62, 63, 64, 493,
- 10, 11, 245, 0, 112, 0, 0, 0, 0, 0,
- 0, 0, 112, 0, 0, 0, 112, 0, 0, 147,
- 0, 151, 0, 0, 0, 0, 0, 0, 294, 295,
- 296, 297, 0, 298, 299, 300, 151, 301, 302, 303,
- 304, 305, 306, 307, 308, 309, 310, 311, 312, 313,
- 314, 0, 161, 0, 321, 346, 324, 79, 79, 0,
- 138, 138, 335, 346, 0, 351, 545, 0, 552, 0,
- 346, 0, 0, 457, 0, 35, 0, 0, 0, 457,
- 37, 0, 565, 351, 0, 0, 0, 0, 366, 113,
- 0, 0, 79, 0, 47, 48, 9, 245, 236, 0,
- 0, 51, 0, 346, 0, 0, 546, 346, 55, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 56, 57, 0, 58, 59, 0, 0, 60, 0,
- 0, 61, 0, 0, 138, 0, 0, 0, 0, 0,
- 0, 62, 63, 64, 138, 10, 11, 37, 0, 0,
- 0, 0, 0, 0, 0, 0, 113, 346, 0, 346,
- 0, 47, 48, 9, 0, 0, 0, 424, 51, 0,
- 0, 161, 37, 0, 0, 225, 0, 424, 0, 0,
- 0, 113, 0, 0, 0, 0, 47, 48, 9, 0,
- 245, 0, 115, 51, 0, 0, 79, 0, 226, 0,
- 114, 0, 0, 151, 282, 0, 0, 0, 0, 0,
- 64, 0, 10, 11, 283, 0, 0, 115, 351, 0,
- 545, 138, 138, 116, 552, 457, 0, 0, 0, 351,
- 351, 0, 0, 0, 0, 64, 0, 10, 11, -2,
- 34, 0, 35, 0, 0, 36, 0, 37, 38, 39,
- 0, 0, 40, 0, 41, 42, 43, 44, 45, 46,
- 138, 47, 48, 9, 0, 0, 49, 50, 51, 52,
- 53, 54, 0, 0, 138, 55, 0, 0, 0, 0,
- 0, 0, 161, 0, 0, 0, 0, 170, 56, 57,
- 0, 58, 59, 0, 0, 60, 0, 0, 61, 0,
- 0, -24, 0, 0, 178, 0, 0, 0, 62, 63,
- 64, 0, 10, 11, 186, 0, 0, 0, 190, 191,
- 192, 193, 194, 195, 196, 197, 198, 0, 569, 570,
- 0, 0, 0, 0, 0, 0, 0, 0, 326, 0,
- 35, 0, 0, 36, -252, 37, 38, 39, 0, -252,
- 40, 161, 41, 42, 113, 44, 45, 46, 0, 47,
- 48, 9, 0, 0, 49, 50, 51, 52, 53, 54,
- 0, 424, 0, 55, 0, 0, 0, 0, 424, 591,
- 424, 0, 0, 0, 0, 0, 56, 57, 0, 58,
- 59, 0, 0, 60, 0, 0, 61, 0, 0, -252,
- 0, 0, 0, 0, 327, -252, 62, 63, 64, 0,
- 10, 11, 0, 0, 0, 0, 326, 0, 35, 0,
- 0, 36, 0, 37, 38, 39, 0, 0, 40, 0,
- 41, 42, 113, 44, 45, 46, 0, 47, 48, 9,
- 0, 0, 49, 50, 51, 52, 53, 54, 170, 0,
- 0, 55, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 56, 57, 0, 58, 59, 0,
- 0, 60, 0, 0, 61, 650, 651, -252, 161, 0,
- 0, 0, 327, -252, 62, 63, 64, 424, 10, 11,
- 35, 0, 0, 0, 0, 37, 0, 0, 0, 0,
- 0, 0, 0, 0, 113, 0, 336, 0, 0, 47,
- 48, 9, 0, 0, 0, 337, 51, 0, 0, 0,
- 338, 339, 340, 159, 0, 0, 0, 341, 0, 0,
- 0, 0, 0, 0, 342, 0, 56, 57, 0, 58,
- 160, 0, 0, 60, 0, 35, 61, 316, 0, 0,
- 37, 343, 0, 0, 0, 0, 62, 63, 64, 113,
- 10, 11, 0, 0, 47, 48, 9, 0, 0, 345,
- 0, 51, 11, 0, 0, 0, 0, 0, 55, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 56, 57, 0, 58, 59, 0, 0, 60, 0,
- 35, 61, 0, 0, 0, 37, 0, 0, 0, 423,
- 0, 62, 63, 64, 113, 10, 11, 0, 0, 47,
- 48, 9, 0, 0, 0, 0, 51, 0, 432, 0,
- 0, 0, 0, 159, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 56, 57, 0, 58,
- 160, 0, 0, 60, 0, 35, 61, 0, 0, 0,
- 37, 0, 0, 0, 0, 0, 62, 63, 64, 113,
- 10, 11, 0, 0, 47, 48, 9, 0, 476, 0,
- 0, 51, 0, 0, 0, 0, 0, 0, 55, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 56, 57, 0, 58, 59, 0, 0, 60, 0,
- 35, 61, 0, 0, 0, 37, 0, 0, 0, 0,
- 0, 62, 63, 64, 113, 10, 11, 0, 0, 47,
- 48, 9, 0, 477, 0, 0, 51, 0, 0, 0,
- 0, 0, 0, 55, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 56, 57, 37, 58,
- 59, 0, 0, 60, 0, 0, 61, 113, 0, 0,
- 0, 0, 47, 48, 9, 0, 62, 63, 64, 51,
- 10, 11, 0, 0, 0, 0, 55, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,
- 57, 0, 58, 59, 0, 0, 60, 0, 35, 61,
- 0, 0, 0, 37, 0, 0, 0, 590, 0, 62,
- 63, 64, 113, 10, 11, 0, 0, 47, 48, 9,
- 0, 0, 0, 0, 51, 0, 0, 0, 0, 0,
- 0, 55, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 35, 0, 0, 56, 57, 37, 58, 59, 0,
- 0, 60, 0, 0, 61, 113, 0, 0, 0, 0,
- 47, 48, 9, 0, 62, 63, 64, 51, 10, 11,
- 0, 0, 0, 0, 159, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 35, 0, 0, 56, 57, 285,
- 58, 160, 0, 0, 60, 0, 0, 61, 113, 0,
- 0, 0, 0, 47, 48, 9, 0, 62, 63, 64,
- 51, 10, 11, 0, 0, 0, 0, 55, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 56, 57, 37, 58, 59, 0, 0, 60, 0, 0,
- 61, 113, 0, 0, 0, 0, 47, 48, 9, 0,
- 62, 63, 64, 51, 10, 11, 0, 37, 0, 0,
- 225, 0, 0, 0, 0, 37, 113, 0, 243, 0,
- 0, 47, 48, 9, 113, 0, 0, 115, 51, 47,
- 48, 9, 0, 226, 0, 225, 51, 0, 0, 292,
- 0, 37, 0, 225, 0, 64, 0, 10, 11, 283,
- 113, 0, 115, 0, 0, 47, 48, 9, 226, 0,
- 115, 0, 51, 0, 0, 0, 226, 0, 37, 225,
- 64, 0, 10, 11, 399, 0, 0, 113, 64, 0,
- 10, 11, 47, 48, 9, 0, 115, 0, 0, 51,
- 0, 0, 226, 0, 37, 0, 409, 0, 0, 0,
- 0, 0, 285, 113, 64, 0, 10, 11, 47, 48,
- 9, 113, 0, 115, 0, 51, 47, 48, 9, 410,
- 0, 0, 225, 51, 0, 0, 0, 336, 0, 0,
- 225, 64, 0, 10, 11, 336, 337, 0, 463, 115,
- 0, 338, 339, 544, 337, 480, 0, 115, 341, 338,
- 339, 340, 0, 226, 0, 342, 341, 64, 0, 10,
- 11, 336, 0, 342, 0, 64, 0, 10, 11, 0,
- 337, 0, 343, 0, 0, 338, 339, 340, 0, 0,
- 343, 0, 341, 0, 0, 0, 0, 0, 0, 342,
- 345, 0, 10, 11, 0, 0, 0, 0, 345, 178,
- 0, 11, 0, 181, 182, 183, 343, 0, 185, 186,
- 187, 188, 613, 190, 191, 192, 193, 194, 195, 196,
- 197, 198, 0, 0, 345, 177, 178, 11, 179, 0,
- 181, 182, 183, 0, 0, 185, 186, 187, 188, 189,
- 190, 191, 192, 193, 194, 195, 196, 197, 198, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 177, 178,
- 0, 179, 0, 181, 182, 183, 0, 437, 185, 186,
- 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
- 197, 198, 0, 0, 0, 0, 0, 0, 177, 178,
- 0, 179, 0, 181, 182, 183, 0, 434, 185, 186,
- 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
- 197, 198, 177, 178, 0, 179, 0, 181, 182, 183,
- 0, 527, 185, 186, 187, 188, 189, 190, 191, 192,
- 193, 194, 195, 196, 197, 198, 177, 178, 0, 179,
- 0, 181, 182, 183, 0, 661, 185, 186, 187, 188,
- 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
- 177, 178, 0, 179, 0, 181, 182, 183, 0, 662,
- 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
- 195, 196, 197, 198, 177, 178, 0, 0, 0, 181,
- 182, 183, 0, 0, 185, 186, 187, 188, 189, 190,
- 191, 192, 193, 194, 195, 196, 197, 198, 177, 178,
- 0, 0, 0, 181, 182, 183, 0, 0, 185, 186,
- 187, 188, 0, 190, 191, 192, 193, 194, 195, 196,
- 197, 198
-};
-
-static const yytype_int16 yycheck[] =
-{
- 37, 37, 61, 143, 67, 37, 37, 202, 380, 205,
- 224, 148, 61, 448, 144, 127, 28, 489, 456, 67,
- 127, 133, 252, 325, 61, 114, 115, 116, 136, 61,
- 31, 143, 323, 36, 3, 51, 39, 251, 11, 5,
- 24, 260, 45, 49, 35, 392, 7, 25, 137, 35,
- 269, 12, 5, 400, 265, 266, 145, 37, 277, 3,
- 1, 35, 281, 152, 318, 0, 24, 83, 59, 62,
- 324, 3, 291, 89, 25, 68, 67, 114, 115, 116,
- 24, 67, 114, 115, 116, 59, 175, 3, 24, 73,
- 1, 128, 24, 67, 35, 53, 128, 20, 3, 65,
- 137, 62, 75, 72, 576, 137, 107, 68, 145, 75,
- 173, 160, 65, 145, 62, 152, 60, 464, 59, 63,
- 152, 127, 75, 160, 35, 173, 67, 59, 160, 73,
- 74, 63, 600, 136, 114, 115, 116, 226, 175, 142,
- 7, 73, 74, 175, 67, 12, 62, 63, 128, 257,
- 441, 200, 68, 62, 243, 3, 67, 137, 3, 68,
- 507, 5, 24, 200, 21, 145, 601, 63, 200, 24,
- 608, 385, 152, 427, 646, 429, 24, 612, 613, 24,
- 391, 59, 393, 59, 273, 63, 654, 224, 656, 226,
- 62, 3, 224, 71, 226, 175, 285, 59, 74, 288,
- 289, 68, 208, 209, 62, 50, 243, 3, 245, 221,
- 440, 243, 24, 245, 251, 63, 563, 519, 71, 251,
- 416, 65, 66, 3, 526, 73, 74, 423, 73, 74,
- 62, 75, 67, 580, 581, 66, 273, 7, 50, 24,
- 435, 273, 12, 66, 224, 475, 226, 59, 285, 285,
- 7, 288, 289, 285, 285, 12, 288, 289, 605, 371,
- 319, 73, 74, 243, 371, 245, 480, 404, 24, 381,
- 319, 251, 402, 362, 381, 60, 282, 59, 59, 387,
- 74, 60, 319, 35, 212, 24, 292, 319, 73, 74,
- 218, 219, 62, 273, 59, 667, 75, 40, 68, 35,
- 389, 44, 40, 522, 60, 285, 44, 59, 288, 289,
- 24, 68, 24, 66, 9, 67, 24, 73, 74, 72,
- 409, 410, 17, 59, 64, 362, 21, 62, 377, 59,
- 362, 67, 63, 635, 73, 74, 31, 32, 375, 24,
- 377, 377, 59, 375, 67, 377, 377, 59, 385, 579,
- 24, 59, 389, 385, 24, 75, 419, 389, 60, 573,
- 68, 73, 74, 369, 370, 73, 74, 35, 53, 64,
- 62, 430, 409, 410, 59, 72, 68, 409, 410, 53,
- 62, 430, 362, 68, 387, 59, 68, 59, 73, 74,
- 60, 72, 395, 430, 590, 375, 399, 377, 430, 73,
- 74, 596, 408, 73, 74, 385, 3, 94, 95, 389,
- 97, 98, 60, 8, 60, 343, 422, 35, 95, 24,
- 97, 98, 62, 351, 473, 24, 75, 60, 62, 409,
- 410, 24, 5, 59, 523, 62, 473, 473, 24, 62,
- 489, 473, 473, 480, 72, 3, 62, 20, 480, 22,
- 499, 62, 489, 489, 59, 28, 65, 489, 489, 571,
- 59, 67, 499, 36, 571, 35, 39, 499, 73, 74,
- 43, 62, 45, 59, 73, 74, 65, 59, 66, 24,
- 53, 54, 67, 67, 71, 8, 523, 73, 74, 59,
- 65, 523, 60, 473, 67, 62, 62, 67, 62, 24,
- 480, 62, 35, 55, 56, 57, 58, 59, 60, 489,
- 62, 63, 60, 60, 59, 443, 60, 63, 35, 68,
- 60, 449, 450, 586, 452, 212, 666, 576, 73, 74,
- 68, 218, 219, 461, 59, 463, 573, 34, 60, 576,
- 576, 573, 59, 523, 576, 576, 60, 44, 73, 74,
- 67, 48, 60, 36, 666, 128, 53, 54, 55, 56,
- 75, 68, 75, 136, 60, 3, 60, 626, 60, 142,
- 8, 144, 60, 68, 3, 148, 62, 626, 60, 17,
- 60, 72, 75, 62, 22, 23, 24, 59, 66, 626,
- 60, 29, 60, 573, 626, 60, 576, 646, 62, 60,
- 173, 60, 8, 60, 59, 59, 59, 159, 160, 646,
- 646, 17, 68, 62, 646, 646, 22, 23, 24, 62,
- 72, 59, 68, 29, 552, 49, 62, 59, 201, 60,
- 36, 68, 560, 71, 207, 73, 74, 60, 68, 60,
- 213, 14, 62, 60, 72, 60, 60, 53, 221, 336,
- 60, 224, 68, 4, 5, 31, 343, 22, 647, 65,
- 586, 512, 235, 528, 351, 71, 646, 528, 74, 245,
- 283, 39, 214, 245, 395, 603, 604, 387, 251, 252,
- 22, 375, 33, 34, 160, 36, 37, 38, 39, 40,
- 499, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 54, 55, 56, 8, 336, 466, 607,
- 283, 49, 444, 603, 65, 17, 336, 462, -1, -1,
- 22, 23, 24, 61, 75, -1, 64, 29, 213, -1,
- -1, -1, -1, -1, 36, -1, -1, -1, -1, -1,
- 3, -1, -1, -1, -1, 8, -1, -1, 11, -1,
- 323, 53, -1, -1, 17, -1, 443, 59, -1, 22,
- 23, 24, 449, 450, -1, 452, 29, -1, -1, 71,
- -1, 344, 74, 36, 461, -1, 463, -1, -1, -1,
- -1, -1, 355, -1, -1, -1, 49, 50, -1, 52,
- 53, -1, -1, 56, -1, -1, 59, -1, -1, -1,
- -1, -1, 375, -1, 377, -1, 69, 70, 71, 382,
- 73, 74, 385, -1, 387, -1, -1, -1, -1, -1,
- -1, -1, 395, -1, -1, -1, 399, -1, -1, 402,
- -1, 404, -1, -1, -1, -1, -1, -1, 176, 177,
- 178, 179, -1, 181, 182, 183, 419, 185, 186, 187,
- 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
- 198, -1, 200, -1, 202, 552, 204, 440, 441, -1,
- 208, 209, 210, 560, -1, 448, 449, -1, 451, -1,
- 567, -1, -1, 456, -1, 3, -1, -1, -1, 462,
- 8, -1, 465, 466, -1, -1, -1, -1, 236, 17,
- -1, -1, 475, -1, 22, 23, 24, 480, 26, -1,
- -1, 29, -1, 600, -1, -1, 603, 604, 36, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
- -1, 59, -1, -1, 282, -1, -1, -1, -1, -1,
- -1, 69, 70, 71, 292, 73, 74, 8, -1, -1,
- -1, -1, -1, -1, -1, -1, 17, 654, -1, 656,
- -1, 22, 23, 24, -1, -1, -1, 315, 29, -1,
- -1, 319, 8, -1, -1, 36, -1, 325, -1, -1,
- -1, 17, -1, -1, -1, -1, 22, 23, 24, -1,
- 573, -1, 53, 29, -1, -1, 579, -1, 59, -1,
- 36, -1, -1, 586, 65, -1, -1, -1, -1, -1,
- 71, -1, 73, 74, 75, -1, -1, 53, 601, -1,
- 603, 369, 370, 59, 607, 608, -1, -1, -1, 612,
- 613, -1, -1, -1, -1, 71, -1, 73, 74, 0,
- 1, -1, 3, -1, -1, 6, -1, 8, 9, 10,
- -1, -1, 13, -1, 15, 16, 17, 18, 19, 20,
- 408, 22, 23, 24, -1, -1, 27, 28, 29, 30,
- 31, 32, -1, -1, 422, 36, -1, -1, -1, -1,
- -1, -1, 430, -1, -1, -1, -1, 435, 49, 50,
- -1, 52, 53, -1, -1, 56, -1, -1, 59, -1,
- -1, 62, -1, -1, 34, -1, -1, -1, 69, 70,
- 71, -1, 73, 74, 44, -1, -1, -1, 48, 49,
- 50, 51, 52, 53, 54, 55, 56, -1, 476, 477,
- -1, -1, -1, -1, -1, -1, -1, -1, 1, -1,
- 3, -1, -1, 6, 7, 8, 9, 10, -1, 12,
- 13, 499, 15, 16, 17, 18, 19, 20, -1, 22,
- 23, 24, -1, -1, 27, 28, 29, 30, 31, 32,
- -1, 519, -1, 36, -1, -1, -1, -1, 526, 527,
- 528, -1, -1, -1, -1, -1, 49, 50, -1, 52,
- 53, -1, -1, 56, -1, -1, 59, -1, -1, 62,
- -1, -1, -1, -1, 67, 68, 69, 70, 71, -1,
- 73, 74, -1, -1, -1, -1, 1, -1, 3, -1,
- -1, 6, -1, 8, 9, 10, -1, -1, 13, -1,
- 15, 16, 17, 18, 19, 20, -1, 22, 23, 24,
- -1, -1, 27, 28, 29, 30, 31, 32, 596, -1,
- -1, 36, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 49, 50, -1, 52, 53, -1,
- -1, 56, -1, -1, 59, 623, 624, 62, 626, -1,
- -1, -1, 67, 68, 69, 70, 71, 635, 73, 74,
- 3, -1, -1, -1, -1, 8, -1, -1, -1, -1,
- -1, -1, -1, -1, 17, -1, 8, -1, -1, 22,
- 23, 24, -1, -1, -1, 17, 29, -1, -1, -1,
- 22, 23, 24, 36, -1, -1, -1, 29, -1, -1,
- -1, -1, -1, -1, 36, -1, 49, 50, -1, 52,
- 53, -1, -1, 56, -1, 3, 59, 60, -1, -1,
- 8, 53, -1, -1, -1, -1, 69, 70, 71, 17,
- 73, 74, -1, -1, 22, 23, 24, -1, -1, 71,
- -1, 29, 74, -1, -1, -1, -1, -1, 36, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
- 3, 59, -1, -1, -1, 8, -1, -1, -1, 67,
- -1, 69, 70, 71, 17, 73, 74, -1, -1, 22,
- 23, 24, -1, -1, -1, -1, 29, -1, 31, -1,
- -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 49, 50, -1, 52,
- 53, -1, -1, 56, -1, 3, 59, -1, -1, -1,
- 8, -1, -1, -1, -1, -1, 69, 70, 71, 17,
- 73, 74, -1, -1, 22, 23, 24, -1, 26, -1,
- -1, 29, -1, -1, -1, -1, -1, -1, 36, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
- 3, 59, -1, -1, -1, 8, -1, -1, -1, -1,
- -1, 69, 70, 71, 17, 73, 74, -1, -1, 22,
- 23, 24, -1, 26, -1, -1, 29, -1, -1, -1,
- -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 3, -1, -1, 49, 50, 8, 52,
- 53, -1, -1, 56, -1, -1, 59, 17, -1, -1,
- -1, -1, 22, 23, 24, -1, 69, 70, 71, 29,
- 73, 74, -1, -1, -1, -1, 36, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 49,
- 50, -1, 52, 53, -1, -1, 56, -1, 3, 59,
- -1, -1, -1, 8, -1, -1, -1, 67, -1, 69,
- 70, 71, 17, 73, 74, -1, -1, 22, 23, 24,
- -1, -1, -1, -1, 29, -1, -1, -1, -1, -1,
- -1, 36, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 3, -1, -1, 49, 50, 8, 52, 53, -1,
- -1, 56, -1, -1, 59, 17, -1, -1, -1, -1,
- 22, 23, 24, -1, 69, 70, 71, 29, 73, 74,
- -1, -1, -1, -1, 36, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 3, -1, -1, 49, 50, 8,
- 52, 53, -1, -1, 56, -1, -1, 59, 17, -1,
- -1, -1, -1, 22, 23, 24, -1, 69, 70, 71,
- 29, 73, 74, -1, -1, -1, -1, 36, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 49, 50, 8, 52, 53, -1, -1, 56, -1, -1,
- 59, 17, -1, -1, -1, -1, 22, 23, 24, -1,
- 69, 70, 71, 29, 73, 74, -1, 8, -1, -1,
- 36, -1, -1, -1, -1, 8, 17, -1, 11, -1,
- -1, 22, 23, 24, 17, -1, -1, 53, 29, 22,
- 23, 24, -1, 59, -1, 36, 29, -1, -1, 65,
- -1, 8, -1, 36, -1, 71, -1, 73, 74, 75,
- 17, -1, 53, -1, -1, 22, 23, 24, 59, -1,
- 53, -1, 29, -1, -1, -1, 59, -1, 8, 36,
- 71, -1, 73, 74, 75, -1, -1, 17, 71, -1,
- 73, 74, 22, 23, 24, -1, 53, -1, -1, 29,
- -1, -1, 59, -1, 8, -1, 36, -1, -1, -1,
- -1, -1, 8, 17, 71, -1, 73, 74, 22, 23,
- 24, 17, -1, 53, -1, 29, 22, 23, 24, 59,
- -1, -1, 36, 29, -1, -1, -1, 8, -1, -1,
- 36, 71, -1, 73, 74, 8, 17, -1, 11, 53,
- -1, 22, 23, 24, 17, 59, -1, 53, 29, 22,
- 23, 24, -1, 59, -1, 36, 29, 71, -1, 73,
- 74, 8, -1, 36, -1, 71, -1, 73, 74, -1,
- 17, -1, 53, -1, -1, 22, 23, 24, -1, -1,
- 53, -1, 29, -1, -1, -1, -1, -1, -1, 36,
- 71, -1, 73, 74, -1, -1, -1, -1, 71, 34,
- -1, 74, -1, 38, 39, 40, 53, -1, 43, 44,
- 45, 46, 59, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, -1, -1, 71, 33, 34, 74, 36, -1,
- 38, 39, 40, -1, -1, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 33, 34,
- -1, 36, -1, 38, 39, 40, -1, 75, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, -1, -1, -1, -1, -1, -1, 33, 34,
- -1, 36, -1, 38, 39, 40, -1, 72, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 33, 34, -1, 36, -1, 38, 39, 40,
- -1, 66, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 54, 55, 56, 33, 34, -1, 36,
- -1, 38, 39, 40, -1, 66, 43, 44, 45, 46,
- 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- 33, 34, -1, 36, -1, 38, 39, 40, -1, 66,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- 53, 54, 55, 56, 33, 34, -1, -1, -1, 38,
- 39, 40, -1, -1, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, 54, 55, 56, 33, 34,
- -1, -1, -1, 38, 39, 40, -1, -1, 43, 44,
- 45, 46, -1, 48, 49, 50, 51, 52, 53, 54,
- 55, 56
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 77, 79, 80, 0, 25, 78, 25, 86, 24,
- 73, 74, 141, 142, 81, 24, 88, 89, 3, 62,
- 21, 82, 166, 24, 87, 214, 63, 3, 59, 63,
- 83, 85, 141, 62, 1, 3, 6, 8, 9, 10,
- 13, 15, 16, 17, 18, 19, 20, 22, 23, 27,
- 28, 29, 30, 31, 32, 36, 49, 50, 52, 53,
- 56, 59, 69, 70, 71, 90, 91, 92, 98, 110,
- 113, 121, 124, 126, 127, 128, 129, 134, 138, 141,
- 143, 144, 149, 150, 153, 156, 157, 158, 161, 164,
- 165, 181, 186, 62, 9, 17, 21, 31, 32, 64,
- 199, 24, 73, 60, 83, 84, 3, 86, 88, 3,
- 138, 140, 141, 17, 36, 53, 59, 141, 143, 148,
- 152, 153, 154, 161, 140, 128, 134, 111, 59, 141,
- 159, 128, 138, 114, 35, 67, 137, 71, 126, 186,
- 193, 125, 137, 122, 59, 96, 97, 141, 59, 93,
- 139, 141, 185, 127, 127, 127, 127, 127, 127, 36,
- 53, 126, 135, 147, 153, 155, 161, 127, 127, 11,
- 126, 192, 62, 59, 94, 185, 4, 33, 34, 36,
- 37, 38, 39, 40, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 67,
- 59, 63, 71, 66, 59, 137, 1, 137, 5, 65,
- 75, 142, 200, 59, 160, 200, 24, 200, 201, 200,
- 64, 62, 190, 88, 59, 36, 59, 146, 152, 153,
- 154, 155, 161, 146, 146, 63, 26, 98, 107, 108,
- 109, 186, 194, 11, 136, 141, 145, 146, 177, 178,
- 179, 59, 67, 162, 112, 194, 24, 59, 68, 138,
- 171, 173, 175, 146, 35, 53, 59, 68, 138, 170,
- 172, 173, 174, 184, 112, 60, 97, 169, 146, 60,
- 93, 167, 65, 75, 146, 8, 147, 60, 72, 72,
- 60, 94, 65, 146, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 130, 60, 135, 187, 59,
- 141, 126, 192, 182, 126, 130, 1, 67, 91, 100,
- 180, 181, 183, 186, 186, 126, 8, 17, 22, 23,
- 24, 29, 36, 53, 65, 71, 142, 202, 204, 205,
- 206, 141, 207, 215, 162, 59, 3, 202, 202, 83,
- 60, 179, 8, 146, 60, 141, 126, 35, 105, 5,
- 65, 62, 146, 136, 145, 75, 191, 60, 179, 183,
- 115, 62, 63, 24, 173, 59, 176, 62, 190, 72,
- 104, 59, 174, 53, 174, 62, 190, 3, 198, 75,
- 146, 123, 62, 190, 62, 190, 186, 139, 65, 36,
- 59, 146, 152, 153, 154, 161, 67, 146, 146, 62,
- 190, 186, 65, 67, 126, 131, 132, 188, 189, 11,
- 75, 191, 31, 135, 72, 66, 180, 75, 191, 189,
- 101, 62, 68, 36, 59, 203, 204, 206, 59, 67,
- 71, 67, 8, 202, 3, 50, 59, 141, 212, 213,
- 3, 72, 65, 11, 202, 60, 75, 62, 195, 215,
- 62, 62, 62, 60, 60, 106, 26, 26, 194, 177,
- 59, 141, 151, 152, 153, 154, 155, 161, 163, 60,
- 68, 105, 194, 141, 60, 179, 175, 68, 146, 7,
- 12, 68, 99, 102, 174, 198, 174, 60, 172, 68,
- 138, 198, 35, 97, 60, 93, 60, 186, 146, 130,
- 94, 95, 168, 185, 60, 186, 130, 66, 75, 191,
- 68, 191, 135, 60, 60, 60, 192, 60, 68, 183,
- 180, 202, 205, 195, 24, 141, 142, 197, 202, 209,
- 217, 202, 141, 196, 208, 216, 202, 3, 212, 62,
- 72, 202, 213, 202, 198, 141, 207, 60, 183, 126,
- 126, 62, 179, 59, 163, 116, 60, 187, 66, 103,
- 60, 60, 198, 104, 60, 189, 62, 190, 146, 189,
- 67, 126, 133, 131, 132, 60, 66, 72, 68, 60,
- 60, 59, 68, 62, 72, 202, 68, 62, 49, 202,
- 62, 198, 59, 59, 202, 210, 211, 68, 194, 60,
- 179, 119, 163, 5, 65, 66, 75, 183, 198, 198,
- 68, 68, 95, 60, 68, 130, 192, 210, 195, 209,
- 202, 198, 208, 212, 195, 195, 60, 14, 117, 120,
- 126, 126, 189, 72, 60, 60, 60, 60, 163, 20,
- 100, 66, 66, 68, 210, 210, 118, 112, 105
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar, yystate;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 2:
-#line 128 "go.y"
- {
- xtop = concat(xtop, (yyvsp[(4) - (4)].list));
- }
- break;
-
- case 3:
-#line 134 "go.y"
- {
- prevlineno = lineno;
- yyerror("package statement must be first");
- errorexit();
- }
- break;
-
- case 4:
-#line 140 "go.y"
- {
- mkpackage((yyvsp[(2) - (3)].sym)->name);
- }
- break;
-
- case 5:
-#line 150 "go.y"
- {
- importpkg = runtimepkg;
-
- if(debug['A'])
- cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
- else
- cannedimports("runtime.builtin", runtimeimport);
- curio.importsafe = 1;
- }
- break;
-
- case 6:
-#line 161 "go.y"
- {
- importpkg = nil;
- }
- break;
-
- case 12:
-#line 175 "go.y"
- {
- Pkg *ipkg;
- Sym *my;
- Node *pack;
-
- ipkg = importpkg;
- my = importmyname;
- importpkg = nil;
- importmyname = S;
-
- if(my == nil)
- my = lookup(ipkg->name);
-
- pack = nod(OPACK, N, N);
- pack->sym = my;
- pack->pkg = ipkg;
- pack->lineno = (yyvsp[(1) - (3)].i);
-
- if(my->name[0] == '.') {
- importdot(ipkg, pack);
- break;
- }
- if(strcmp(my->name, "init") == 0) {
- yyerror("cannot import package as init - init must be a func");
- break;
- }
- if(my->name[0] == '_' && my->name[1] == '\0')
- break;
- if(my->def) {
- lineno = (yyvsp[(1) - (3)].i);
- redeclare(my, "as imported package name");
- }
- my->def = pack;
- my->lastlineno = (yyvsp[(1) - (3)].i);
- my->block = 1; // at top level
- }
- break;
-
- case 13:
-#line 212 "go.y"
- {
- // When an invalid import path is passed to importfile,
- // it calls yyerror and then sets up a fake import with
- // no package statement. This allows us to test more
- // than one invalid import statement in a single file.
- if(nerrors == 0)
- fatal("phase error in import");
- }
- break;
-
- case 16:
-#line 227 "go.y"
- {
- // import with original name
- (yyval.i) = parserline();
- importmyname = S;
- importfile(&(yyvsp[(1) - (1)].val), (yyval.i));
- }
- break;
-
- case 17:
-#line 234 "go.y"
- {
- // import with given name
- (yyval.i) = parserline();
- importmyname = (yyvsp[(1) - (2)].sym);
- importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
- }
- break;
-
- case 18:
-#line 241 "go.y"
- {
- // import into my name space
- (yyval.i) = parserline();
- importmyname = lookup(".");
- importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
- }
- break;
-
- case 19:
-#line 250 "go.y"
- {
- if(importpkg->name == nil) {
- importpkg->name = (yyvsp[(2) - (4)].sym)->name;
- pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++;
- } else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0)
- yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path);
- importpkg->direct = 1;
- importpkg->safe = curio.importsafe;
-
- if(safemode && !curio.importsafe)
- yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
- }
- break;
-
- case 21:
-#line 265 "go.y"
- {
- if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
- curio.importsafe = 1;
- }
- break;
-
- case 22:
-#line 271 "go.y"
- {
- defercheckwidth();
- }
- break;
-
- case 23:
-#line 275 "go.y"
- {
- resumecheckwidth();
- unimportfile();
- }
- break;
-
- case 24:
-#line 284 "go.y"
- {
- yyerror("empty top-level declaration");
- (yyval.list) = nil;
- }
- break;
-
- case 26:
-#line 290 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 27:
-#line 294 "go.y"
- {
- yyerror("non-declaration statement outside function body");
- (yyval.list) = nil;
- }
- break;
-
- case 28:
-#line 299 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 29:
-#line 305 "go.y"
- {
- (yyval.list) = (yyvsp[(2) - (2)].list);
- }
- break;
-
- case 30:
-#line 309 "go.y"
- {
- (yyval.list) = (yyvsp[(3) - (5)].list);
- }
- break;
-
- case 31:
-#line 313 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 32:
-#line 317 "go.y"
- {
- (yyval.list) = (yyvsp[(2) - (2)].list);
- iota = -100000;
- lastconst = nil;
- }
- break;
-
- case 33:
-#line 323 "go.y"
- {
- (yyval.list) = (yyvsp[(3) - (5)].list);
- iota = -100000;
- lastconst = nil;
- }
- break;
-
- case 34:
-#line 329 "go.y"
- {
- (yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
- iota = -100000;
- lastconst = nil;
- }
- break;
-
- case 35:
-#line 335 "go.y"
- {
- (yyval.list) = nil;
- iota = -100000;
- }
- break;
-
- case 36:
-#line 340 "go.y"
- {
- (yyval.list) = list1((yyvsp[(2) - (2)].node));
- }
- break;
-
- case 37:
-#line 344 "go.y"
- {
- (yyval.list) = (yyvsp[(3) - (5)].list);
- }
- break;
-
- case 38:
-#line 348 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 39:
-#line 354 "go.y"
- {
- iota = 0;
- }
- break;
-
- case 40:
-#line 360 "go.y"
- {
- (yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
- }
- break;
-
- case 41:
-#line 364 "go.y"
- {
- (yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
- }
- break;
-
- case 42:
-#line 368 "go.y"
- {
- (yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
- }
- break;
-
- case 43:
-#line 374 "go.y"
- {
- (yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
- }
- break;
-
- case 44:
-#line 378 "go.y"
- {
- (yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
- }
- break;
-
- case 46:
-#line 385 "go.y"
- {
- (yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
- }
- break;
-
- case 47:
-#line 389 "go.y"
- {
- (yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
- }
- break;
-
- case 48:
-#line 395 "go.y"
- {
- // different from dclname because the name
- // becomes visible right here, not at the end
- // of the declaration.
- (yyval.node) = typedcl0((yyvsp[(1) - (1)].sym));
- }
- break;
-
- case 49:
-#line 404 "go.y"
- {
- (yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
- }
- break;
-
- case 50:
-#line 410 "go.y"
- {
- (yyval.node) = (yyvsp[(1) - (1)].node);
-
- // These nodes do not carry line numbers.
- // Since a bare name used as an expression is an error,
- // introduce a wrapper node to give the correct line.
- switch((yyval.node)->op) {
- case ONAME:
- case ONONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- (yyval.node) = nod(OPAREN, (yyval.node), N);
- (yyval.node)->implicit = 1;
- break;
- }
- }
- break;
-
- case 51:
-#line 428 "go.y"
- {
- (yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- (yyval.node)->etype = (yyvsp[(2) - (3)].i); // rathole to pass opcode
- }
- break;
-
- case 52:
-#line 433 "go.y"
- {
- if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
- // simple
- (yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n);
- break;
- }
- // multiple
- (yyval.node) = nod(OAS2, N, N);
- (yyval.node)->list = (yyvsp[(1) - (3)].list);
- (yyval.node)->rlist = (yyvsp[(3) - (3)].list);
- }
- break;
-
- case 53:
-#line 445 "go.y"
- {
- if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
- (yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right);
- if((yyvsp[(3) - (3)].list)->next != nil)
- yyerror("expr.(type) must be alone in list");
- if((yyvsp[(1) - (3)].list)->next != nil)
- yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1);
- else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n))
- yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n);
- else
- (yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym); // it's a colas, so must not re-use an oldname.
- break;
- }
- (yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list), (yyvsp[(2) - (3)].i));
- }
- break;
-
- case 54:
-#line 461 "go.y"
- {
- (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
- (yyval.node)->implicit = 1;
- (yyval.node)->etype = OADD;
- }
- break;
-
- case 55:
-#line 467 "go.y"
- {
- (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
- (yyval.node)->implicit = 1;
- (yyval.node)->etype = OSUB;
- }
- break;
-
- case 56:
-#line 475 "go.y"
- {
- Node *n, *nn;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- (yyval.node) = nod(OXCASE, N, N);
- (yyval.node)->list = (yyvsp[(2) - (3)].list);
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- nn = newname(n->sym);
- declare(nn, dclcontext);
- (yyval.node)->nname = nn;
-
- // keep track of the instances for reporting unused
- nn->defn = typesw->right;
- }
- }
- break;
-
- case 57:
-#line 495 "go.y"
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- (yyval.node) = nod(OXCASE, N, N);
- if((yyvsp[(2) - (5)].list)->next == nil)
- n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node));
- else {
- n = nod(OAS2, N, N);
- n->list = (yyvsp[(2) - (5)].list);
- n->rlist = list1((yyvsp[(4) - (5)].node));
- }
- (yyval.node)->list = list1(n);
- }
- break;
-
- case 58:
-#line 513 "go.y"
- {
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- (yyval.node) = nod(OXCASE, N, N);
- (yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node)), (yyvsp[(3) - (5)].i)));
- }
- break;
-
- case 59:
-#line 522 "go.y"
- {
- Node *n, *nn;
-
- markdcl();
- (yyval.node) = nod(OXCASE, N, N);
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- nn = newname(n->sym);
- declare(nn, dclcontext);
- (yyval.node)->nname = nn;
-
- // keep track of the instances for reporting unused
- nn->defn = typesw->right;
- }
- }
- break;
-
- case 60:
-#line 540 "go.y"
- {
- markdcl();
- }
- break;
-
- case 61:
-#line 544 "go.y"
- {
- if((yyvsp[(3) - (4)].list) == nil)
- (yyval.node) = nod(OEMPTY, N, N);
- else
- (yyval.node) = liststmt((yyvsp[(3) - (4)].list));
- popdcl();
- }
- break;
-
- case 62:
-#line 554 "go.y"
- {
- // If the last token read by the lexer was consumed
- // as part of the case, clear it (parser has cleared yychar).
- // If the last token read by the lexer was the lookahead
- // leave it alone (parser has it cached in yychar).
- // This is so that the stmt_list action doesn't look at
- // the case tokens if the stmt_list is empty.
- yylast = yychar;
- (yyvsp[(1) - (1)].node)->xoffset = block;
- }
- break;
-
- case 63:
-#line 565 "go.y"
- {
- int last;
-
- // This is the only place in the language where a statement
- // list is not allowed to drop the final semicolon, because
- // it's the only place where a statement list is not followed
- // by a closing brace. Handle the error for pedantry.
-
- // Find the final token of the statement list.
- // yylast is lookahead; yyprev is last of stmt_list
- last = yyprev;
-
- if(last > 0 && last != ';' && yychar != '}')
- yyerror("missing statement after label");
- (yyval.node) = (yyvsp[(1) - (3)].node);
- (yyval.node)->nbody = (yyvsp[(3) - (3)].list);
- popdcl();
- }
- break;
-
- case 64:
-#line 585 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 65:
-#line 589 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 66:
-#line 595 "go.y"
- {
- markdcl();
- }
- break;
-
- case 67:
-#line 599 "go.y"
- {
- (yyval.list) = (yyvsp[(3) - (4)].list);
- popdcl();
- }
- break;
-
- case 68:
-#line 606 "go.y"
- {
- (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
- (yyval.node)->list = (yyvsp[(1) - (4)].list);
- (yyval.node)->etype = 0; // := flag
- }
- break;
-
- case 69:
-#line 612 "go.y"
- {
- (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
- (yyval.node)->list = (yyvsp[(1) - (4)].list);
- (yyval.node)->colas = 1;
- colasdefn((yyvsp[(1) - (4)].list), (yyval.node));
- }
- break;
-
- case 70:
-#line 619 "go.y"
- {
- (yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node));
- (yyval.node)->etype = 0; // := flag
- }
- break;
-
- case 71:
-#line 626 "go.y"
- {
- // init ; test ; incr
- if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
- yyerror("cannot declare in the for-increment");
- (yyval.node) = nod(OFOR, N, N);
- if((yyvsp[(1) - (5)].node) != N)
- (yyval.node)->ninit = list1((yyvsp[(1) - (5)].node));
- (yyval.node)->ntest = (yyvsp[(3) - (5)].node);
- (yyval.node)->nincr = (yyvsp[(5) - (5)].node);
- }
- break;
-
- case 72:
-#line 637 "go.y"
- {
- // normal test
- (yyval.node) = nod(OFOR, N, N);
- (yyval.node)->ntest = (yyvsp[(1) - (1)].node);
- }
- break;
-
- case 74:
-#line 646 "go.y"
- {
- (yyval.node) = (yyvsp[(1) - (2)].node);
- (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
- }
- break;
-
- case 75:
-#line 653 "go.y"
- {
- markdcl();
- }
- break;
-
- case 76:
-#line 657 "go.y"
- {
- (yyval.node) = (yyvsp[(3) - (3)].node);
- popdcl();
- }
- break;
-
- case 77:
-#line 664 "go.y"
- {
- // test
- (yyval.node) = nod(OIF, N, N);
- (yyval.node)->ntest = (yyvsp[(1) - (1)].node);
- }
- break;
-
- case 78:
-#line 670 "go.y"
- {
- // init ; test
- (yyval.node) = nod(OIF, N, N);
- if((yyvsp[(1) - (3)].node) != N)
- (yyval.node)->ninit = list1((yyvsp[(1) - (3)].node));
- (yyval.node)->ntest = (yyvsp[(3) - (3)].node);
- }
- break;
-
- case 79:
-#line 681 "go.y"
- {
- markdcl();
- }
- break;
-
- case 80:
-#line 685 "go.y"
- {
- if((yyvsp[(3) - (3)].node)->ntest == N)
- yyerror("missing condition in if statement");
- }
- break;
-
- case 81:
-#line 690 "go.y"
- {
- (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
- }
- break;
-
- case 82:
-#line 694 "go.y"
- {
- Node *n;
- NodeList *nn;
-
- (yyval.node) = (yyvsp[(3) - (8)].node);
- n = (yyvsp[(3) - (8)].node);
- popdcl();
- for(nn = concat((yyvsp[(7) - (8)].list), (yyvsp[(8) - (8)].list)); nn; nn = nn->next) {
- if(nn->n->op == OIF)
- popdcl();
- n->nelse = list1(nn->n);
- n = nn->n;
- }
- }
- break;
-
- case 83:
-#line 711 "go.y"
- {
- markdcl();
- }
- break;
-
- case 84:
-#line 715 "go.y"
- {
- if((yyvsp[(4) - (5)].node)->ntest == N)
- yyerror("missing condition in if statement");
- (yyvsp[(4) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
- (yyval.list) = list1((yyvsp[(4) - (5)].node));
- }
- break;
-
- case 85:
-#line 723 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 86:
-#line 727 "go.y"
- {
- (yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
- }
- break;
-
- case 87:
-#line 732 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 88:
-#line 736 "go.y"
- {
- NodeList *node;
-
- node = mal(sizeof *node);
- node->n = (yyvsp[(2) - (2)].node);
- node->end = node;
- (yyval.list) = node;
- }
- break;
-
- case 89:
-#line 747 "go.y"
- {
- markdcl();
- }
- break;
-
- case 90:
-#line 751 "go.y"
- {
- Node *n;
- n = (yyvsp[(3) - (3)].node)->ntest;
- if(n != N && n->op != OTYPESW)
- n = N;
- typesw = nod(OXXX, typesw, n);
- }
- break;
-
- case 91:
-#line 759 "go.y"
- {
- (yyval.node) = (yyvsp[(3) - (7)].node);
- (yyval.node)->op = OSWITCH;
- (yyval.node)->list = (yyvsp[(6) - (7)].list);
- typesw = typesw->left;
- popdcl();
- }
- break;
-
- case 92:
-#line 769 "go.y"
- {
- typesw = nod(OXXX, typesw, N);
- }
- break;
-
- case 93:
-#line 773 "go.y"
- {
- (yyval.node) = nod(OSELECT, N, N);
- (yyval.node)->lineno = typesw->lineno;
- (yyval.node)->list = (yyvsp[(4) - (5)].list);
- typesw = typesw->left;
- }
- break;
-
- case 95:
-#line 786 "go.y"
- {
- (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 96:
-#line 790 "go.y"
- {
- (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 97:
-#line 794 "go.y"
- {
- (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 98:
-#line 798 "go.y"
- {
- (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 99:
-#line 802 "go.y"
- {
- (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 100:
-#line 806 "go.y"
- {
- (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 101:
-#line 810 "go.y"
- {
- (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 102:
-#line 814 "go.y"
- {
- (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 103:
-#line 818 "go.y"
- {
- (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 104:
-#line 822 "go.y"
- {
- (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 105:
-#line 826 "go.y"
- {
- (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 106:
-#line 830 "go.y"
- {
- (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 107:
-#line 834 "go.y"
- {
- (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 108:
-#line 838 "go.y"
- {
- (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 109:
-#line 842 "go.y"
- {
- (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 110:
-#line 846 "go.y"
- {
- (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 111:
-#line 850 "go.y"
- {
- (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 112:
-#line 854 "go.y"
- {
- (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 113:
-#line 858 "go.y"
- {
- (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 114:
-#line 863 "go.y"
- {
- (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 116:
-#line 870 "go.y"
- {
- (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 117:
-#line 874 "go.y"
- {
- if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
- // Special case for &T{...}: turn into (*T){...}.
- (yyval.node) = (yyvsp[(2) - (2)].node);
- (yyval.node)->right = nod(OIND, (yyval.node)->right, N);
- (yyval.node)->right->implicit = 1;
- } else {
- (yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N);
- }
- }
- break;
-
- case 118:
-#line 885 "go.y"
- {
- (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 119:
-#line 889 "go.y"
- {
- (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 120:
-#line 893 "go.y"
- {
- (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 121:
-#line 897 "go.y"
- {
- yyerror("the bitwise complement operator is ^");
- (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 122:
-#line 902 "go.y"
- {
- (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 123:
-#line 906 "go.y"
- {
- (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 124:
-#line 916 "go.y"
- {
- (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
- }
- break;
-
- case 125:
-#line 920 "go.y"
- {
- (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
- (yyval.node)->list = (yyvsp[(3) - (5)].list);
- }
- break;
-
- case 126:
-#line 925 "go.y"
- {
- (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
- (yyval.node)->list = (yyvsp[(3) - (6)].list);
- (yyval.node)->isddd = 1;
- }
- break;
-
- case 127:
-#line 933 "go.y"
- {
- (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
- }
- break;
-
- case 129:
-#line 938 "go.y"
- {
- if((yyvsp[(1) - (3)].node)->op == OPACK) {
- Sym *s;
- s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
- (yyvsp[(1) - (3)].node)->used = 1;
- (yyval.node) = oldname(s);
- break;
- }
- (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
- }
- break;
-
- case 130:
-#line 949 "go.y"
- {
- (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
- }
- break;
-
- case 131:
-#line 953 "go.y"
- {
- (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
- }
- break;
-
- case 132:
-#line 957 "go.y"
- {
- (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
- }
- break;
-
- case 133:
-#line 961 "go.y"
- {
- (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
- }
- break;
-
- case 134:
-#line 965 "go.y"
- {
- if((yyvsp[(5) - (8)].node) == N)
- yyerror("middle index required in 3-index slice");
- if((yyvsp[(7) - (8)].node) == N)
- yyerror("final index required in 3-index slice");
- (yyval.node) = nod(OSLICE3, (yyvsp[(1) - (8)].node), nod(OKEY, (yyvsp[(3) - (8)].node), nod(OKEY, (yyvsp[(5) - (8)].node), (yyvsp[(7) - (8)].node))));
- }
- break;
-
- case 136:
-#line 974 "go.y"
- {
- // conversion
- (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
- (yyval.node)->list = list1((yyvsp[(3) - (5)].node));
- }
- break;
-
- case 137:
-#line 980 "go.y"
- {
- (yyval.node) = (yyvsp[(3) - (5)].node);
- (yyval.node)->right = (yyvsp[(1) - (5)].node);
- (yyval.node)->list = (yyvsp[(4) - (5)].list);
- fixlbrace((yyvsp[(2) - (5)].i));
- }
- break;
-
- case 138:
-#line 987 "go.y"
- {
- (yyval.node) = (yyvsp[(3) - (5)].node);
- (yyval.node)->right = (yyvsp[(1) - (5)].node);
- (yyval.node)->list = (yyvsp[(4) - (5)].list);
- }
- break;
-
- case 139:
-#line 993 "go.y"
- {
- yyerror("cannot parenthesize type in composite literal");
- (yyval.node) = (yyvsp[(5) - (7)].node);
- (yyval.node)->right = (yyvsp[(2) - (7)].node);
- (yyval.node)->list = (yyvsp[(6) - (7)].list);
- }
- break;
-
- case 141:
-#line 1002 "go.y"
- {
- // composite expression.
- // make node early so we get the right line number.
- (yyval.node) = nod(OCOMPLIT, N, N);
- }
- break;
-
- case 142:
-#line 1010 "go.y"
- {
- (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 143:
-#line 1016 "go.y"
- {
- // These nodes do not carry line numbers.
- // Since a composite literal commonly spans several lines,
- // the line number on errors may be misleading.
- // Introduce a wrapper node to give the correct line.
- (yyval.node) = (yyvsp[(1) - (1)].node);
- switch((yyval.node)->op) {
- case ONAME:
- case ONONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- (yyval.node) = nod(OPAREN, (yyval.node), N);
- (yyval.node)->implicit = 1;
- }
- }
- break;
-
- case 144:
-#line 1033 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (4)].node);
- (yyval.node)->list = (yyvsp[(3) - (4)].list);
- }
- break;
-
- case 146:
-#line 1041 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (4)].node);
- (yyval.node)->list = (yyvsp[(3) - (4)].list);
- }
- break;
-
- case 148:
-#line 1049 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
-
- // Need to know on lhs of := whether there are ( ).
- // Don't bother with the OPAREN in other cases:
- // it's just a waste of memory and time.
- switch((yyval.node)->op) {
- case ONAME:
- case ONONAME:
- case OPACK:
- case OTYPE:
- case OLITERAL:
- case OTYPESW:
- (yyval.node) = nod(OPAREN, (yyval.node), N);
- }
- }
- break;
-
- case 152:
-#line 1075 "go.y"
- {
- (yyval.i) = LBODY;
- }
- break;
-
- case 153:
-#line 1079 "go.y"
- {
- (yyval.i) = '{';
- }
- break;
-
- case 154:
-#line 1090 "go.y"
- {
- if((yyvsp[(1) - (1)].sym) == S)
- (yyval.node) = N;
- else
- (yyval.node) = newname((yyvsp[(1) - (1)].sym));
- }
- break;
-
- case 155:
-#line 1099 "go.y"
- {
- (yyval.node) = dclname((yyvsp[(1) - (1)].sym));
- }
- break;
-
- case 156:
-#line 1104 "go.y"
- {
- (yyval.node) = N;
- }
- break;
-
- case 158:
-#line 1111 "go.y"
- {
- (yyval.sym) = (yyvsp[(1) - (1)].sym);
- // during imports, unqualified non-exported identifiers are from builtinpkg
- if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name))
- (yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
- }
- break;
-
- case 160:
-#line 1119 "go.y"
- {
- (yyval.sym) = S;
- }
- break;
-
- case 161:
-#line 1125 "go.y"
- {
- Pkg *p;
-
- if((yyvsp[(2) - (4)].val).u.sval->len == 0)
- p = importpkg;
- else {
- if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
- errorexit();
- p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
- }
- (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, p);
- }
- break;
-
- case 162:
-#line 1138 "go.y"
- {
- Pkg *p;
-
- if((yyvsp[(2) - (4)].val).u.sval->len == 0)
- p = importpkg;
- else {
- if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
- errorexit();
- p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
- }
- (yyval.sym) = pkglookup("?", p);
- }
- break;
-
- case 163:
-#line 1153 "go.y"
- {
- (yyval.node) = oldname((yyvsp[(1) - (1)].sym));
- if((yyval.node)->pack != N)
- (yyval.node)->pack->used = 1;
- }
- break;
-
- case 165:
-#line 1173 "go.y"
- {
- yyerror("final argument in variadic function missing type");
- (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
- }
- break;
-
- case 166:
-#line 1178 "go.y"
- {
- (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 172:
-#line 1189 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 176:
-#line 1198 "go.y"
- {
- (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 181:
-#line 1208 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- }
- break;
-
- case 191:
-#line 1229 "go.y"
- {
- if((yyvsp[(1) - (3)].node)->op == OPACK) {
- Sym *s;
- s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
- (yyvsp[(1) - (3)].node)->used = 1;
- (yyval.node) = oldname(s);
- break;
- }
- (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
- }
- break;
-
- case 192:
-#line 1242 "go.y"
- {
- (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
- }
- break;
-
- case 193:
-#line 1246 "go.y"
- {
- // array literal of nelem
- (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
- }
- break;
-
- case 194:
-#line 1251 "go.y"
- {
- (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
- (yyval.node)->etype = Cboth;
- }
- break;
-
- case 195:
-#line 1256 "go.y"
- {
- (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
- (yyval.node)->etype = Csend;
- }
- break;
-
- case 196:
-#line 1261 "go.y"
- {
- (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
- }
- break;
-
- case 199:
-#line 1269 "go.y"
- {
- (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 200:
-#line 1275 "go.y"
- {
- (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
- (yyval.node)->etype = Crecv;
- }
- break;
-
- case 201:
-#line 1282 "go.y"
- {
- (yyval.node) = nod(OTSTRUCT, N, N);
- (yyval.node)->list = (yyvsp[(3) - (5)].list);
- fixlbrace((yyvsp[(2) - (5)].i));
- }
- break;
-
- case 202:
-#line 1288 "go.y"
- {
- (yyval.node) = nod(OTSTRUCT, N, N);
- fixlbrace((yyvsp[(2) - (3)].i));
- }
- break;
-
- case 203:
-#line 1295 "go.y"
- {
- (yyval.node) = nod(OTINTER, N, N);
- (yyval.node)->list = (yyvsp[(3) - (5)].list);
- fixlbrace((yyvsp[(2) - (5)].i));
- }
- break;
-
- case 204:
-#line 1301 "go.y"
- {
- (yyval.node) = nod(OTINTER, N, N);
- fixlbrace((yyvsp[(2) - (3)].i));
- }
- break;
-
- case 205:
-#line 1312 "go.y"
- {
- (yyval.node) = (yyvsp[(2) - (3)].node);
- if((yyval.node) == N)
- break;
- if(noescape && (yyvsp[(3) - (3)].list) != nil)
- yyerror("can only use //go:noescape with external func implementations");
- (yyval.node)->nbody = (yyvsp[(3) - (3)].list);
- (yyval.node)->endlineno = lineno;
- (yyval.node)->noescape = noescape;
- (yyval.node)->nosplit = nosplit;
- (yyval.node)->nowritebarrier = nowritebarrier;
- funcbody((yyval.node));
- }
- break;
-
- case 206:
-#line 1328 "go.y"
- {
- Node *t;
-
- (yyval.node) = N;
- (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
-
- if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) {
- (yyvsp[(1) - (5)].sym) = renameinit();
- if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
- yyerror("func init must have no arguments and no return values");
- }
- if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) {
- if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
- yyerror("func main must have no arguments and no return values");
- }
-
- t = nod(OTFUNC, N, N);
- t->list = (yyvsp[(3) - (5)].list);
- t->rlist = (yyvsp[(5) - (5)].list);
-
- (yyval.node) = nod(ODCLFUNC, N, N);
- (yyval.node)->nname = newname((yyvsp[(1) - (5)].sym));
- (yyval.node)->nname->defn = (yyval.node);
- (yyval.node)->nname->ntype = t; // TODO: check if nname already has an ntype
- declare((yyval.node)->nname, PFUNC);
-
- funchdr((yyval.node));
- }
- break;
-
- case 207:
-#line 1357 "go.y"
- {
- Node *rcvr, *t;
-
- (yyval.node) = N;
- (yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0);
- (yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1);
-
- if((yyvsp[(2) - (8)].list) == nil) {
- yyerror("method has no receiver");
- break;
- }
- if((yyvsp[(2) - (8)].list)->next != nil) {
- yyerror("method has multiple receivers");
- break;
- }
- rcvr = (yyvsp[(2) - (8)].list)->n;
- if(rcvr->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- break;
- }
-
- t = nod(OTFUNC, rcvr, N);
- t->list = (yyvsp[(6) - (8)].list);
- t->rlist = (yyvsp[(8) - (8)].list);
-
- (yyval.node) = nod(ODCLFUNC, N, N);
- (yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym));
- (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
- (yyval.node)->nname->defn = (yyval.node);
- (yyval.node)->nname->ntype = t;
- (yyval.node)->nname->nointerface = nointerface;
- declare((yyval.node)->nname, PFUNC);
-
- funchdr((yyval.node));
- }
- break;
-
- case 208:
-#line 1395 "go.y"
- {
- Sym *s;
- Type *t;
-
- (yyval.node) = N;
-
- s = (yyvsp[(1) - (5)].sym);
- t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
-
- importsym(s, ONAME);
- if(s->def != N && s->def->op == ONAME) {
- if(eqtype(t, s->def->type)) {
- dclcontext = PDISCARD; // since we skip funchdr below
- break;
- }
- yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
- }
-
- (yyval.node) = newname(s);
- (yyval.node)->type = t;
- declare((yyval.node), PFUNC);
-
- funchdr((yyval.node));
- }
- break;
-
- case 209:
-#line 1420 "go.y"
- {
- (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right);
- (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
-
- checkwidth((yyval.node)->type);
- addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0, nointerface);
- nointerface = 0;
- funchdr((yyval.node));
-
- // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
- // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
- // out by typecheck's lookdot as this $$->ttype. So by providing
- // this back link here we avoid special casing there.
- (yyval.node)->type->nname = (yyval.node);
- }
- break;
-
- case 210:
-#line 1438 "go.y"
- {
- (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
- (yyval.node) = nod(OTFUNC, N, N);
- (yyval.node)->list = (yyvsp[(3) - (5)].list);
- (yyval.node)->rlist = (yyvsp[(5) - (5)].list);
- }
- break;
-
- case 211:
-#line 1446 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 212:
-#line 1450 "go.y"
- {
- (yyval.list) = (yyvsp[(2) - (3)].list);
- if((yyval.list) == nil)
- (yyval.list) = list1(nod(OEMPTY, N, N));
- }
- break;
-
- case 213:
-#line 1458 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 214:
-#line 1462 "go.y"
- {
- (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
- }
- break;
-
- case 215:
-#line 1466 "go.y"
- {
- (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
- (yyval.list) = (yyvsp[(2) - (3)].list);
- }
- break;
-
- case 216:
-#line 1473 "go.y"
- {
- closurehdr((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 217:
-#line 1479 "go.y"
- {
- (yyval.node) = closurebody((yyvsp[(3) - (4)].list));
- fixlbrace((yyvsp[(2) - (4)].i));
- }
- break;
-
- case 218:
-#line 1484 "go.y"
- {
- (yyval.node) = closurebody(nil);
- }
- break;
-
- case 219:
-#line 1495 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 220:
-#line 1499 "go.y"
- {
- (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
- if(nsyntaxerrors == 0)
- testdclstack();
- nointerface = 0;
- noescape = 0;
- nosplit = 0;
- nowritebarrier = 0;
- }
- break;
-
- case 222:
-#line 1512 "go.y"
- {
- (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
- }
- break;
-
- case 224:
-#line 1519 "go.y"
- {
- (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
- }
- break;
-
- case 225:
-#line 1525 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 226:
-#line 1529 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 228:
-#line 1536 "go.y"
- {
- (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
- }
- break;
-
- case 229:
-#line 1542 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 230:
-#line 1546 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 231:
-#line 1552 "go.y"
- {
- NodeList *l;
-
- Node *n;
- l = (yyvsp[(1) - (3)].list);
- if(l == nil) {
- // ? symbol, during import (list1(N) == nil)
- n = (yyvsp[(2) - (3)].node);
- if(n->op == OIND)
- n = n->left;
- n = embedded(n->sym, importpkg);
- n->right = (yyvsp[(2) - (3)].node);
- n->val = (yyvsp[(3) - (3)].val);
- (yyval.list) = list1(n);
- break;
- }
-
- for(l=(yyvsp[(1) - (3)].list); l; l=l->next) {
- l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node));
- l->n->val = (yyvsp[(3) - (3)].val);
- }
- }
- break;
-
- case 232:
-#line 1575 "go.y"
- {
- (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
- (yyval.list) = list1((yyvsp[(1) - (2)].node));
- }
- break;
-
- case 233:
-#line 1580 "go.y"
- {
- (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
- (yyval.list) = list1((yyvsp[(2) - (4)].node));
- yyerror("cannot parenthesize embedded type");
- }
- break;
-
- case 234:
-#line 1586 "go.y"
- {
- (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
- (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
- (yyval.list) = list1((yyvsp[(2) - (3)].node));
- }
- break;
-
- case 235:
-#line 1592 "go.y"
- {
- (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
- (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
- (yyval.list) = list1((yyvsp[(3) - (5)].node));
- yyerror("cannot parenthesize embedded type");
- }
- break;
-
- case 236:
-#line 1599 "go.y"
- {
- (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
- (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
- (yyval.list) = list1((yyvsp[(3) - (5)].node));
- yyerror("cannot parenthesize embedded type");
- }
- break;
-
- case 237:
-#line 1608 "go.y"
- {
- Node *n;
-
- (yyval.sym) = (yyvsp[(1) - (1)].sym);
- n = oldname((yyvsp[(1) - (1)].sym));
- if(n->pack != N)
- n->pack->used = 1;
- }
- break;
-
- case 238:
-#line 1617 "go.y"
- {
- Pkg *pkg;
-
- if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) {
- yyerror("%S is not a package", (yyvsp[(1) - (3)].sym));
- pkg = localpkg;
- } else {
- (yyvsp[(1) - (3)].sym)->def->used = 1;
- pkg = (yyvsp[(1) - (3)].sym)->def->pkg;
- }
- (yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg);
- }
- break;
-
- case 239:
-#line 1632 "go.y"
- {
- (yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg);
- }
- break;
-
- case 240:
-#line 1638 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
- ifacedcl((yyval.node));
- }
- break;
-
- case 241:
-#line 1643 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
- }
- break;
-
- case 242:
-#line 1647 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
- yyerror("cannot parenthesize embedded type");
- }
- break;
-
- case 243:
-#line 1654 "go.y"
- {
- // without func keyword
- (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
- (yyval.node) = nod(OTFUNC, fakethis(), N);
- (yyval.node)->list = (yyvsp[(2) - (4)].list);
- (yyval.node)->rlist = (yyvsp[(4) - (4)].list);
- }
- break;
-
- case 245:
-#line 1668 "go.y"
- {
- (yyval.node) = nod(ONONAME, N, N);
- (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
- (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 246:
-#line 1674 "go.y"
- {
- (yyval.node) = nod(ONONAME, N, N);
- (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
- (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
- }
- break;
-
- case 248:
-#line 1683 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 249:
-#line 1687 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 250:
-#line 1692 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 251:
-#line 1696 "go.y"
- {
- (yyval.list) = (yyvsp[(1) - (2)].list);
- }
- break;
-
- case 252:
-#line 1704 "go.y"
- {
- (yyval.node) = N;
- }
- break;
-
- case 254:
-#line 1709 "go.y"
- {
- (yyval.node) = liststmt((yyvsp[(1) - (1)].list));
- }
- break;
-
- case 256:
-#line 1714 "go.y"
- {
- (yyval.node) = N;
- }
- break;
-
- case 262:
-#line 1725 "go.y"
- {
- (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
- (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
- }
- break;
-
- case 263:
-#line 1730 "go.y"
- {
- NodeList *l;
-
- (yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node);
- l = list1((yyvsp[(1) - (4)].node));
- if((yyvsp[(4) - (4)].node))
- l = list(l, (yyvsp[(4) - (4)].node));
- (yyval.node) = liststmt(l);
- }
- break;
-
- case 264:
-#line 1740 "go.y"
- {
- // will be converted to OFALL
- (yyval.node) = nod(OXFALL, N, N);
- (yyval.node)->xoffset = block;
- }
- break;
-
- case 265:
-#line 1746 "go.y"
- {
- (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 266:
-#line 1750 "go.y"
- {
- (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 267:
-#line 1754 "go.y"
- {
- (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 268:
-#line 1758 "go.y"
- {
- (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
- }
- break;
-
- case 269:
-#line 1762 "go.y"
- {
- (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
- (yyval.node)->sym = dclstack; // context, for goto restrictions
- }
- break;
-
- case 270:
-#line 1767 "go.y"
- {
- (yyval.node) = nod(ORETURN, N, N);
- (yyval.node)->list = (yyvsp[(2) - (2)].list);
- if((yyval.node)->list == nil && curfn != N) {
- NodeList *l;
-
- for(l=curfn->dcl; l; l=l->next) {
- if(l->n->class == PPARAM)
- continue;
- if(l->n->class != PPARAMOUT)
- break;
- if(l->n->sym->def != l->n)
- yyerror("%s is shadowed during return", l->n->sym->name);
- }
- }
- }
- break;
-
- case 271:
-#line 1786 "go.y"
- {
- (yyval.list) = nil;
- if((yyvsp[(1) - (1)].node) != N)
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 272:
-#line 1792 "go.y"
- {
- (yyval.list) = (yyvsp[(1) - (3)].list);
- if((yyvsp[(3) - (3)].node) != N)
- (yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 273:
-#line 1800 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 274:
-#line 1804 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 275:
-#line 1810 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 276:
-#line 1814 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 277:
-#line 1820 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 278:
-#line 1824 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 279:
-#line 1830 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 280:
-#line 1834 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 281:
-#line 1843 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 282:
-#line 1847 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 283:
-#line 1851 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 284:
-#line 1855 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 285:
-#line 1860 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 286:
-#line 1864 "go.y"
- {
- (yyval.list) = (yyvsp[(1) - (2)].list);
- }
- break;
-
- case 291:
-#line 1878 "go.y"
- {
- (yyval.node) = N;
- }
- break;
-
- case 293:
-#line 1884 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 295:
-#line 1890 "go.y"
- {
- (yyval.node) = N;
- }
- break;
-
- case 297:
-#line 1896 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 299:
-#line 1902 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 301:
-#line 1908 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 303:
-#line 1914 "go.y"
- {
- (yyval.val).ctype = CTxxx;
- }
- break;
-
- case 305:
-#line 1924 "go.y"
- {
- importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
- }
- break;
-
- case 306:
-#line 1928 "go.y"
- {
- importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
- }
- break;
-
- case 307:
-#line 1932 "go.y"
- {
- importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
- }
- break;
-
- case 308:
-#line 1936 "go.y"
- {
- importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
- }
- break;
-
- case 309:
-#line 1940 "go.y"
- {
- importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
- }
- break;
-
- case 310:
-#line 1944 "go.y"
- {
- if((yyvsp[(2) - (4)].node) == N) {
- dclcontext = PEXTERN; // since we skip the funcbody below
- break;
- }
-
- (yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list);
-
- funcbody((yyvsp[(2) - (4)].node));
- importlist = list(importlist, (yyvsp[(2) - (4)].node));
-
- if(debug['E']) {
- print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node));
- if(debug['m'] > 2 && (yyvsp[(2) - (4)].node)->inl)
- print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl);
- }
- }
- break;
-
- case 311:
-#line 1964 "go.y"
- {
- (yyval.sym) = (yyvsp[(1) - (1)].sym);
- structpkg = (yyval.sym)->pkg;
- }
- break;
-
- case 312:
-#line 1971 "go.y"
- {
- (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
- importsym((yyvsp[(1) - (1)].sym), OTYPE);
- }
- break;
-
- case 318:
-#line 1991 "go.y"
- {
- (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
- }
- break;
-
- case 319:
-#line 1995 "go.y"
- {
- // predefined name like uint8
- (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
- if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) {
- yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name);
- (yyval.type) = T;
- } else
- (yyval.type) = (yyvsp[(1) - (1)].sym)->def->type;
- }
- break;
-
- case 320:
-#line 2005 "go.y"
- {
- (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
- }
- break;
-
- case 321:
-#line 2009 "go.y"
- {
- (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
- }
- break;
-
- case 322:
-#line 2013 "go.y"
- {
- (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
- }
- break;
-
- case 323:
-#line 2017 "go.y"
- {
- (yyval.type) = tostruct((yyvsp[(3) - (4)].list));
- }
- break;
-
- case 324:
-#line 2021 "go.y"
- {
- (yyval.type) = tointerface((yyvsp[(3) - (4)].list));
- }
- break;
-
- case 325:
-#line 2025 "go.y"
- {
- (yyval.type) = ptrto((yyvsp[(2) - (2)].type));
- }
- break;
-
- case 326:
-#line 2029 "go.y"
- {
- (yyval.type) = typ(TCHAN);
- (yyval.type)->type = (yyvsp[(2) - (2)].type);
- (yyval.type)->chan = Cboth;
- }
- break;
-
- case 327:
-#line 2035 "go.y"
- {
- (yyval.type) = typ(TCHAN);
- (yyval.type)->type = (yyvsp[(3) - (4)].type);
- (yyval.type)->chan = Cboth;
- }
- break;
-
- case 328:
-#line 2041 "go.y"
- {
- (yyval.type) = typ(TCHAN);
- (yyval.type)->type = (yyvsp[(3) - (3)].type);
- (yyval.type)->chan = Csend;
- }
- break;
-
- case 329:
-#line 2049 "go.y"
- {
- (yyval.type) = typ(TCHAN);
- (yyval.type)->type = (yyvsp[(3) - (3)].type);
- (yyval.type)->chan = Crecv;
- }
- break;
-
- case 330:
-#line 2057 "go.y"
- {
- (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
- }
- break;
-
- case 331:
-#line 2063 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
- if((yyvsp[(1) - (3)].sym))
- (yyval.node)->left = newname((yyvsp[(1) - (3)].sym));
- (yyval.node)->val = (yyvsp[(3) - (3)].val);
- }
- break;
-
- case 332:
-#line 2070 "go.y"
- {
- Type *t;
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = (yyvsp[(3) - (4)].type);
-
- (yyval.node) = nod(ODCLFIELD, N, typenod(t));
- if((yyvsp[(1) - (4)].sym))
- (yyval.node)->left = newname((yyvsp[(1) - (4)].sym));
- (yyval.node)->isddd = 1;
- (yyval.node)->val = (yyvsp[(4) - (4)].val);
- }
- break;
-
- case 333:
-#line 2086 "go.y"
- {
- Sym *s;
- Pkg *p;
-
- if((yyvsp[(1) - (3)].sym) != S && strcmp((yyvsp[(1) - (3)].sym)->name, "?") != 0) {
- (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type)));
- (yyval.node)->val = (yyvsp[(3) - (3)].val);
- } else {
- s = (yyvsp[(2) - (3)].type)->sym;
- if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype])
- s = (yyvsp[(2) - (3)].type)->type->sym;
- p = importpkg;
- if((yyvsp[(1) - (3)].sym) != S)
- p = (yyvsp[(1) - (3)].sym)->pkg;
- (yyval.node) = embedded(s, p);
- (yyval.node)->right = typenod((yyvsp[(2) - (3)].type));
- (yyval.node)->val = (yyvsp[(3) - (3)].val);
- }
- }
- break;
-
- case 334:
-#line 2108 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
- }
- break;
-
- case 335:
-#line 2112 "go.y"
- {
- (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
- }
- break;
-
- case 336:
-#line 2117 "go.y"
- {
- (yyval.list) = nil;
- }
- break;
-
- case 338:
-#line 2124 "go.y"
- {
- (yyval.list) = (yyvsp[(2) - (3)].list);
- }
- break;
-
- case 339:
-#line 2128 "go.y"
- {
- (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
- }
- break;
-
- case 340:
-#line 2138 "go.y"
- {
- (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
- }
- break;
-
- case 341:
-#line 2142 "go.y"
- {
- (yyval.node) = nodlit((yyvsp[(2) - (2)].val));
- switch((yyval.node)->val.ctype){
- case CTINT:
- case CTRUNE:
- mpnegfix((yyval.node)->val.u.xval);
- break;
- case CTFLT:
- mpnegflt((yyval.node)->val.u.fval);
- break;
- case CTCPLX:
- mpnegflt(&(yyval.node)->val.u.cval->real);
- mpnegflt(&(yyval.node)->val.u.cval->imag);
- break;
- default:
- yyerror("bad negated constant");
- }
- }
- break;
-
- case 342:
-#line 2161 "go.y"
- {
- (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
- if((yyval.node)->op != OLITERAL)
- yyerror("bad constant %S", (yyval.node)->sym);
- }
- break;
-
- case 344:
-#line 2170 "go.y"
- {
- if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
- (yyval.node) = (yyvsp[(2) - (5)].node);
- mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0);
- break;
- }
- (yyvsp[(4) - (5)].node)->val.u.cval->real = (yyvsp[(4) - (5)].node)->val.u.cval->imag;
- mpmovecflt(&(yyvsp[(4) - (5)].node)->val.u.cval->imag, 0.0);
- (yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val);
- }
- break;
-
- case 347:
-#line 2186 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 348:
-#line 2190 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 349:
-#line 2196 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 350:
-#line 2200 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
- case 351:
-#line 2206 "go.y"
- {
- (yyval.list) = list1((yyvsp[(1) - (1)].node));
- }
- break;
-
- case 352:
-#line 2210 "go.y"
- {
- (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
- }
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 4909 "y.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-#line 2214 "go.y"
-
-
-static void
-fixlbrace(int lbr)
-{
- // If the opening brace was an LBODY,
- // set up for another one now that we're done.
- // See comment in lex.c about loophack.
- if(lbr == LBODY)
- loophack = 1;
-}
-
-
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
deleted file mode 100644
index d01fbe1987..0000000000
--- a/src/cmd/gc/y.tab.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- LLITERAL = 258,
- LASOP = 259,
- LCOLAS = 260,
- LBREAK = 261,
- LCASE = 262,
- LCHAN = 263,
- LCONST = 264,
- LCONTINUE = 265,
- LDDD = 266,
- LDEFAULT = 267,
- LDEFER = 268,
- LELSE = 269,
- LFALL = 270,
- LFOR = 271,
- LFUNC = 272,
- LGO = 273,
- LGOTO = 274,
- LIF = 275,
- LIMPORT = 276,
- LINTERFACE = 277,
- LMAP = 278,
- LNAME = 279,
- LPACKAGE = 280,
- LRANGE = 281,
- LRETURN = 282,
- LSELECT = 283,
- LSTRUCT = 284,
- LSWITCH = 285,
- LTYPE = 286,
- LVAR = 287,
- LANDAND = 288,
- LANDNOT = 289,
- LBODY = 290,
- LCOMM = 291,
- LDEC = 292,
- LEQ = 293,
- LGE = 294,
- LGT = 295,
- LIGNORE = 296,
- LINC = 297,
- LLE = 298,
- LLSH = 299,
- LLT = 300,
- LNE = 301,
- LOROR = 302,
- LRSH = 303,
- NotPackage = 304,
- NotParen = 305,
- PreferToRightParen = 306
- };
-#endif
-/* Tokens. */
-#define LLITERAL 258
-#define LASOP 259
-#define LCOLAS 260
-#define LBREAK 261
-#define LCASE 262
-#define LCHAN 263
-#define LCONST 264
-#define LCONTINUE 265
-#define LDDD 266
-#define LDEFAULT 267
-#define LDEFER 268
-#define LELSE 269
-#define LFALL 270
-#define LFOR 271
-#define LFUNC 272
-#define LGO 273
-#define LGOTO 274
-#define LIF 275
-#define LIMPORT 276
-#define LINTERFACE 277
-#define LMAP 278
-#define LNAME 279
-#define LPACKAGE 280
-#define LRANGE 281
-#define LRETURN 282
-#define LSELECT 283
-#define LSTRUCT 284
-#define LSWITCH 285
-#define LTYPE 286
-#define LVAR 287
-#define LANDAND 288
-#define LANDNOT 289
-#define LBODY 290
-#define LCOMM 291
-#define LDEC 292
-#define LEQ 293
-#define LGE 294
-#define LGT 295
-#define LIGNORE 296
-#define LINC 297
-#define LLE 298
-#define LLSH 299
-#define LLT 300
-#define LNE 301
-#define LOROR 302
-#define LRSH 303
-#define NotPackage 304
-#define NotParen 305
-#define PreferToRightParen 306
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 28 "go.y"
-{
- Node* node;
- NodeList* list;
- Type* type;
- Sym* sym;
- struct Val val;
- int i;
-}
-/* Line 1529 of yacc.c. */
-#line 160 "y.tab.h"
- YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h
deleted file mode 100644
index d0dd639ff3..0000000000
--- a/src/cmd/gc/yerr.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
- int yystate;
- int yychar;
- char *msg;
-} yymsg[] = {
- // Each line of the form % token list
- // is converted by bisonerrors into the yystate and yychar caused
- // by that token list.
-
- {222, ',',
- "unexpected comma during import block"},
-
- {32, ';',
- "missing import path; require quoted string"},
-
- {380, ';',
- "missing { after if clause"},
-
- {401, ';',
- "missing { after switch clause"},
-
- {239, ';',
- "missing { after for clause"},
-
- {478, LBODY,
- "missing { after for clause"},
-
- {22, '{',
- "unexpected semicolon or newline before {"},
-
- {145, ';',
- "unexpected semicolon or newline in type declaration"},
-
- {37, '}',
- "unexpected } in channel type"},
-
- {37, ')',
- "unexpected ) in channel type"},
-
- {37, ',',
- "unexpected comma in channel type"},
-
- {441, LELSE,
- "unexpected semicolon or newline before else"},
-
- {259, ',',
- "name list not allowed in interface type"},
-
- {239, LVAR,
- "var declaration not allowed in for initializer"},
-
- {65, '{',
- "unexpected { at end of statement"},
-
- {379, '{',
- "unexpected { at end of statement"},
-
- {126, ';',
- "argument to go/defer must be function call"},
-
- {428, ';',
- "need trailing comma before newline in composite literal"},
-
- {439, ';',
- "need trailing comma before newline in composite literal"},
-
- {113, LNAME,
- "nested func not allowed"},
-
- {647, ';',
- "else must be followed by if or statement block"}
-};
diff --git a/src/cmd/new5a/a.y b/src/cmd/new5a/a.y
deleted file mode 100644
index 39fab8fa26..0000000000
--- a/src/cmd/new5a/a.y
+++ /dev/null
@@ -1,795 +0,0 @@
-// Inferno utils/5a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
-//
-// 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.
-
-%{
-package main
-
-import (
- "cmd/internal/asm"
- "cmd/internal/obj"
- . "cmd/internal/obj/arm"
-)
-%}
-
-%union {
- sym *asm.Sym
- lval int32
- dval float64
- sval string
- addr obj.Addr
-}
-
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
-%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
-%token <lval> LTYPEB LTYPEC LTYPED LTYPEE
-%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
-%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
-%token <lval> LCONST LSP LSB LFP LPC
-%token <lval> LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
-%token <lval> LCOND LS LAT LGLOBL
-%token <dval> LFCONST
-%token <sval> LSCONST
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr oexpr pointer offset sreg spreg creg
-%type <lval> rcon cond reglist
-%type <addr> gen rel reg regreg freg shift fcon frcon textsize
-%type <addr> imm ximm name oreg ireg nireg ioreg imsr
-%%
-prog:
-| prog
- {
- stmtline = asm.Lineno;
- }
- line
-
-line:
- LNAME ':'
- {
- $1 = asm.LabelLookup($1);
- if $1.Type == LLAB && $1.Value != int64(asm.PC) {
- yyerror("redeclaration of %s", $1.Labelname)
- }
- $1.Type = LLAB;
- $1.Value = int64(asm.PC)
- }
- line
-| LNAME '=' expr ';'
- {
- $1.Type = LVAR;
- $1.Value = int64($3);
- }
-| LVAR '=' expr ';'
- {
- if $1.Value != int64($3) {
- yyerror("redeclaration of %s", $1.Name)
- }
- $1.Value = int64($3);
- }
-| ';'
-| inst ';'
-| error ';'
-
-inst:
-/*
- * ADD
- */
- LTYPE1 cond imsr ',' spreg ',' reg
- {
- outcode($1, $2, &$3, $5, &$7);
- }
-| LTYPE1 cond imsr ',' spreg ','
- {
- outcode($1, $2, &$3, $5, &nullgen);
- }
-| LTYPE1 cond imsr ',' reg
- {
- outcode($1, $2, &$3, 0, &$5);
- }
-/*
- * MVN
- */
-| LTYPE2 cond imsr ',' reg
- {
- outcode($1, $2, &$3, 0, &$5);
- }
-/*
- * MOVW
- */
-| LTYPE3 cond gen ',' gen
- {
- outcode($1, $2, &$3, 0, &$5);
- }
-/*
- * B/BL
- */
-| LTYPE4 cond comma rel
- {
- outcode($1, $2, &nullgen, 0, &$4);
- }
-| LTYPE4 cond comma nireg
- {
- outcode($1, $2, &nullgen, 0, &$4);
- }
-/*
- * BX
- */
-| LTYPEBX comma ireg
- {
- outcode($1, Always, &nullgen, 0, &$3);
- }
-/*
- * BEQ
- */
-| LTYPE5 comma rel
- {
- outcode($1, Always, &nullgen, 0, &$3);
- }
-/*
- * SWI
- */
-| LTYPE6 cond comma gen
- {
- outcode($1, $2, &nullgen, 0, &$4);
- }
-/*
- * CMP
- */
-| LTYPE7 cond imsr ',' spreg comma
- {
- outcode($1, $2, &$3, $5, &nullgen);
- }
-/*
- * MOVM
- */
-| LTYPE8 cond ioreg ',' '[' reglist ']'
- {
- var g obj.Addr
-
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = int64($6);
- outcode($1, $2, &$3, 0, &g);
- }
-| LTYPE8 cond '[' reglist ']' ',' ioreg
- {
- var g obj.Addr
-
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = int64($4);
- outcode($1, $2, &g, 0, &$7);
- }
-/*
- * SWAP
- */
-| LTYPE9 cond reg ',' ireg ',' reg
- {
- outcode($1, $2, &$5, int32($3.Reg), &$7);
- }
-| LTYPE9 cond reg ',' ireg comma
- {
- outcode($1, $2, &$5, int32($3.Reg), &$3);
- }
-| LTYPE9 cond comma ireg ',' reg
- {
- outcode($1, $2, &$4, int32($6.Reg), &$6);
- }
-/*
- * RET
- */
-| LTYPEA cond comma
- {
- outcode($1, $2, &nullgen, 0, &nullgen);
- }
-/*
- * TEXT
- */
-| LTYPEB name ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode($1, Always, &$2, 0, &$5);
- }
-| LTYPEB name ',' con ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode($1, Always, &$2, 0, &$7);
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST;
- lastpc.From3.Offset = int64($4)
- }
- }
-/*
- * GLOBL
- */
-| LGLOBL name ',' imm
- {
- asm.Settext($2.Sym)
- outcode($1, Always, &$2, 0, &$4)
- }
-| LGLOBL name ',' con ',' imm
- {
- asm.Settext($2.Sym)
- outcode($1, Always, &$2, 0, &$6)
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = int64($4)
- }
- }
-
-/*
- * DATA
- */
-| LTYPEC name '/' con ',' ximm
- {
- outcode($1, Always, &$2, 0, &$6)
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = int64($4)
- }
- }
-/*
- * CASE
- */
-| LTYPED cond reg comma
- {
- outcode($1, $2, &$3, 0, &nullgen);
- }
-/*
- * word
- */
-| LTYPEH comma ximm
- {
- outcode($1, Always, &nullgen, 0, &$3);
- }
-/*
- * floating-point coprocessor
- */
-| LTYPEI cond freg ',' freg
- {
- outcode($1, $2, &$3, 0, &$5);
- }
-| LTYPEK cond frcon ',' freg
- {
- outcode($1, $2, &$3, 0, &$5);
- }
-| LTYPEK cond frcon ',' LFREG ',' freg
- {
- outcode($1, $2, &$3, $5, &$7);
- }
-| LTYPEL cond freg ',' freg comma
- {
- outcode($1, $2, &$3, int32($5.Reg), &nullgen);
- }
-/*
- * MCR MRC
- */
-| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
- {
- var g obj.Addr
-
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = int64(
- (0xe << 24) | /* opcode */
- ($1 << 20) | /* MCR/MRC */
- (($2^C_SCOND_XOR) << 28) | /* scond */
- (($3 & 15) << 8) | /* coprocessor number */
- (($5 & 7) << 21) | /* coprocessor operation */
- (($7 & 15) << 12) | /* arm register */
- (($9 & 15) << 16) | /* Crn */
- (($11 & 15) << 0) | /* Crm */
- (($12 & 7) << 5) | /* coprocessor information */
- (1<<4)); /* must be set */
- outcode(AMRC, Always, &nullgen, 0, &g);
- }
-/*
- * MULL r1,r2,(hi,lo)
- */
-| LTYPEM cond reg ',' reg ',' regreg
- {
- outcode($1, $2, &$3, int32($5.Reg), &$7);
- }
-/*
- * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4
- * MULAW{T,B} r1,r2,r3,r4
- */
-| LTYPEN cond reg ',' reg ',' reg ',' spreg
- {
- $7.Type = obj.TYPE_REGREG2;
- $7.Offset = int64($9);
- outcode($1, $2, &$3, int32($5.Reg), &$7);
- }
-/*
- * PLD
- */
-| LTYPEPLD oreg
- {
- outcode($1, Always, &$2, 0, &nullgen);
- }
-/*
- * PCDATA
- */
-| LTYPEPC gen ',' gen
- {
- if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST {
- yyerror("arguments to PCDATA must be integer constants")
- }
- outcode($1, Always, &$2, 0, &$4);
- }
-/*
- * FUNCDATA
- */
-| LTYPEF gen ',' gen
- {
- if $2.Type != obj.TYPE_CONST {
- yyerror("index for FUNCDATA must be integer constant")
- }
- if $4.Type != obj.NAME_EXTERN && $4.Type != obj.NAME_STATIC && $4.Type != obj.TYPE_MEM {
- yyerror("value for FUNCDATA must be symbol reference")
- }
- outcode($1, Always, &$2, 0, &$4);
- }
-/*
- * END
- */
-| LTYPEE comma
- {
- outcode($1, Always, &nullgen, 0, &nullgen);
- }
-
-textsize:
- LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = int64($1)
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -int64($2)
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = int64($1)
- $$.U.Argsize = int32($3);
- }
-| '-' LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -int64($2)
- $$.U.Argsize = int32($4);
- }
-
-cond:
- {
- $$ = Always;
- }
-| cond LCOND
- {
- $$ = ($1 & ^ C_SCOND) | $2;
- }
-| cond LS
- {
- $$ = $1 | $2;
- }
-
-comma:
-| ',' comma
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = int64($1) + int64(asm.PC);
- }
-| LNAME offset
- {
- $1 = asm.LabelLookup($1);
- $$ = nullgen;
- if asm.Pass == 2 && $1.Type != LLAB {
- yyerror("undefined label: %s", $1.Labelname)
- }
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1.Value + int64($2);
- }
-
-ximm: '$' con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- $$.Offset = int64($2);
- }
-| '$' oreg
- {
- $$ = $2;
- $$.Type = obj.TYPE_ADDR;
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SCONST;
- $$.U.Sval = $2
- }
-| fcon
-
-fcon:
- '$' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $2;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$3;
- }
-
-reglist:
- spreg
- {
- $$ = 1 << uint($1&15);
- }
-| spreg '-' spreg
- {
- $$=0;
- for i:=$1; i<=$3; i++ {
- $$ |= 1<<uint(i&15)
- }
- for i:=$3; i<=$1; i++ {
- $$ |= 1<<uint(i&15)
- }
- }
-| spreg comma reglist
- {
- $$ = (1<<uint($1&15)) | $3;
- }
-
-gen:
- reg
-| ximm
-| shift
-| shift '(' spreg ')'
- {
- $$ = $1;
- $$.Reg = int16($3);
- }
-| LPSR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LFCR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Offset = int64($1);
- }
-| oreg
-| freg
-
-nireg:
- ireg
-| name
- {
- $$ = $1;
- if($1.Name != obj.NAME_EXTERN && $1.Name != obj.NAME_STATIC) {
- }
- }
-
-ireg:
- '(' spreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($2);
- $$.Offset = 0;
- }
-
-ioreg:
- ireg
-| con '(' sreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($3);
- $$.Offset = int64($1);
- }
-
-oreg:
- name
-| name '(' sreg ')'
- {
- $$ = $1;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($3);
- }
-| ioreg
-
-imsr:
- reg
-| imm
-| shift
-
-imm: '$' con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- $$.Offset = int64($2);
- }
-
-reg:
- spreg
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-regreg:
- '(' spreg ',' spreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REGREG;
- $$.Reg = int16($2);
- $$.Offset = int64($4);
- }
-
-shift:
- spreg '<' '<' rcon
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SHIFT;
- $$.Offset = int64($1&15) | int64($4) | (0 << 5);
- }
-| spreg '>' '>' rcon
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SHIFT;
- $$.Offset = int64($1&15) | int64($4) | (1 << 5);
- }
-| spreg '-' '>' rcon
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SHIFT;
- $$.Offset = int64($1&15) | int64($4) | (2 << 5);
- }
-| spreg LAT '>' rcon
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SHIFT;
- $$.Offset = int64($1&15) | int64($4) | (3 << 5);
- }
-
-rcon:
- spreg
- {
- if $$ < REG_R0 || $$ > REG_R15 {
- print("register value out of range\n")
- }
- $$ = (($1&15) << 8) | (1 << 4);
- }
-| con
- {
- if $$ < 0 || $$ >= 32 {
- print("shift value out of range\n")
- }
- $$ = ($1&31) << 7;
- }
-
-sreg:
- LREG
-| LPC
- {
- $$ = REGPC;
- }
-| LR '(' expr ')'
- {
- if $3 < 0 || $3 >= NREG {
- print("register value out of range\n")
- }
- $$ = REG_R0 + $3;
- }
-
-spreg:
- sreg
-| LSP
- {
- $$ = REGSP;
- }
-
-creg:
- LCREG
-| LC '(' expr ')'
- {
- if $3 < 0 || $3 >= NREG {
- print("register value out of range\n")
- }
- $$ = $3; // TODO(rsc): REG_C0+$3
- }
-
-frcon:
- freg
-| fcon
-
-freg:
- LFREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-| LF '(' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16(REG_F0 + $3);
- }
-
-name:
- con '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = int8($3);
- $$.Sym = nil;
- $$.Offset = int64($1);
- }
-| LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = int8($4);
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
- $$.Offset = int64($2);
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = obj.NAME_STATIC;
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
- $$.Offset = int64($4);
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = int32($1.Value);
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ^$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-oexpr:
- {
- $$ = 0;
- }
-| ',' expr
- {
- $$ = $2;
- }
-
-expr:
- con
-| expr '+' expr
- {
- $$ = $1 + $3;
- }
-| expr '-' expr
- {
- $$ = $1 - $3;
- }
-| expr '*' expr
- {
- $$ = $1 * $3;
- }
-| expr '/' expr
- {
- $$ = $1 / $3;
- }
-| expr '%' expr
- {
- $$ = $1 % $3;
- }
-| expr '<' '<' expr
- {
- $$ = $1 << uint($4);
- }
-| expr '>' '>' expr
- {
- $$ = $1 >> uint($4);
- }
-| expr '&' expr
- {
- $$ = $1 & $3;
- }
-| expr '^' expr
- {
- $$ = $1 ^ $3;
- }
-| expr '|' expr
- {
- $$ = $1 | $3;
- }
diff --git a/src/cmd/new6a/a.y b/src/cmd/new6a/a.y
deleted file mode 100644
index bd59a1faba..0000000000
--- a/src/cmd/new6a/a.y
+++ /dev/null
@@ -1,723 +0,0 @@
-// Inferno utils/6a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
-//
-// 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.
-
-%{
-package main
-
-import (
- "cmd/internal/asm"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
-)
-%}
-
-%union {
- sym *asm.Sym
- lval int64
- dval float64
- sval string
- addr obj.Addr
- addr2 Addr2
-}
-
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG LTYPEPC
-%token <lval> LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT LTYPEF
-%token <lval> LCONST LFP LPC LSB
-%token <lval> LBREG LLREG LSREG LFREG LMREG LXREG
-%token <dval> LFCONST
-%token <sval> LSCONST LSP
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr pointer offset
-%type <addr> mem imm textsize reg nam rel rem rim rom omem nmem
-%type <addr2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <addr2> spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%type <addr2> spec10 spec12 spec13
-%%
-prog:
-| prog
- {
- stmtline = asm.Lineno;
- }
- line
-
-line:
- LNAME ':'
- {
- $1 = asm.LabelLookup($1);
- if $1.Type == LLAB && $1.Value != int64(asm.PC) {
- yyerror("redeclaration of %s (%s)", $1.Labelname, $1.Name);
- }
- $1.Type = LLAB;
- $1.Value = int64(asm.PC)
- }
- line
-| ';'
-| inst ';'
-| error ';'
-
-inst:
- LNAME '=' expr
- {
- $1.Type = LVAR;
- $1.Value = $3;
- }
-| LVAR '=' expr
- {
- if $1.Value != $3 {
- yyerror("redeclaration of %s", $1.Name);
- }
- $1.Value = $3;
- }
-| LTYPE0 nonnon { outcode(int($1), &$2); }
-| LTYPE1 nonrem { outcode(int($1), &$2); }
-| LTYPE2 rimnon { outcode(int($1), &$2); }
-| LTYPE3 rimrem { outcode(int($1), &$2); }
-| LTYPE4 remrim { outcode(int($1), &$2); }
-| LTYPER nonrel { outcode(int($1), &$2); }
-| spec1
-| spec2
-| LTYPEC spec3 { outcode(int($1), &$2); }
-| LTYPEN spec4 { outcode(int($1), &$2); }
-| LTYPES spec5 { outcode(int($1), &$2); }
-| LTYPEM spec6 { outcode(int($1), &$2); }
-| LTYPEI spec7 { outcode(int($1), &$2); }
-| LTYPEXC spec8 { outcode(int($1), &$2); }
-| LTYPEX spec9 { outcode(int($1), &$2); }
-| LTYPERT spec10 { outcode(int($1), &$2); }
-| spec11
-| LTYPEPC spec12 { outcode(int($1), &$2); }
-| LTYPEF spec13 { outcode(int($1), &$2); }
-
-nonnon:
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| ','
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-
-rimrem:
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-remrim:
- rem ',' rim
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-rimnon:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-nonrem:
- ',' rem
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rem
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-nonrel:
- ',' rel
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rel
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-| imm ',' rel
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec1: /* DATA */
- LTYPED nam '/' con ',' imm
- {
- var a Addr2
- a.from = $2
- a.to = $6
- outcode(obj.ADATA, &a)
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-spec2: /* TEXT */
- LTYPET mem ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(obj.ATEXT, &Addr2{$2, $5})
- }
-| LTYPET mem ',' con ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(obj.ATEXT, &Addr2{$2, $7})
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-spec11: /* GLOBL */
- LTYPEG mem ',' imm
- {
- asm.Settext($2.Sym)
- outcode(obj.AGLOBL, &Addr2{$2, $4})
- }
-| LTYPEG mem ',' con ',' imm
- {
- asm.Settext($2.Sym)
- outcode(obj.AGLOBL, &Addr2{$2, $6})
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-spec3: /* JMP/CALL */
- ',' rom
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rom
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-spec4: /* NOP */
- nonnon
-| nonrem
-
-spec5: /* SHL/SHR */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LLREG
- {
- $$.from = $1;
- $$.to = $3;
- if $$.from.Index != obj.TYPE_NONE {
- yyerror("dp shift with lhs index");
- }
- $$.from.Index = int16($5);
- }
-
-spec6: /* MOVW/MOVL */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LSREG
- {
- $$.from = $1;
- $$.to = $3;
- if $$.to.Index != obj.TYPE_NONE {
- yyerror("dp move with lhs index");
- }
- $$.to.Index = int16($5);
- }
-
-spec7:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec8: /* CMPPS/CMPPD */
- reg ',' rem ',' con
- {
- $$.from = $1;
- $$.to = $3;
- $$.to.Offset = $5;
- }
-
-spec9: /* shufl */
- imm ',' rem ',' reg
- {
- $$.from = $3;
- $$.to = $5;
- if $1.Type != obj.TYPE_CONST {
- yyerror("illegal constant");
- }
- $$.to.Offset = $1.Offset;
- }
-
-spec10: /* RET/RETF */
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| imm
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-spec12: /* asm.PCDATA */
- rim ',' rim
- {
- if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST {
- yyerror("arguments to asm.PCDATA must be integer constants");
- }
- $$.from = $1;
- $$.to = $3;
- }
-
-spec13: /* FUNCDATA */
- rim ',' rim
- {
- if $1.Type != obj.TYPE_CONST {
- yyerror("index for FUNCDATA must be integer constant");
- }
- if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) {
- yyerror("value for FUNCDATA must be symbol reference");
- }
- $$.from = $1;
- $$.to = $3;
- }
-
-rem:
- reg
-| mem
-
-rom:
- rel
-| nmem
-| '*' reg
- {
- $$ = $2;
- }
-| '*' omem
- {
- $$ = $2;
- }
-| reg
-| omem
-
-rim:
- rem
-| imm
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1 + int64(asm.PC);
- }
-| LNAME offset
- {
- $1 = asm.LabelLookup($1);
- $$ = nullgen;
- if asm.Pass == 2 && $1.Type != LLAB {
- yyerror("undefined label: %s", $1.Labelname);
- }
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1.Value + $2;
- }
-
-reg:
- LBREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LFREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LLREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LMREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LSP
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = x86.REG_SP;
- }
-| LSREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LXREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-
-imm:
- '$' con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- $$.Offset = $2;
- }
-| '$' nam
- {
- $$ = $2;
- $$.Type = obj.TYPE_ADDR;
- /*
- if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.sym.Name);
- */
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SCONST;
- $$.U.Sval = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
- }
-| '$' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $2;
- }
-| '$' '(' LFCONST ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $3;
- }
-| '$' '(' '-' LFCONST ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$4;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$3;
- }
-
-mem:
- omem
-| nmem
-
-omem:
- con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Offset = $1;
- }
-| con '(' LLREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- }
-| con '(' LSP ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = x86.REG_SP
- $$.Offset = $1;
- }
-| con '(' LSREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- }
-| con '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Offset = $1;
- $$.Index = int16($3);
- $$.Scale = int8($5);
- checkscale($$.Scale);
- }
-| con '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- $$.Index = int16($6);
- $$.Scale = int8($8);
- checkscale($$.Scale);
- }
-| con '(' LLREG ')' '(' LSREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- $$.Index = int16($6);
- $$.Scale = int8($8);
- checkscale($$.Scale);
- }
-| '(' LLREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($2)
- }
-| '(' LSP ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = x86.REG_SP
- }
-| '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Index = int16($2);
- $$.Scale = int8($4);
- checkscale($$.Scale);
- }
-| '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($2)
- $$.Index = int16($5);
- $$.Scale = int8($7);
- checkscale($$.Scale);
- }
-
-nmem:
- nam
- {
- $$ = $1;
- }
-| nam '(' LLREG '*' con ')'
- {
- $$ = $1;
- $$.Index = int16($3);
- $$.Scale = int8($5);
- checkscale($$.Scale);
- }
-
-nam:
- LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Name = int8($4)
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
- $$.Offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Name = obj.NAME_STATIC
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
- $$.Offset = $4;
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
- {
- $$ = obj.NAME_AUTO;
- }
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = $1.Value;
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ^$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-textsize:
- LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = $1;
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -$2;
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = $1;
- $$.U.Argsize = int32($3);
- }
-| '-' LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -$2;
- $$.U.Argsize = int32($4);
- }
-
-expr:
- con
-| expr '+' expr
- {
- $$ = $1 + $3;
- }
-| expr '-' expr
- {
- $$ = $1 - $3;
- }
-| expr '*' expr
- {
- $$ = $1 * $3;
- }
-| expr '/' expr
- {
- $$ = $1 / $3;
- }
-| expr '%' expr
- {
- $$ = $1 % $3;
- }
-| expr '<' '<' expr
- {
- $$ = $1 << uint($4);
- }
-| expr '>' '>' expr
- {
- $$ = $1 >> uint($4);
- }
-| expr '&' expr
- {
- $$ = $1 & $3;
- }
-| expr '^' expr
- {
- $$ = $1 ^ $3;
- }
-| expr '|' expr
- {
- $$ = $1 | $3;
- }
diff --git a/src/cmd/new8a/a.y b/src/cmd/new8a/a.y
deleted file mode 100644
index 906ad331df..0000000000
--- a/src/cmd/new8a/a.y
+++ /dev/null
@@ -1,713 +0,0 @@
-// Inferno utils/8a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
-//
-// 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.
-
-%{
-package main
-
-import (
- "cmd/internal/asm"
- "cmd/internal/obj"
- . "cmd/internal/obj/i386"
-)
-%}
-
-%union {
- sym *asm.Sym
- lval int64
- con2 struct {
- v1 int32
- v2 int32
- }
- dval float64
- sval string
- addr obj.Addr
- addr2 Addr2
-}
-
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC
-%token <lval> LTYPEX LTYPEPC LTYPEF LCONST LFP LPC LSB
-%token <lval> LBREG LLREG LSREG LFREG LXREG
-%token <dval> LFCONST
-%token <sval> LSCONST LSP
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr pointer offset
-%type <addr> mem imm reg nam rel rem rim rom omem nmem textsize
-%type <addr2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <addr2> spec3 spec4 spec5 spec6 spec7 spec9 spec10 spec11 spec12
-%%
-prog:
-| prog
- {
- stmtline = asm.Lineno;
- }
- line
-
-line:
- LNAME ':'
- {
- $1 = asm.LabelLookup($1);
- if $1.Type == LLAB && $1.Value != int64(asm.PC) {
- yyerror("redeclaration of %s", $1.Labelname)
- }
- $1.Type = LLAB;
- $1.Value = int64(asm.PC)
- }
- line
-| ';'
-| inst ';'
-| error ';'
-
-inst:
- LNAME '=' expr
- {
- $1.Type = LVAR;
- $1.Value = $3;
- }
-| LVAR '=' expr
- {
- if $1.Value != int64($3) {
- yyerror("redeclaration of %s", $1.Name);
- }
- $1.Value = $3;
- }
-| LTYPE0 nonnon { outcode(int($1), &$2); }
-| LTYPE1 nonrem { outcode(int($1), &$2); }
-| LTYPE2 rimnon { outcode(int($1), &$2); }
-| LTYPE3 rimrem { outcode(int($1), &$2); }
-| LTYPE4 remrim { outcode(int($1), &$2); }
-| LTYPER nonrel { outcode(int($1), &$2); }
-| spec1
-| spec2
-| LTYPEC spec3 { outcode(int($1), &$2); }
-| LTYPEN spec4 { outcode(int($1), &$2); }
-| LTYPES spec5 { outcode(int($1), &$2); }
-| LTYPEM spec6 { outcode(int($1), &$2); }
-| LTYPEI spec7 { outcode(int($1), &$2); }
-| spec8
-| LTYPEXC spec9 { outcode(int($1), &$2); }
-| LTYPEX spec10 { outcode(int($1), &$2); }
-| LTYPEPC spec11 { outcode(int($1), &$2); }
-| LTYPEF spec12 { outcode(int($1), &$2); }
-
-nonnon:
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-| ','
- {
- $$.from = nullgen;
- $$.to = nullgen;
- }
-
-rimrem:
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-remrim:
- rem ',' rim
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-rimnon:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-
-nonrem:
- ',' rem
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rem
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-
-nonrel:
- ',' rel
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rel
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-| imm ',' rel
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec1: /* DATA */
- LTYPED nam '/' con ',' imm
- {
- outcode(obj.ADATA, &Addr2{$2, $6})
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-spec2: /* TEXT */
- LTYPET mem ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(obj.ATEXT, &Addr2{$2, $5})
- }
-| LTYPET mem ',' con ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(obj.ATEXT, &Addr2{$2, $7})
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-spec8: /* GLOBL */
- LTYPEG mem ',' imm
- {
- asm.Settext($2.Sym);
- outcode(obj.AGLOBL, &Addr2{$2, $4})
- }
-| LTYPEG mem ',' con ',' imm
- {
- asm.Settext($2.Sym);
- outcode(obj.AGLOBL, &Addr2{$2, $6})
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-
-spec3: /* JMP/CALL */
- ',' rom
- {
- $$.from = nullgen;
- $$.to = $2;
- }
-| rom
- {
- $$.from = nullgen;
- $$.to = $1;
- }
-| '*' nam
- {
- $$.from = nullgen;
- $$.to = $2;
- $$.to.Type = obj.TYPE_INDIR
- }
-
-spec4: /* NOP */
- nonnon
-| nonrem
-
-spec5: /* SHL/SHR */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LLREG
- {
- $$.from = $1;
- $$.to = $3;
- if $$.from.Index != obj.TYPE_NONE {
- yyerror("dp shift with lhs index");
- }
- $$.from.Index = int16($5);
- }
-
-spec6: /* MOVW/MOVL */
- rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-| rim ',' rem ':' LSREG
- {
- $$.from = $1;
- $$.to = $3;
- if $$.to.Index != obj.TYPE_NONE {
- yyerror("dp move with lhs index");
- }
- $$.to.Index = int16($5);
- }
-
-spec7:
- rim ','
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim
- {
- $$.from = $1;
- $$.to = nullgen;
- }
-| rim ',' rem
- {
- $$.from = $1;
- $$.to = $3;
- }
-
-spec9: /* CMPPS/CMPPD */
- reg ',' rem ',' con
- {
- $$.from = $1;
- $$.to = $3;
- $$.to.Offset = $5;
- }
-
-spec10: /* PINSRD */
- imm ',' rem ',' reg
- {
- $$.from = $3;
- $$.to = $5;
- if $1.Type != obj.TYPE_CONST {
- yyerror("illegal constant")
- }
- $$.to.Offset = $1.Offset;
- }
-
-spec11: /* PCDATA */
- rim ',' rim
- {
- if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST {
- yyerror("arguments to PCDATA must be integer constants");
- }
- $$.from = $1;
- $$.to = $3;
- }
-
-spec12: /* FUNCDATA */
- rim ',' rim
- {
- if $1.Type != obj.TYPE_CONST {
- yyerror("index for FUNCDATA must be integer constant");
- }
- if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) {
- yyerror("value for FUNCDATA must be symbol reference");
- }
- $$.from = $1;
- $$.to = $3;
- }
-
-rem:
- reg
-| mem
-
-rom:
- rel
-| nmem
-| '*' reg
- {
- $$ = $2;
- }
-| '*' omem
- {
- $$ = $2;
- }
-| reg
-| omem
-| imm
-
-rim:
- rem
-| imm
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1 + int64(asm.PC);
- }
-| LNAME offset
- {
- $1 = asm.LabelLookup($1);
- $$ = nullgen;
- if asm.Pass == 2 && $1.Type != LLAB {
- yyerror("undefined label: %s", $1.Labelname);
- }
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1.Value + $2;
- }
-
-reg:
- LBREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LFREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LLREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LXREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-| LSP
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = REG_SP;
- }
-| LSREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1);
- }
-
-imm:
- '$' con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- $$.Offset = $2;
- }
-| '$' nam
- {
- $$ = $2;
- $$.Type = obj.TYPE_ADDR
- /*
- if($2.Type == D_AUTO || $2.Type == D_PARAM)
- yyerror("constant cannot be automatic: %s",
- $2.Sym.name);
- */
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SCONST;
- $$.U.Sval = $2
- }
-| '$' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $2;
- }
-| '$' '(' LFCONST ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $3;
- }
-| '$' '(' '-' LFCONST ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$4;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$3;
- }
-
-textsize:
- LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = $1;
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -$2;
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = $1;
- $$.U.Argsize = int32($3);
- }
-| '-' LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -$2;
- $$.U.Argsize = int32($4);
- }
-
-
-mem:
- omem
-| nmem
-
-omem:
- con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Offset = $1;
- }
-| con '(' LLREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- }
-| con '(' LSP ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = REG_SP
- $$.Offset = $1;
- }
-| con '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Offset = $1;
- $$.Index = int16($3);
- $$.Scale = int8($5);
- checkscale($$.Scale);
- }
-| con '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- $$.Index = int16($6);
- $$.Scale = int8($8);
- checkscale($$.Scale);
- }
-| con '(' LLREG ')' '(' LSREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- $$.Index = int16($6);
- $$.Scale = int8($8);
- checkscale($$.Scale);
- }
-| '(' LLREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($2);
- }
-| '(' LSP ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = REG_SP
- }
-| con '(' LSREG ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($3)
- $$.Offset = $1;
- }
-| '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Index = int16($2);
- $$.Scale = int8($4);
- checkscale($$.Scale);
- }
-| '(' LLREG ')' '(' LLREG '*' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Reg = int16($2)
- $$.Index = int16($5);
- $$.Scale = int8($7);
- checkscale($$.Scale);
- }
-
-nmem:
- nam
- {
- $$ = $1;
- }
-| nam '(' LLREG '*' con ')'
- {
- $$ = $1;
- $$.Index = int16($3);
- $$.Scale = int8($5);
- checkscale($$.Scale);
- }
-
-nam:
- LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Name = int8($4);
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
- $$.Offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM
- $$.Name = obj.NAME_STATIC
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
- $$.Offset = $4;
- }
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
- {
- $$ = obj.NAME_AUTO;
- }
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = $1.Value;
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ^$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-expr:
- con
-| expr '+' expr
- {
- $$ = $1 + $3;
- }
-| expr '-' expr
- {
- $$ = $1 - $3;
- }
-| expr '*' expr
- {
- $$ = $1 * $3;
- }
-| expr '/' expr
- {
- $$ = $1 / $3;
- }
-| expr '%' expr
- {
- $$ = $1 % $3;
- }
-| expr '<' '<' expr
- {
- $$ = $1 << uint($4);
- }
-| expr '>' '>' expr
- {
- $$ = $1 >> uint($4);
- }
-| expr '&' expr
- {
- $$ = $1 & $3;
- }
-| expr '^' expr
- {
- $$ = $1 ^ $3;
- }
-| expr '|' expr
- {
- $$ = $1 | $3;
- }
diff --git a/src/cmd/new9a/a.y b/src/cmd/new9a/a.y
deleted file mode 100644
index db733c5987..0000000000
--- a/src/cmd/new9a/a.y
+++ /dev/null
@@ -1,1055 +0,0 @@
-// cmd/9a/a.y 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.
-
-%{
-package main
-
-import (
- "cmd/internal/asm"
- "cmd/internal/obj"
- . "cmd/internal/obj/ppc64"
-)
-%}
-
-%union
-{
- sym *asm.Sym
- lval int64
- dval float64
- sval string
- addr obj.Addr
-}
-
-%left '|'
-%left '^'
-%left '&'
-%left '<' '>'
-%left '+' '-'
-%left '*' '/' '%'
-%token <lval> LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
-%token <lval> LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
-%token <lval> LNOP LEND LRETT LWORD LTEXT LDATA LGLOBL LRETRN
-%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH
-%token <lval> LREG LFREG LR LCR LF LFPSCR
-%token <lval> LLR LCTR LSPR LSPREG LSEG LMSR
-%token <lval> LPCDAT LFUNCDAT LSCHED LXLD LXST LXOP LXMV
-%token <lval> LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA
-%token <dval> LFCONST
-%token <sval> LSCONST
-%token <sym> LNAME LLAB LVAR
-%type <lval> con expr pointer offset sreg
-%type <addr> addr rreg regaddr name creg freg xlreg lr ctr textsize
-%type <addr> imm ximm fimm rel psr lcr cbit fpscr msr mask
-%%
-prog:
-| prog
- {
- stmtline = asm.Lineno
- }
- line
-
-line:
- LNAME ':'
- {
- $1 = asm.LabelLookup($1);
- if $1.Type == LLAB && $1.Value != int64(asm.PC) {
- yyerror("redeclaration of %s", $1.Labelname)
- }
- $1.Type = LLAB;
- $1.Value = int64(asm.PC);
- }
- line
-| LNAME '=' expr ';'
- {
- $1.Type = LVAR;
- $1.Value = $3;
- }
-| LVAR '=' expr ';'
- {
- if $1.Value != $3 {
- yyerror("redeclaration of %s", $1.Name)
- }
- $1.Value = $3;
- }
-| LSCHED ';'
- {
- nosched = int($1);
- }
-| ';'
-| inst ';'
-| error ';'
-
-inst:
-/*
- * load ints and bytes
- */
- LMOVW rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW addr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW regaddr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVB rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVB addr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVB regaddr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * load floats
- */
-| LFMOV addr ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFMOV regaddr ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFMOV fimm ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFMOV freg ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFMOV freg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFMOV freg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * store ints and bytes
- */
-| LMOVW rreg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW rreg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVB rreg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVB rreg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * store floats
- */
-| LMOVW freg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW freg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * floating point status
- */
-| LMOVW fpscr ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW freg ',' fpscr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW freg ',' imm ',' fpscr
- {
- outgcode(int($1), &$2, 0, &$4, &$6);
- }
-| LMOVW fpscr ',' creg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMTFSB imm ',' con
- {
- outcode(int($1), &$2, int($4), &nullgen);
- }
-/*
- * field moves (mtcrf)
- */
-| LMOVW rreg ',' imm ',' lcr
- {
- outgcode(int($1), &$2, 0, &$4, &$6);
- }
-| LMOVW rreg ',' creg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW rreg ',' lcr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * integer operations
- * logical instructions
- * shift instructions
- * unary instructions
- */
-| LADDW rreg ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-| LADDW imm ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-| LADDW rreg ',' imm ',' rreg
- {
- outgcode(int($1), &$2, 0, &$4, &$6);
- }
-| LADDW rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LADDW imm ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LLOGW rreg ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-| LLOGW rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LSHW rreg ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-| LSHW rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LSHW imm ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-| LSHW imm ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LABS rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LABS rreg
- {
- outcode(int($1), &$2, 0, &$2);
- }
-/*
- * multiply-accumulate
- */
-| LMA rreg ',' sreg ',' rreg
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-/*
- * move immediate: macro for cau+or, addi, addis, and other combinations
- */
-| LMOVW imm ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW ximm ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * condition register operations
- */
-| LCROP cbit ',' cbit
- {
- outcode(int($1), &$2, int($4.Reg), &$4);
- }
-| LCROP cbit ',' con ',' cbit
- {
- outcode(int($1), &$2, int($4), &$6);
- }
-/*
- * condition register moves
- * move from machine state register
- */
-| LMOVW creg ',' creg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW psr ',' creg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW lcr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW psr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW xlreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW rreg ',' xlreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW creg ',' psr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVW rreg ',' psr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * branch, branch conditional
- * branch conditional register
- * branch conditional to count register
- */
-| LBRA rel
- {
- outcode(int($1), &nullgen, 0, &$2);
- }
-| LBRA addr
- {
- outcode(int($1), &nullgen, 0, &$2);
- }
-| LBRA '(' xlreg ')'
- {
- outcode(int($1), &nullgen, 0, &$3);
- }
-| LBRA ',' rel
- {
- outcode(int($1), &nullgen, 0, &$3);
- }
-| LBRA ',' addr
- {
- outcode(int($1), &nullgen, 0, &$3);
- }
-| LBRA ',' '(' xlreg ')'
- {
- outcode(int($1), &nullgen, 0, &$4);
- }
-| LBRA creg ',' rel
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LBRA creg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LBRA creg ',' '(' xlreg ')'
- {
- outcode(int($1), &$2, 0, &$5);
- }
-| LBRA con ',' rel
- {
- outcode(int($1), &nullgen, int($2), &$4);
- }
-| LBRA con ',' addr
- {
- outcode(int($1), &nullgen, int($2), &$4);
- }
-| LBRA con ',' '(' xlreg ')'
- {
- outcode(int($1), &nullgen, int($2), &$5);
- }
-| LBRA con ',' con ',' rel
- {
- var g obj.Addr
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = $2;
- outcode(int($1), &g, int(REG_R0+$4), &$6);
- }
-| LBRA con ',' con ',' addr
- {
- var g obj.Addr
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = $2;
- outcode(int($1), &g, int(REG_R0+$4), &$6);
- }
-| LBRA con ',' con ',' '(' xlreg ')'
- {
- var g obj.Addr
- g = nullgen;
- g.Type = obj.TYPE_CONST;
- g.Offset = $2;
- outcode(int($1), &g, int(REG_R0+$4), &$7);
- }
-/*
- * conditional trap
- */
-| LTRAP rreg ',' sreg
- {
- outcode(int($1), &$2, int($4), &nullgen);
- }
-| LTRAP imm ',' sreg
- {
- outcode(int($1), &$2, int($4), &nullgen);
- }
-| LTRAP rreg comma
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-| LTRAP comma
- {
- outcode(int($1), &nullgen, 0, &nullgen);
- }
-/*
- * floating point operate
- */
-| LFCONV freg ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFADD freg ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFADD freg ',' freg ',' freg
- {
- outcode(int($1), &$2, int($4.Reg), &$6);
- }
-| LFMA freg ',' freg ',' freg ',' freg
- {
- outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
- }
-| LFCMP freg ',' freg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LFCMP freg ',' freg ',' creg
- {
- outcode(int($1), &$2, int($6.Reg), &$4);
- }
-/*
- * CMP
- */
-| LCMP rreg ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LCMP rreg ',' imm
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LCMP rreg ',' rreg ',' creg
- {
- outcode(int($1), &$2, int($6.Reg), &$4);
- }
-| LCMP rreg ',' imm ',' creg
- {
- outcode(int($1), &$2, int($6.Reg), &$4);
- }
-/*
- * rotate and mask
- */
-| LRLWM imm ',' rreg ',' imm ',' rreg
- {
- outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
- }
-| LRLWM imm ',' rreg ',' mask ',' rreg
- {
- outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
- }
-| LRLWM rreg ',' rreg ',' imm ',' rreg
- {
- outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
- }
-| LRLWM rreg ',' rreg ',' mask ',' rreg
- {
- outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
- }
-/*
- * load/store multiple
- */
-| LMOVMW addr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LMOVMW rreg ',' addr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * various indexed load/store
- * indexed unary (eg, cache clear)
- */
-| LXLD regaddr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LXLD regaddr ',' imm ',' rreg
- {
- outgcode(int($1), &$2, 0, &$4, &$6);
- }
-| LXST rreg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LXST rreg ',' imm ',' regaddr
- {
- outgcode(int($1), &$2, 0, &$4, &$6);
- }
-| LXMV regaddr ',' rreg
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LXMV rreg ',' regaddr
- {
- outcode(int($1), &$2, 0, &$4);
- }
-| LXOP regaddr
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-/*
- * NOP
- */
-| LNOP comma
- {
- outcode(int($1), &nullgen, 0, &nullgen);
- }
-| LNOP rreg comma
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-| LNOP freg comma
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-| LNOP ',' rreg
- {
- outcode(int($1), &nullgen, 0, &$3);
- }
-| LNOP ',' freg
- {
- outcode(int($1), &nullgen, 0, &$3);
- }
-| LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-/*
- * word
- */
-| LWORD imm comma
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-| LWORD ximm comma
- {
- outcode(int($1), &$2, 0, &nullgen);
- }
-/*
- * PCDATA
- */
-| LPCDAT imm ',' imm
- {
- if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST {
- yyerror("arguments to PCDATA must be integer constants")
- }
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * FUNCDATA
- */
-| LFUNCDAT imm ',' addr
- {
- if $2.Type != obj.TYPE_CONST {
- yyerror("index for FUNCDATA must be integer constant")
- }
- if $4.Type != obj.TYPE_MEM || ($4.Name != obj.NAME_EXTERN && $4.Name != obj.NAME_STATIC) {
- yyerror("value for FUNCDATA must be symbol reference")
- }
- outcode(int($1), &$2, 0, &$4);
- }
-/*
- * END
- */
-| LEND comma
- {
- outcode(int($1), &nullgen, 0, &nullgen);
- }
-/*
- * TEXT
- */
-| LTEXT name ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(int($1), &$2, 0, &$5);
- }
-| LTEXT name ',' con ',' '$' textsize
- {
- asm.Settext($2.Sym);
- outcode(int($1), &$2, int($4), &$7);
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-/*
- * GLOBL
- */
-| LGLOBL name ',' imm
- {
- asm.Settext($2.Sym)
- outcode(int($1), &$2, 0, &$4)
- }
-| LGLOBL name ',' con ',' imm
- {
- asm.Settext($2.Sym)
- outcode(int($1), &$2, 0, &$6)
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-
-/*
- * DATA
- */
-| LDATA name '/' con ',' imm
- {
- outcode(int($1), &$2, 0, &$6);
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-| LDATA name '/' con ',' ximm
- {
- outcode(int($1), &$2, 0, &$6);
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-| LDATA name '/' con ',' fimm
- {
- outcode(int($1), &$2, 0, &$6);
- if asm.Pass > 1 {
- lastpc.From3.Type = obj.TYPE_CONST
- lastpc.From3.Offset = $4
- }
- }
-/*
- * RETURN
- */
-| LRETRN comma
- {
- outcode(int($1), &nullgen, 0, &nullgen);
- }
-
-rel:
- con '(' LPC ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1 + int64(asm.PC);
- }
-| LNAME offset
- {
- $1 = asm.LabelLookup($1);
- $$ = nullgen;
- if asm.Pass == 2 && $1.Type != LLAB {
- yyerror("undefined label: %s", $1.Labelname)
- }
- $$.Type = obj.TYPE_BRANCH;
- $$.Offset = $1.Value + $2;
- }
-
-rreg:
- sreg
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-xlreg:
- lr
-| ctr
-
-lr:
- LLR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-lcr:
- LCR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1); /* whole register */
- }
-
-ctr:
- LCTR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-msr:
- LMSR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1)
- }
-
-psr:
- LSPREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-| LSPR '(' con ')'
- {
- if $3 < 0 || $3 >= 1024 {
- yyerror("SPR/DCR out of range")
- }
- $$ = nullgen;
- $$.Type = obj.TYPE_REG
- $$.Reg = int16($1 + $3);
- }
-| msr
-
-fpscr:
- LFPSCR
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-freg:
- LFREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-| LF '(' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16(REG_F0 + $3);
- }
-
-creg:
- LCREG
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-| LCR '(' con ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16(REG_C0 + $3);
- }
-
-
-cbit: con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_REG;
- $$.Reg = int16($1);
- }
-
-mask:
- con ',' con
- {
- var mb, me int
- var v uint32
-
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- mb = int($1);
- me = int($3);
- if(mb < 0 || mb > 31 || me < 0 || me > 31){
- yyerror("illegal mask start/end value(s)");
- mb = 0
- me = 0;
- }
- if mb <= me {
- v = (^uint32(0)>>uint(mb)) & (^uint32(0)<<uint(31-me))
- } else {
- v = (^uint32(0)>>uint(me+1)) & (^uint32(0)<<uint(31-(mb-1)))
- }
- $$.Offset = int64(v);
- }
-
-textsize:
- LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = int64($1)
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -int64($2)
- $$.U.Argsize = obj.ArgsSizeUnknown;
- }
-| LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = int64($1)
- $$.U.Argsize = int32($3);
- }
-| '-' LCONST '-' LCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_TEXTSIZE;
- $$.Offset = -int64($2)
- $$.U.Argsize = int32($4);
- }
-
-ximm:
- '$' addr
- {
- $$ = $2;
- $$.Type = obj.TYPE_ADDR;
- }
-| '$' LSCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_SCONST;
- $$.U.Sval = $2
- }
-
-fimm:
- '$' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = $2;
- }
-| '$' '-' LFCONST
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_FCONST;
- $$.U.Dval = -$3;
- }
-
-imm: '$' con
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_CONST;
- $$.Offset = $2;
- }
-
-sreg:
- LREG
-| LR '(' con ')'
- {
- if $$ < 0 || $$ >= NREG {
- print("register value out of range\n")
- }
- $$ = REG_R0 + $3;
- }
-
-regaddr:
- '(' sreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($2);
- $$.Offset = 0;
- }
-| '(' sreg '+' sreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($2);
- $$.Scale = int8($4);
- $$.Offset = 0;
- }
-
-addr:
- name
-| con '(' sreg ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Reg = int16($3);
- $$.Offset = $1;
- }
-
-name:
- con '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = int8($3);
- $$.Sym = nil;
- $$.Offset = $1;
- }
-| LNAME offset '(' pointer ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = int8($4);
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
- $$.Offset = $2;
- }
-| LNAME '<' '>' offset '(' LSB ')'
- {
- $$ = nullgen;
- $$.Type = obj.TYPE_MEM;
- $$.Name = obj.NAME_STATIC;
- $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
- $$.Offset = $4;
- }
-
-comma:
-| ','
-
-offset:
- {
- $$ = 0;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '-' con
- {
- $$ = -$2;
- }
-
-pointer:
- LSB
-| LSP
-| LFP
-
-con:
- LCONST
-| LVAR
- {
- $$ = $1.Value;
- }
-| '-' con
- {
- $$ = -$2;
- }
-| '+' con
- {
- $$ = $2;
- }
-| '~' con
- {
- $$ = ^$2;
- }
-| '(' expr ')'
- {
- $$ = $2;
- }
-
-expr:
- con
-| expr '+' expr
- {
- $$ = $1 + $3;
- }
-| expr '-' expr
- {
- $$ = $1 - $3;
- }
-| expr '*' expr
- {
- $$ = $1 * $3;
- }
-| expr '/' expr
- {
- $$ = $1 / $3;
- }
-| expr '%' expr
- {
- $$ = $1 % $3;
- }
-| expr '<' '<' expr
- {
- $$ = $1 << uint($4);
- }
-| expr '>' '>' expr
- {
- $$ = $1 >> uint($4);
- }
-| expr '&' expr
- {
- $$ = $1 & $3;
- }
-| expr '^' expr
- {
- $$ = $1 ^ $3;
- }
-| expr '|' expr
- {
- $$ = $1 | $3;
- }
diff --git a/src/cmd/objwriter/main.go b/src/cmd/objwriter/main.go
deleted file mode 100644
index df83298ecc..0000000000
--- a/src/cmd/objwriter/main.go
+++ /dev/null
@@ -1,411 +0,0 @@
-// Copyright 2015 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.
-
-// Objwriter reads an object file description in an unspecified format
-// and writes a Go object file. It is invoked by parts of the toolchain
-// that have not yet been converted from C to Go and should not be
-// used otherwise.
-package main
-
-import (
- "bufio"
- "bytes"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "math"
- "os"
- "runtime/pprof"
- "strconv"
- "strings"
-
- "cmd/internal/obj"
- "cmd/internal/obj/arm"
- "cmd/internal/obj/i386"
- "cmd/internal/obj/ppc64"
- "cmd/internal/obj/x86"
-)
-
-var arch *obj.LinkArch
-var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
-var memprofile = flag.String("memprofile", "", "write memory profile to this file")
-
-func main() {
- log.SetPrefix("goobj: ")
- log.SetFlags(0)
- flag.Parse()
-
- if flag.NArg() == 1 && flag.Arg(0) == "ping" {
- // old invocation from liblink, just testing that objwriter exists
- return
- }
-
- if flag.NArg() != 4 {
- fmt.Fprintf(os.Stderr, "usage: goobj infile objfile offset goarch\n")
- os.Exit(2)
- }
-
- if *cpuprofile != "" {
- f, err := os.Create(*cpuprofile)
- if err != nil {
- log.Fatal(err)
- }
- pprof.StartCPUProfile(f)
- defer pprof.StopCPUProfile()
- }
- if *memprofile != "" {
- f, err := os.Create(*memprofile)
- if err != nil {
- log.Fatal(err)
- }
- defer pprof.WriteHeapProfile(f)
- }
-
- switch flag.Arg(3) {
- case "amd64":
- arch = &x86.Linkamd64
- case "amd64p32":
- arch = &x86.Linkamd64p32
- case "386":
- // TODO(rsc): Move Link386 to package x86.
- arch = &i386.Link386
- case "arm":
- arch = &arm.Linkarm
- case "ppc64":
- arch = &ppc64.Linkppc64
- case "ppc64le":
- arch = &ppc64.Linkppc64le
- }
-
- input()
-}
-
-const (
- // must match liblink/objfilego.c
- TypeEnd = iota
- TypeCtxt
- TypePlist
- TypeSym
- TypeProg
- TypeAddr
- TypeHist
-)
-
-var (
- ctxt *obj.Link
- plists = map[int64]*obj.Plist{}
- syms = map[int64]*obj.LSym{}
- progs = map[int64]*obj.Prog{}
- hists = map[int64]*obj.Hist{}
- undef = map[interface{}]bool{}
-)
-
-func input() {
- args := flag.Args()
- ctxt = obj.Linknew(arch)
- ctxt.Debugasm = 1
- ctxt.Bso = obj.Binitw(os.Stdout)
- defer obj.Bflush(ctxt.Bso)
- ctxt.Diag = log.Fatalf
- f, err := os.Open(args[0])
- if err != nil {
- log.Fatal(err)
- }
-
- b := bufio.NewReaderSize(f, 1<<20)
- if v := rdint(b); v != TypeCtxt {
- log.Fatalf("invalid input - missing ctxt - got %d", v)
- }
- name := rdstring(b)
- if name != ctxt.Arch.Name {
- log.Fatalf("bad arch %s - want %s", name, ctxt.Arch.Name)
- }
-
- ctxt.Goarm = int32(rdint(b))
- ctxt.Debugasm = int32(rdint(b))
- ctxt.Trimpath = rdstring(b)
- ctxt.Plist = rdplist(b)
- ctxt.Plast = rdplist(b)
- ctxt.Hist = rdhist(b)
- ctxt.Ehist = rdhist(b)
- for {
- i := rdint(b)
- if i < 0 {
- break
- }
- ctxt.Hash[i] = rdsym(b)
- }
- last := int64(TypeCtxt)
-
-Loop:
- for {
- t := rdint(b)
- switch t {
- default:
- log.Fatalf("unexpected input after type %d: %v", last, t)
- case TypeEnd:
- break Loop
- case TypePlist:
- readplist(b, rdplist(b))
- case TypeSym:
- readsym(b, rdsym(b))
- case TypeProg:
- readprog(b, rdprog(b))
- case TypeHist:
- readhist(b, rdhist(b))
- }
- last = t
- }
-
- if len(undef) > 0 {
- panic("missing definitions")
- }
-
- var buf bytes.Buffer
- obuf := obj.Binitw(&buf)
- obj.Writeobjdirect(ctxt, obuf)
- obj.Bflush(obuf)
-
- data, err := ioutil.ReadFile(args[1])
- if err != nil {
- log.Fatal(err)
- }
-
- offset, err := strconv.Atoi(args[2])
- if err != nil {
- log.Fatalf("bad offset: %v", err)
- }
- if offset > len(data) {
- log.Fatalf("offset too large: %v > %v", offset, len(data))
- }
-
- old := data[offset:]
- if len(old) > 0 && !bytes.Equal(old, buf.Bytes()) {
- out := strings.TrimSuffix(args[0], ".in") + ".out"
- if err := ioutil.WriteFile(out, append(data[:offset:offset], buf.Bytes()...), 0666); err != nil {
- log.Fatal(err)
- }
- log.Fatalf("goobj produced different output:\n\toriginal: %s\n\tgoobj: %s", args[1], out)
- }
-
- if len(old) == 0 {
- data = append(data, buf.Bytes()...)
- if err := ioutil.WriteFile(args[1], data, 0666); err != nil {
- log.Fatal(err)
- }
- }
-}
-
-func rdstring(b *bufio.Reader) string {
- v := rdint(b)
- buf := make([]byte, v)
- io.ReadFull(b, buf)
- return string(buf)
-}
-
-func rdint(b *bufio.Reader) int64 {
- var v uint64
- shift := uint(0)
- for {
- b, err := b.ReadByte()
- if err != nil {
- log.Fatal(err)
- }
- v |= uint64(b&0x7F) << shift
- shift += 7
- if b&0x80 == 0 {
- break
- }
- }
- return int64(v>>1) ^ int64(v<<63)>>63
-}
-
-func rdplist(b *bufio.Reader) *obj.Plist {
- id := rdint(b)
- if id == 0 {
- return nil
- }
- pl := plists[id]
- if pl == nil {
- pl = new(obj.Plist)
- plists[id] = pl
- undef[pl] = true
- }
- return pl
-}
-
-func rdsym(b *bufio.Reader) *obj.LSym {
- id := rdint(b)
- if id == 0 {
- return nil
- }
- sym := syms[id]
- if sym == nil {
- sym = new(obj.LSym)
- syms[id] = sym
- undef[sym] = true
- }
- return sym
-}
-
-func rdprog(b *bufio.Reader) *obj.Prog {
- id := rdint(b)
- if id == 0 {
- return nil
- }
- prog := progs[id]
- if prog == nil {
- prog = new(obj.Prog)
- prog.Ctxt = ctxt
- progs[id] = prog
- undef[prog] = true
- }
- return prog
-}
-
-func rdhist(b *bufio.Reader) *obj.Hist {
- id := rdint(b)
- if id == 0 {
- return nil
- }
- h := hists[id]
- if h == nil {
- h = new(obj.Hist)
- hists[id] = h
- undef[h] = true
- }
- return h
-}
-
-func readplist(b *bufio.Reader, pl *obj.Plist) {
- if !undef[pl] {
- panic("double-def")
- }
- delete(undef, pl)
- pl.Recur = int(rdint(b))
- pl.Name = rdsym(b)
- pl.Firstpc = rdprog(b)
- pl.Link = rdplist(b)
-}
-
-func readsym(b *bufio.Reader, s *obj.LSym) {
- if !undef[s] {
- panic("double-def")
- }
- delete(undef, s)
- s.Name = rdstring(b)
- s.Extname = rdstring(b)
- s.Type = int16(rdint(b))
- s.Version = int16(rdint(b))
- s.Dupok = uint8(rdint(b))
- s.External = uint8(rdint(b))
- s.Nosplit = uint8(rdint(b))
- s.Reachable = uint8(rdint(b))
- s.Cgoexport = uint8(rdint(b))
- s.Special = uint8(rdint(b))
- s.Stkcheck = uint8(rdint(b))
- s.Hide = uint8(rdint(b))
- s.Leaf = uint8(rdint(b))
- s.Fnptr = uint8(rdint(b))
- s.Seenglobl = uint8(rdint(b))
- s.Onlist = uint8(rdint(b))
- s.Symid = int16(rdint(b))
- s.Dynid = int32(rdint(b))
- s.Sig = int32(rdint(b))
- s.Plt = int32(rdint(b))
- s.Got = int32(rdint(b))
- s.Align = int32(rdint(b))
- s.Elfsym = int32(rdint(b))
- s.Args = int32(rdint(b))
- s.Locals = int32(rdint(b))
- s.Value = rdint(b)
- s.Size = rdint(b)
- s.Hash = rdsym(b)
- s.Allsym = rdsym(b)
- s.Next = rdsym(b)
- s.Sub = rdsym(b)
- s.Outer = rdsym(b)
- s.Gotype = rdsym(b)
- s.Reachparent = rdsym(b)
- s.Queue = rdsym(b)
- s.File = rdstring(b)
- s.Dynimplib = rdstring(b)
- s.Dynimpvers = rdstring(b)
- s.Text = rdprog(b)
- s.Etext = rdprog(b)
- n := int(rdint(b))
- if n > 0 {
- s.P = make([]byte, n)
- io.ReadFull(b, s.P)
- }
- s.R = make([]obj.Reloc, int(rdint(b)))
- for i := range s.R {
- r := &s.R[i]
- r.Off = int32(rdint(b))
- r.Siz = uint8(rdint(b))
- r.Done = uint8(rdint(b))
- r.Type = int32(rdint(b))
- r.Add = rdint(b)
- r.Xadd = rdint(b)
- r.Sym = rdsym(b)
- r.Xsym = rdsym(b)
- }
-}
-
-func readprog(b *bufio.Reader, p *obj.Prog) {
- if !undef[p] {
- panic("double-def")
- }
- delete(undef, p)
- p.Pc = rdint(b)
- p.Lineno = int32(rdint(b))
- p.Link = rdprog(b)
- p.As = int16(rdint(b))
- p.Reg = int16(rdint(b))
- p.Scond = uint8(rdint(b))
- p.Width = int8(rdint(b))
- readaddr(b, &p.From)
- readaddr(b, &p.From3)
- readaddr(b, &p.To)
-}
-
-func readaddr(b *bufio.Reader, a *obj.Addr) {
- if rdint(b) != TypeAddr {
- log.Fatal("out of sync")
- }
- a.Offset = rdint(b)
- a.U.Dval = rdfloat(b)
- buf := make([]byte, 8)
- io.ReadFull(b, buf)
- a.U.Sval = string(buf)
- a.U.Branch = rdprog(b)
- a.Sym = rdsym(b)
- a.Gotype = rdsym(b)
- a.Type = int16(rdint(b))
- a.Index = int16(rdint(b))
- a.Scale = int8(rdint(b))
- a.Reg = int16(rdint(b))
- a.Name = int8(rdint(b))
- a.Class = int8(rdint(b))
- a.Etype = uint8(rdint(b))
- a.U.Argsize = int32(rdint(b))
- a.Width = rdint(b)
-}
-
-func readhist(b *bufio.Reader, h *obj.Hist) {
- if !undef[h] {
- panic("double-def")
- }
- delete(undef, h)
- h.Link = rdhist(b)
- h.Name = rdstring(b)
- h.Line = int32(rdint(b))
- h.Offset = int32(rdint(b))
-}
-
-func rdfloat(b *bufio.Reader) float64 {
- return math.Float64frombits(uint64(rdint(b)))
-}