--- /dev/null
- #include "../../pkg/runtime/funcdata.h"
+// 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.
+
+%{
+#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"
+%}
+%union
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Addr 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 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
+%type <addr> imm ximm fimm rel psr lcr cbit fpscr fpscrf msr mask
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = 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 = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * load ints and bytes
+ */
+ LMOVW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * load floats
+ */
+| LFMOV addr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV regaddr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV fimm ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store ints and bytes
+ */
+| LMOVW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store floats
+ */
+| LMOVW freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * floating point status
+ */
+| LMOVW fpscr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' fpscr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' imm ',' fpscr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW fpscr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW imm ',' fpscrf
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMTFSB imm ',' con
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * field moves (mtcrf)
+ */
+| LMOVW rreg ',' imm ',' lcr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW rreg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' lcr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * integer operations
+ * logical instructions
+ * shift instructions
+ * unary instructions
+ */
+| LADDW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LADDW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LADDW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LLOGW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LLOGW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg
+ {
+ outcode($1, &$2, NREG, &$2);
+ }
+/*
+ * multiply-accumulate
+ */
+| LMA rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * move immediate: macro for cau+or, addi, addis, and other combinations
+ */
+| LMOVW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * condition register operations
+ */
+| LCROP cbit ',' cbit
+ {
+ outcode($1, &$2, $4.reg, &$4);
+ }
+| LCROP cbit ',' con ',' cbit
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * condition register moves
+ * move from machine state register
+ */
+| LMOVW creg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW lcr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW xlreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' xlreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW creg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * branch, branch conditional
+ * branch conditional register
+ * branch conditional to count register
+ */
+| LBRA rel
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA addr
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' addr
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$4);
+ }
+| LBRA creg ',' rel
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' '(' xlreg ')'
+ {
+ outcode($1, &$2, NREG, &$5);
+ }
+| LBRA con ',' rel
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' addr
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, $2, &$5);
+ }
+| LBRA con ',' con ',' rel
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' addr
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' '(' xlreg ')'
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$7);
+ }
+/*
+ * conditional trap
+ */
+| LTRAP rreg ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP imm ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LTRAP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * floating point operate
+ */
+| LFCONV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg ',' freg
+ {
+ outcode($1, &$2, $4.reg, &$6);
+ }
+| LFMA freg ',' freg ',' freg ',' freg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LFCMP freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFCMP freg ',' freg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * CMP
+ */
+| LCMP rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' rreg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+| LCMP rreg ',' imm ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * rotate and mask
+ */
+| LRLWM imm ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM imm ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+/*
+ * load/store multiple
+ */
+| LMOVMW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVMW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * various indexed load/store
+ * indexed unary (eg, cache clear)
+ */
+| LXLD regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXLD regaddr ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXST rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXST rreg ',' imm ',' regaddr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXMV regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXMV rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXOP regaddr
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * NOP
+ */
+| LNOP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LNOP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP freg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP ',' rreg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP ',' freg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * word
+ */
+| LWORD imm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LWORD ximm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * PCDATA
+ */
+| LPCDAT imm ',' imm
+ {
+ if($2.type != D_CONST || $4.type != D_CONST)
+ yyerror("arguments to PCDATA must be integer constants");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * FUNCDATA
+ */
+| LFUNCDAT imm ',' addr
+ {
+ if($2.type != D_CONST)
+ yyerror("index for FUNCDATA must be integer constant");
+ if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
+ yyerror("value for FUNCDATA must be symbol reference");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * END
+ */
+| LEND comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTEXT name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTEXT name ',' con ',' imm
+ {
+ $6.offset &= 0xffffffffull;
+ $6.offset |= (vlong)ArgsSizeUnknown << 32;
+ outcode($1, &$2, $4, &$6);
+ }
+| LTEXT name ',' con ',' imm '-' con
+ {
+ $6.offset &= 0xffffffffull;
+ $6.offset |= ($8 & 0xffffffffull) << 32;
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LDATA name '/' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' fimm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * RETURN
+ */
+| LRETRN comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1->value + $2;
+ }
+
+rreg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+xlreg:
+ lr
+| ctr
+
+lr:
+ LLR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+lcr:
+ LCR
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = NREG; /* whole register */
+ }
+
+ctr:
+ LCTR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+msr:
+ LMSR
+ {
+ $$ = nullgen;
+ $$.type = D_MSR;
+ }
+
+psr:
+ LSPREG
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+| LSPR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ $$.offset = $3;
+ }
+| msr
+
+fpscr:
+ LFPSCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = NREG;
+ }
+
+fpscrf:
+ LFPSCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+creg:
+ LCREG
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $1;
+ }
+| LCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $3;
+ }
+
+
+cbit: con
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+mask:
+ con ',' con
+ {
+ int mb, me;
+ uint32 v;
+
+ $$ = nullgen;
+ $$.type = D_CONST;
+ mb = $1;
+ me = $3;
+ 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))));
+ $$.offset = v;
+ }
+
+ximm:
+ '$' addr
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.u.sval, $2, sizeof($$.u.sval));
+ }
+
+fimm:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.u.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.u.dval = -$3;
+ }
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+regaddr:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| '(' sreg '+' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.scale = $4;
+ $$.offset = 0;
+ }
+
+addr:
+ name
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = nil;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = linklookup(ctxt, $1->name, 0);
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = linklookup(ctxt, $1->name, 0);
+ $$.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 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
--- /dev/null
- #include "../../pkg/runtime/funcdata.h"
+/* A Bison parser, made by GNU Bison 2.5. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2011 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
+
+/* 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.5"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 268 of yacc.c */
+#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"
+
+
+/* Line 268 of yacc.c */
+#line 80 "y.tab.c"
+
+/* 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
+
+
+/* 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,
+ LDATA = 279,
+ LRETRN = 280,
+ LCONST = 281,
+ LSP = 282,
+ LSB = 283,
+ LFP = 284,
+ LPC = 285,
+ LCREG = 286,
+ LFLUSH = 287,
+ LREG = 288,
+ LFREG = 289,
+ LR = 290,
+ LCR = 291,
+ LF = 292,
+ LFPSCR = 293,
+ LLR = 294,
+ LCTR = 295,
+ LSPR = 296,
+ LSPREG = 297,
+ LSEG = 298,
+ LMSR = 299,
+ LPCDAT = 300,
+ LFUNCDAT = 301,
+ LSCHED = 302,
+ LXLD = 303,
+ LXST = 304,
+ LXOP = 305,
+ LXMV = 306,
+ LRLWM = 307,
+ LMOVMW = 308,
+ LMOVEM = 309,
+ LMOVFL = 310,
+ LMTFSB = 311,
+ LMA = 312,
+ LFCONST = 313,
+ LSCONST = 314,
+ LNAME = 315,
+ LLAB = 316,
+ LVAR = 317
+ };
+#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 LDATA 279
+#define LRETRN 280
+#define LCONST 281
+#define LSP 282
+#define LSB 283
+#define LFP 284
+#define LPC 285
+#define LCREG 286
+#define LFLUSH 287
+#define LREG 288
+#define LFREG 289
+#define LR 290
+#define LCR 291
+#define LF 292
+#define LFPSCR 293
+#define LLR 294
+#define LCTR 295
+#define LSPR 296
+#define LSPREG 297
+#define LSEG 298
+#define LMSR 299
+#define LPCDAT 300
+#define LFUNCDAT 301
+#define LSCHED 302
+#define LXLD 303
+#define LXST 304
+#define LXOP 305
+#define LXMV 306
+#define LRLWM 307
+#define LMOVMW 308
+#define LMOVEM 309
+#define LMOVFL 310
+#define LMTFSB 311
+#define LMA 312
+#define LFCONST 313
+#define LSCONST 314
+#define LNAME 315
+#define LLAB 316
+#define LVAR 317
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 293 of yacc.c */
+#line 38 "a.y"
+
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+
+
+
+/* Line 293 of yacc.c */
+#line 250 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 343 of yacc.c */
+#line 262 "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 yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#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 EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# 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 EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (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 EXIT_SUCCESS && (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_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* 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)
+
+# define YYCOPY_NEEDED 1
+
+/* 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_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* 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
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 836
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 81
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 32
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 186
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 459
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 317
+
+#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, 79, 12, 5, 2,
+ 77, 78, 10, 8, 76, 9, 2, 11, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 73, 75,
+ 6, 74, 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, 80, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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
+};
+
+#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, 7, 8, 13, 14, 19, 24,
+ 29, 32, 34, 37, 40, 45, 50, 55, 60, 65,
+ 70, 75, 80, 85, 90, 95, 100, 105, 110, 115,
+ 120, 125, 130, 135, 140, 147, 152, 157, 162, 169,
+ 174, 179, 186, 193, 200, 205, 210, 217, 222, 229,
+ 234, 241, 246, 251, 254, 261, 266, 271, 276, 283,
+ 288, 293, 298, 303, 308, 313, 318, 323, 326, 329,
+ 334, 338, 342, 348, 353, 358, 365, 370, 375, 382,
+ 389, 396, 405, 410, 415, 419, 422, 427, 432, 439,
+ 448, 453, 460, 465, 470, 477, 484, 493, 502, 511,
+ 520, 525, 530, 535, 542, 547, 554, 559, 564, 567,
+ 570, 574, 578, 582, 586, 589, 593, 597, 602, 607,
+ 610, 615, 622, 631, 638, 645, 652, 655, 660, 663,
+ 666, 668, 670, 672, 674, 676, 678, 680, 682, 687,
+ 689, 691, 696, 698, 703, 705, 710, 712, 716, 719,
+ 722, 725, 729, 732, 734, 739, 743, 749, 751, 756,
+ 761, 767, 775, 776, 778, 779, 782, 785, 787, 789,
+ 791, 793, 795, 798, 801, 804, 808, 810, 814, 818,
+ 822, 826, 830, 835, 840, 844, 848
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 82, 0, -1, -1, 82, 83, -1, -1, 71, 73,
+ 84, 83, -1, -1, 70, 73, 85, 83, -1, 70,
+ 74, 112, 75, -1, 72, 74, 112, 75, -1, 57,
+ 75, -1, 75, -1, 86, 75, -1, 1, 75, -1,
+ 13, 88, 76, 88, -1, 13, 106, 76, 88, -1,
+ 13, 105, 76, 88, -1, 14, 88, 76, 88, -1,
+ 14, 106, 76, 88, -1, 14, 105, 76, 88, -1,
+ 22, 106, 76, 97, -1, 22, 105, 76, 97, -1,
+ 22, 102, 76, 97, -1, 22, 97, 76, 97, -1,
+ 22, 97, 76, 106, -1, 22, 97, 76, 105, -1,
+ 13, 88, 76, 106, -1, 13, 88, 76, 105, -1,
+ 14, 88, 76, 106, -1, 14, 88, 76, 105, -1,
+ 13, 97, 76, 106, -1, 13, 97, 76, 105, -1,
+ 13, 95, 76, 97, -1, 13, 97, 76, 95, -1,
+ 13, 97, 76, 103, 76, 95, -1, 13, 95, 76,
+ 98, -1, 13, 103, 76, 96, -1, 66, 103, 76,
+ 111, -1, 13, 88, 76, 103, 76, 91, -1, 13,
+ 88, 76, 98, -1, 13, 88, 76, 91, -1, 18,
+ 88, 76, 104, 76, 88, -1, 18, 103, 76, 104,
+ 76, 88, -1, 18, 88, 76, 103, 76, 88, -1,
+ 18, 88, 76, 88, -1, 18, 103, 76, 88, -1,
+ 16, 88, 76, 104, 76, 88, -1, 16, 88, 76,
+ 88, -1, 17, 88, 76, 104, 76, 88, -1, 17,
+ 88, 76, 88, -1, 17, 103, 76, 104, 76, 88,
+ -1, 17, 103, 76, 88, -1, 15, 88, 76, 88,
+ -1, 15, 88, -1, 67, 88, 76, 104, 76, 88,
+ -1, 13, 103, 76, 88, -1, 13, 101, 76, 88,
+ -1, 20, 99, 76, 99, -1, 20, 99, 76, 111,
+ 76, 99, -1, 13, 98, 76, 98, -1, 13, 94,
+ 76, 98, -1, 13, 91, 76, 88, -1, 13, 94,
+ 76, 88, -1, 13, 89, 76, 88, -1, 13, 88,
+ 76, 89, -1, 13, 98, 76, 94, -1, 13, 88,
+ 76, 94, -1, 21, 87, -1, 21, 106, -1, 21,
+ 77, 89, 78, -1, 21, 76, 87, -1, 21, 76,
+ 106, -1, 21, 76, 77, 89, 78, -1, 21, 98,
+ 76, 87, -1, 21, 98, 76, 106, -1, 21, 98,
+ 76, 77, 89, 78, -1, 21, 111, 76, 87, -1,
+ 21, 111, 76, 106, -1, 21, 111, 76, 77, 89,
+ 78, -1, 21, 111, 76, 111, 76, 87, -1, 21,
+ 111, 76, 111, 76, 106, -1, 21, 111, 76, 111,
+ 76, 77, 89, 78, -1, 27, 88, 76, 104, -1,
+ 27, 103, 76, 104, -1, 27, 88, 108, -1, 27,
+ 108, -1, 23, 97, 76, 97, -1, 25, 97, 76,
+ 97, -1, 25, 97, 76, 97, 76, 97, -1, 26,
+ 97, 76, 97, 76, 97, 76, 97, -1, 24, 97,
+ 76, 97, -1, 24, 97, 76, 97, 76, 98, -1,
+ 19, 88, 76, 88, -1, 19, 88, 76, 103, -1,
+ 19, 88, 76, 88, 76, 98, -1, 19, 88, 76,
+ 103, 76, 98, -1, 62, 103, 76, 88, 76, 103,
+ 76, 88, -1, 62, 103, 76, 88, 76, 100, 76,
+ 88, -1, 62, 88, 76, 88, 76, 103, 76, 88,
+ -1, 62, 88, 76, 88, 76, 100, 76, 88, -1,
+ 63, 106, 76, 88, -1, 63, 88, 76, 106, -1,
+ 58, 105, 76, 88, -1, 58, 105, 76, 103, 76,
+ 88, -1, 59, 88, 76, 105, -1, 59, 88, 76,
+ 103, 76, 105, -1, 61, 105, 76, 88, -1, 61,
+ 88, 76, 105, -1, 60, 105, -1, 29, 108, -1,
+ 29, 88, 108, -1, 29, 97, 108, -1, 29, 76,
+ 88, -1, 29, 76, 97, -1, 29, 103, -1, 32,
+ 103, 108, -1, 32, 101, 108, -1, 55, 103, 76,
+ 103, -1, 56, 103, 76, 106, -1, 30, 108, -1,
+ 33, 107, 76, 103, -1, 33, 107, 76, 111, 76,
+ 103, -1, 33, 107, 76, 111, 76, 103, 9, 111,
+ -1, 34, 107, 11, 111, 76, 103, -1, 34, 107,
+ 11, 111, 76, 101, -1, 34, 107, 11, 111, 76,
+ 102, -1, 35, 108, -1, 111, 77, 40, 78, -1,
+ 70, 109, -1, 71, 109, -1, 104, -1, 90, -1,
+ 92, -1, 49, -1, 46, -1, 50, -1, 54, -1,
+ 52, -1, 51, 77, 111, 78, -1, 93, -1, 48,
+ -1, 48, 77, 111, 78, -1, 44, -1, 47, 77,
+ 111, 78, -1, 41, -1, 46, 77, 111, 78, -1,
+ 111, -1, 111, 76, 111, -1, 79, 106, -1, 79,
+ 69, -1, 79, 68, -1, 79, 9, 68, -1, 79,
+ 111, -1, 43, -1, 45, 77, 111, 78, -1, 77,
+ 104, 78, -1, 77, 104, 8, 104, 78, -1, 107,
+ -1, 111, 77, 104, 78, -1, 111, 77, 110, 78,
+ -1, 70, 109, 77, 110, 78, -1, 70, 6, 7,
+ 109, 77, 38, 78, -1, -1, 76, -1, -1, 8,
+ 111, -1, 9, 111, -1, 38, -1, 37, -1, 39,
+ -1, 36, -1, 72, -1, 9, 111, -1, 8, 111,
+ -1, 80, 111, -1, 77, 112, 78, -1, 111, -1,
+ 112, 8, 112, -1, 112, 9, 112, -1, 112, 10,
+ 112, -1, 112, 11, 112, -1, 112, 12, 112, -1,
+ 112, 6, 6, 112, -1, 112, 7, 7, 112, -1,
+ 112, 5, 112, -1, 112, 4, 112, -1, 112, 3,
+ 112, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 66, 66, 67, 71, 70, 78, 77, 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, 210, 217, 221,
+ 225, 235, 239, 243, 247, 251, 255, 259, 263, 267,
+ 271, 275, 279, 283, 290, 297, 301, 308, 312, 320,
+ 324, 328, 332, 336, 340, 344, 348, 357, 361, 365,
+ 369, 373, 377, 381, 385, 389, 393, 397, 401, 405,
+ 413, 421, 432, 436, 440, 444, 451, 455, 459, 463,
+ 467, 471, 478, 482, 486, 490, 497, 501, 505, 509,
+ 516, 520, 528, 532, 536, 540, 544, 548, 552, 559,
+ 563, 567, 571, 575, 579, 586, 590, 597, 606, 617,
+ 624, 628, 634, 643, 647, 651, 658, 664, 670, 678,
+ 686, 694, 695, 698, 706, 714, 722, 729, 735, 741,
+ 744, 752, 760, 766, 774, 780, 788, 796, 817, 822,
+ 830, 836, 843, 851, 852, 860, 867, 877, 878, 887,
+ 895, 903, 912, 913, 916, 919, 923, 929, 930, 931,
+ 934, 935, 939, 943, 947, 951, 957, 958, 962, 966,
+ 970, 974, 978, 982, 986, 990, 994
+};
+#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",
+ "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", "line",
+ "$@1", "$@2", "inst", "rel", "rreg", "xlreg", "lr", "lcr", "ctr", "msr",
+ "psr", "fpscr", "fpscrf", "freg", "creg", "cbit", "mask", "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, 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, 81, 82, 82, 84, 83, 85, 83, 83, 83,
+ 83, 83, 83, 83, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 87, 87, 87,
+ 88, 89, 89, 90, 91, 92, 93, 94, 94, 94,
+ 95, 96, 97, 97, 98, 98, 99, 100, 101, 101,
+ 102, 102, 103, 104, 104, 105, 105, 106, 106, 107,
+ 107, 107, 108, 108, 109, 109, 109, 110, 110, 110,
+ 111, 111, 111, 111, 111, 111, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 112
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 0, 4, 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, 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,
+ 4, 6, 8, 6, 6, 6, 2, 4, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 4, 1,
+ 1, 4, 1, 4, 1, 4, 1, 3, 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 reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 162, 162,
+ 162, 0, 0, 0, 162, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 11,
+ 3, 0, 13, 0, 0, 170, 144, 153, 142, 0,
+ 134, 0, 140, 133, 135, 0, 137, 136, 164, 171,
+ 0, 0, 0, 0, 0, 131, 0, 132, 139, 0,
+ 0, 0, 0, 0, 0, 130, 0, 0, 157, 0,
+ 0, 0, 0, 53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 146, 0, 164, 164, 0, 0, 67,
+ 0, 68, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 163, 162, 0, 85, 163, 162, 162, 114,
+ 109, 119, 162, 162, 0, 0, 0, 126, 0, 0,
+ 10, 0, 0, 0, 108, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 0, 4, 0, 12, 173, 172,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 176,
+ 0, 149, 148, 152, 174, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 152, 0, 0, 0, 0, 0, 0, 128,
+ 129, 0, 70, 71, 0, 0, 0, 0, 0, 0,
+ 150, 0, 0, 0, 0, 0, 0, 0, 0, 163,
+ 84, 0, 112, 113, 110, 111, 116, 115, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 164, 165, 166, 0, 0, 155, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 175, 14, 64,
+ 40, 66, 39, 0, 27, 26, 63, 61, 62, 60,
+ 32, 35, 33, 0, 31, 30, 65, 59, 56, 0,
+ 55, 36, 16, 15, 168, 167, 169, 0, 0, 17,
+ 29, 28, 19, 18, 52, 47, 130, 49, 130, 51,
+ 130, 44, 0, 130, 45, 130, 92, 93, 57, 146,
+ 0, 69, 0, 73, 74, 0, 76, 77, 0, 0,
+ 151, 23, 25, 24, 22, 21, 20, 86, 90, 87,
+ 0, 82, 83, 120, 0, 0, 117, 118, 102, 0,
+ 0, 104, 107, 106, 0, 0, 101, 100, 37, 0,
+ 7, 8, 5, 9, 154, 145, 143, 138, 0, 0,
+ 0, 186, 185, 184, 0, 0, 177, 178, 179, 180,
+ 181, 0, 0, 0, 158, 159, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 72, 0, 0, 0, 127,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 160, 156, 182, 183, 134, 38, 34, 0, 46,
+ 48, 50, 43, 41, 42, 94, 95, 58, 75, 78,
+ 0, 79, 80, 91, 88, 0, 121, 0, 124, 125,
+ 123, 103, 105, 0, 0, 0, 0, 0, 54, 0,
+ 141, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 161, 81, 89, 122, 99, 98, 147, 97, 96
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 40, 235, 233, 41, 99, 63, 64, 65,
+ 66, 67, 68, 69, 70, 281, 71, 72, 92, 433,
+ 73, 105, 74, 75, 76, 162, 78, 115, 157, 288,
+ 159, 160
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -178
+static const yytype_int16 yypact[] =
+{
+ -178, 471, -178, -66, 567, 640, 32, 32, -26, -26,
+ 32, 756, 626, 24, 55, 55, 55, 55, -14, 73,
+ -60, -54, 743, 743, -60, -44, -44, -32, -23, 32,
+ -23, -1, -26, 644, -44, 32, 35, 17, -10, -178,
+ -178, 48, -178, 756, 756, -178, -178, -178, -178, 4,
+ 63, 88, -178, -178, -178, 94, -178, -178, 130, -178,
+ 710, 508, 756, 101, 114, -178, 117, -178, -178, 123,
+ 128, 140, 155, 166, 170, -178, 172, 177, -178, 174,
+ 181, 190, 192, 193, 202, 756, 203, 206, 208, 220,
+ 221, 756, 224, -178, 63, 130, 175, 700, 42, -178,
+ 229, -178, 143, 6, 232, 235, 238, 240, 245, 246,
+ 255, 257, -178, 259, 262, -178, 285, -60, -60, -178,
+ -178, -178, -60, -60, 265, 268, 306, -178, 270, 271,
+ -178, 32, 272, 301, -178, 302, 315, 316, 317, 319,
+ 320, 321, 324, -178, 756, -178, 756, -178, -178, -178,
+ 756, 756, 756, 756, 394, 756, 756, 328, 15, -178,
+ 347, -178, -178, 174, -178, 614, 32, 32, 86, 26,
+ 665, 258, 32, -9, 32, 32, 18, 640, 32, 32,
+ 32, 32, -178, 32, 32, -26, 32, -26, 756, 328,
+ -178, 42, -178, -178, 330, 332, 714, 725, 157, 340,
+ -178, 696, 55, 55, 55, 55, 55, 55, 55, 32,
+ -178, 32, -178, -178, -178, -178, -178, -178, 390, 106,
+ 756, -44, 743, -26, 49, -23, 32, 32, 32, 743,
+ 32, 756, 32, 534, 357, 534, 377, 335, 337, 338,
+ 339, 175, -178, -178, 106, 32, -178, 756, 756, 756,
+ 406, 411, 756, 756, 756, 756, 756, -178, -178, -178,
+ -178, -178, -178, 343, -178, -178, -178, -178, -178, -178,
+ -178, -178, -178, 351, -178, -178, -178, -178, -178, 352,
+ -178, -178, -178, -178, -178, -178, -178, 350, 353, -178,
+ -178, -178, -178, -178, -178, -178, 361, -178, 362, -178,
+ 363, -178, 366, 369, -178, 370, 371, 372, -178, 373,
+ 375, -178, 42, -178, -178, 42, -178, -178, 184, 376,
+ -178, -178, -178, -178, -178, -178, -178, -178, 374, 379,
+ 380, -178, -178, -178, 381, 382, -178, -178, -178, 383,
+ 388, -178, -178, -178, 389, 392, -178, -178, -178, 397,
+ -178, -178, -178, -178, -178, -178, -178, -178, 398, 396,
+ 399, 620, 513, 147, 756, 756, 216, 216, -178, -178,
+ -178, 405, 418, 756, -178, -178, 32, 32, 32, 32,
+ 32, 32, 59, 59, 756, -178, 403, 404, 739, -178,
+ 59, 55, 55, -44, 420, 32, -23, 390, 390, 32,
+ 438, -178, -178, 283, 283, -178, -178, -178, 424, -178,
+ -178, -178, -178, -178, -178, -178, -178, -178, -178, -178,
+ 42, -178, -178, -178, -178, 431, 499, 334, -178, -178,
+ -178, -178, -178, 436, 439, 460, 463, 464, -178, 467,
+ -178, 484, 55, 756, 721, 32, 32, 756, 32, 32,
+ -178, -178, -178, -178, -178, -178, -178, -178, -178
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -178, -178, 8, -178, -178, -178, -90, -5, -76, -178,
+ -157, -178, -178, -153, -160, -178, 69, 40, -177, 167,
+ -15, 176, 116, 104, 82, 33, 241, 127, -75, 327,
+ 36, 71
+};
+
+/* 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 YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+ 80, 83, 84, 86, 88, 90, 122, 192, 260, 42,
+ 272, 308, 261, 113, 117, 199, 112, 47, 276, 49,
+ 189, 190, 195, 245, 133, 61, 135, 137, 139, 47,
+ 142, 49, 43, 44, 47, 85, 49, 77, 82, 279,
+ 79, 79, 47, 130, 49, 101, 107, 93, 102, 79,
+ 43, 44, 100, 85, 131, 284, 285, 286, 125, 125,
+ 45, 47, 112, 49, 146, 85, 140, 46, 48, 79,
+ 48, 51, 94, 51, 200, 47, 131, 49, 45, 148,
+ 149, 150, 104, 108, 109, 110, 111, 81, 118, 259,
+ 145, 53, 54, 246, 58, 106, 59, 163, 164, 48,
+ 46, 60, 51, 103, 62, 94, 313, 316, 143, 144,
+ 132, 212, 134, 136, 59, 310, 47, 48, 49, 91,
+ 51, 182, 62, 147, 87, 89, 131, 46, 85, 47,
+ 193, 49, 94, 194, 114, 119, 154, 123, 155, 156,
+ 151, 128, 129, 284, 285, 286, 120, 121, 138, 116,
+ 141, 127, 85, 250, 251, 252, 253, 254, 255, 256,
+ 258, 266, 267, 268, 158, 152, 358, 278, 280, 282,
+ 283, 153, 289, 292, 293, 294, 295, 165, 297, 299,
+ 301, 304, 306, 155, 156, 213, 237, 238, 239, 240,
+ 166, 242, 243, 167, 284, 285, 286, 319, 265, 168,
+ 47, 79, 49, 275, 169, 262, 79, 417, 269, 271,
+ 291, 277, 407, 79, 406, 234, 170, 236, 338, 197,
+ 198, 343, 344, 345, 309, 347, 254, 255, 256, 314,
+ 317, 171, 194, 318, 323, 158, 386, 79, 270, 387,
+ 210, 350, 172, 352, 214, 215, 173, 264, 174, 216,
+ 217, 176, 274, 175, 334, 337, 335, 177, 79, 290,
+ 388, 198, 346, 124, 126, 79, 178, 348, 179, 180,
+ 321, 324, 325, 326, 327, 328, 329, 330, 181, 183,
+ 287, 263, 184, 322, 185, 296, 273, 298, 300, 303,
+ 305, 252, 253, 254, 255, 256, 186, 187, 421, 46,
+ 188, 302, 287, 307, 94, 196, 341, 342, 201, 55,
+ 56, 202, 57, 331, 203, 332, 204, 220, 361, 362,
+ 363, 205, 206, 366, 367, 368, 369, 370, 47, 48,
+ 49, 207, 51, 208, 333, 209, 349, 336, 211, 339,
+ 340, 218, 43, 444, 441, 219, 221, 222, 223, 360,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 45, 409, 410, 411, 412, 413, 414, 224, 225, 428,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 431, 226, 227, 228, 438, 229, 230, 231, 43, 44,
+ 232, 241, 200, 161, 58, 244, 59, 198, 320, 408,
+ 311, 91, 364, 354, 62, 355, 356, 357, 365, 371,
+ 93, 422, 415, 416, 194, 257, 45, 372, 374, 373,
+ 423, 375, 351, 435, 435, 403, 404, 376, 377, 378,
+ 454, 455, 379, 457, 458, 380, 381, 382, 383, 384,
+ 390, 405, 353, 385, 389, 391, 392, 393, 394, 395,
+ 424, 425, 59, 163, 396, 397, 52, 91, 398, 85,
+ 62, 2, 3, 399, 401, 400, 439, 402, 432, 453,
+ 149, 418, 419, 456, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 427,
+ 19, 20, 440, 21, 22, 23, 24, 442, 443, 426,
+ 430, 452, 445, 434, 437, 446, 43, 44, 249, 250,
+ 251, 252, 253, 254, 255, 256, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 3, 447, 34, 35, 448,
+ 449, 36, 37, 38, 45, 450, 39, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 451, 19, 20, 436, 21, 22, 23, 24,
+ 429, 359, 0, 0, 0, 43, 44, 161, 58, 0,
+ 59, 0, 0, 0, 0, 91, 0, 0, 62, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 0, 0,
+ 34, 35, 0, 45, 36, 37, 38, 0, 46, 39,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 0, 57, 43, 44, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 0, 43, 44, 0, 58, 0, 59,
+ 0, 0, 0, 0, 60, 0, 61, 62, 43, 44,
+ 45, 0, 43, 44, 0, 46, 0, 47, 0, 49,
+ 50, 0, 45, 53, 54, 55, 56, 46, 57, 0,
+ 0, 0, 94, 43, 44, 0, 45, 0, 0, 0,
+ 45, 0, 0, 47, 58, 49, 59, 47, 0, 49,
+ 0, 60, 0, 85, 62, 0, 95, 96, 59, 0,
+ 0, 45, 97, 98, 43, 44, 62, 0, 43, 44,
+ 58, 0, 59, 52, 58, 0, 59, 60, 43, 44,
+ 62, 91, 43, 44, 62, 0, 0, 0, 0, 43,
+ 44, 0, 45, 43, 44, 58, 45, 59, 0, 0,
+ 48, 0, 60, 51, 85, 62, 45, 43, 44, 0,
+ 45, 43, 44, 47, 0, 49, 0, 45, 0, 0,
+ 0, 45, 0, 0, 43, 44, 58, 0, 59, 0,
+ 95, 96, 59, 60, 0, 45, 62, 191, 0, 45,
+ 62, 0, 59, 0, 95, 96, 59, 91, 0, 320,
+ 62, 312, 45, 59, 62, 95, 96, 59, 91, 0,
+ 0, 62, 315, 0, 0, 62, 0, 0, 0, 95,
+ 96, 59, 0, 58, 0, 59, 420, 0, 0, 62,
+ 91, 0, 0, 62, 0, 0, 0, 0, 59, 0,
+ 0, 0, 0, 91, 0, 0, 62
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-178))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 5, 6, 7, 8, 9, 10, 21, 97, 165, 75,
+ 170, 188, 165, 18, 19, 9, 76, 43, 171, 45,
+ 95, 96, 98, 8, 29, 79, 31, 32, 33, 43,
+ 35, 45, 8, 9, 43, 79, 45, 4, 5, 48,
+ 4, 5, 43, 75, 45, 12, 13, 11, 12, 13,
+ 8, 9, 12, 79, 77, 37, 38, 39, 22, 23,
+ 36, 43, 76, 45, 74, 79, 33, 41, 44, 33,
+ 44, 47, 46, 47, 68, 43, 77, 45, 36, 43,
+ 44, 77, 13, 14, 15, 16, 17, 5, 19, 165,
+ 73, 49, 50, 78, 70, 13, 72, 61, 62, 44,
+ 41, 77, 47, 79, 80, 46, 196, 197, 73, 74,
+ 28, 116, 30, 31, 72, 191, 43, 44, 45, 77,
+ 47, 85, 80, 75, 8, 9, 77, 41, 79, 43,
+ 97, 45, 46, 97, 18, 19, 6, 21, 8, 9,
+ 77, 25, 26, 37, 38, 39, 19, 20, 32, 76,
+ 34, 24, 79, 6, 7, 8, 9, 10, 11, 12,
+ 165, 166, 167, 168, 60, 77, 241, 172, 173, 174,
+ 175, 77, 177, 178, 179, 180, 181, 76, 183, 184,
+ 185, 186, 187, 8, 9, 116, 150, 151, 152, 153,
+ 76, 155, 156, 76, 37, 38, 39, 40, 165, 76,
+ 43, 165, 45, 170, 76, 165, 170, 384, 168, 169,
+ 177, 171, 372, 177, 371, 144, 76, 146, 223, 76,
+ 77, 226, 227, 228, 188, 230, 10, 11, 12, 196,
+ 197, 76, 196, 197, 201, 131, 312, 201, 169, 315,
+ 113, 233, 76, 235, 117, 118, 76, 165, 76, 122,
+ 123, 77, 170, 76, 218, 222, 220, 76, 222, 177,
+ 76, 77, 229, 22, 23, 229, 76, 231, 76, 76,
+ 201, 202, 203, 204, 205, 206, 207, 208, 76, 76,
+ 176, 165, 76, 201, 76, 181, 170, 183, 184, 185,
+ 186, 8, 9, 10, 11, 12, 76, 76, 388, 41,
+ 76, 185, 198, 187, 46, 76, 224, 225, 76, 51,
+ 52, 76, 54, 209, 76, 211, 76, 11, 247, 248,
+ 249, 76, 76, 252, 253, 254, 255, 256, 43, 44,
+ 45, 76, 47, 76, 218, 76, 232, 221, 76, 223,
+ 224, 76, 8, 9, 420, 77, 76, 76, 76, 245,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 36, 376, 377, 378, 379, 380, 381, 76, 76, 394,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 395, 76, 76, 76, 399, 76, 76, 76, 8, 9,
+ 76, 7, 68, 69, 70, 77, 72, 77, 68, 373,
+ 78, 77, 6, 78, 80, 78, 78, 78, 7, 76,
+ 384, 388, 382, 383, 388, 78, 36, 76, 78, 77,
+ 390, 78, 75, 397, 398, 364, 365, 76, 76, 76,
+ 445, 446, 76, 448, 449, 76, 76, 76, 76, 76,
+ 76, 46, 75, 78, 78, 76, 76, 76, 76, 76,
+ 391, 392, 72, 427, 76, 76, 48, 77, 76, 79,
+ 80, 0, 1, 76, 78, 77, 38, 78, 396, 443,
+ 444, 78, 78, 447, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 79,
+ 29, 30, 78, 32, 33, 34, 35, 76, 9, 393,
+ 394, 442, 76, 397, 398, 76, 8, 9, 5, 6,
+ 7, 8, 9, 10, 11, 12, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 1, 76, 66, 67, 76,
+ 76, 70, 71, 72, 36, 78, 75, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 78, 29, 30, 398, 32, 33, 34, 35,
+ 394, 244, -1, -1, -1, 8, 9, 69, 70, -1,
+ 72, -1, -1, -1, -1, 77, -1, -1, 80, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
+ 66, 67, -1, 36, 70, 71, 72, -1, 41, 75,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ -1, 54, 8, 9, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, -1, 8, 9, -1, 70, -1, 72,
+ -1, -1, -1, -1, 77, -1, 79, 80, 8, 9,
+ 36, -1, 8, 9, -1, 41, -1, 43, -1, 45,
+ 46, -1, 36, 49, 50, 51, 52, 41, 54, -1,
+ -1, -1, 46, 8, 9, -1, 36, -1, -1, -1,
+ 36, -1, -1, 43, 70, 45, 72, 43, -1, 45,
+ -1, 77, -1, 79, 80, -1, 70, 71, 72, -1,
+ -1, 36, 76, 77, 8, 9, 80, -1, 8, 9,
+ 70, -1, 72, 48, 70, -1, 72, 77, 8, 9,
+ 80, 77, 8, 9, 80, -1, -1, -1, -1, 8,
+ 9, -1, 36, 8, 9, 70, 36, 72, -1, -1,
+ 44, -1, 77, 47, 79, 80, 36, 8, 9, -1,
+ 36, 8, 9, 43, -1, 45, -1, 36, -1, -1,
+ -1, 36, -1, -1, 8, 9, 70, -1, 72, -1,
+ 70, 71, 72, 77, -1, 36, 80, 77, -1, 36,
+ 80, -1, 72, -1, 70, 71, 72, 77, -1, 68,
+ 80, 77, 36, 72, 80, 70, 71, 72, 77, -1,
+ -1, 80, 77, -1, -1, 80, -1, -1, -1, 70,
+ 71, 72, -1, 70, -1, 72, 77, -1, -1, 80,
+ 77, -1, -1, 80, -1, -1, -1, -1, 72, -1,
+ -1, -1, -1, 77, -1, -1, 80
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 82, 0, 1, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 29,
+ 30, 32, 33, 34, 35, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 66, 67, 70, 71, 72, 75,
+ 83, 86, 75, 8, 9, 36, 41, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 54, 70, 72,
+ 77, 79, 80, 88, 89, 90, 91, 92, 93, 94,
+ 95, 97, 98, 101, 103, 104, 105, 106, 107, 111,
+ 88, 105, 106, 88, 88, 79, 88, 103, 88, 103,
+ 88, 77, 99, 111, 46, 70, 71, 76, 77, 87,
+ 98, 106, 111, 79, 97, 102, 105, 106, 97, 97,
+ 97, 97, 76, 88, 103, 108, 76, 88, 97, 103,
+ 108, 108, 101, 103, 107, 111, 107, 108, 103, 103,
+ 75, 77, 105, 88, 105, 88, 105, 88, 103, 88,
+ 106, 103, 88, 73, 74, 73, 74, 75, 111, 111,
+ 77, 77, 77, 77, 6, 8, 9, 109, 104, 111,
+ 112, 69, 106, 111, 111, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 77, 76, 76, 76,
+ 76, 76, 111, 76, 76, 76, 76, 76, 76, 109,
+ 109, 77, 87, 106, 111, 89, 76, 76, 77, 9,
+ 68, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 108, 76, 88, 97, 108, 108, 108, 108, 76, 77,
+ 11, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 85, 112, 84, 112, 111, 111, 111,
+ 111, 7, 111, 111, 77, 8, 78, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 78, 88, 89,
+ 91, 94, 98, 103, 105, 106, 88, 88, 88, 98,
+ 97, 98, 95, 103, 105, 106, 94, 98, 88, 48,
+ 88, 96, 88, 88, 37, 38, 39, 104, 110, 88,
+ 105, 106, 88, 88, 88, 88, 104, 88, 104, 88,
+ 104, 88, 103, 104, 88, 104, 88, 103, 99, 111,
+ 89, 78, 77, 87, 106, 77, 87, 106, 111, 40,
+ 68, 97, 105, 106, 97, 97, 97, 97, 97, 97,
+ 97, 104, 104, 103, 111, 111, 103, 106, 88, 103,
+ 103, 105, 105, 88, 88, 88, 106, 88, 111, 104,
+ 83, 75, 83, 75, 78, 78, 78, 78, 109, 110,
+ 104, 112, 112, 112, 6, 7, 112, 112, 112, 112,
+ 112, 76, 76, 77, 78, 78, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 78, 89, 89, 76, 78,
+ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 77, 78, 78, 112, 112, 46, 91, 95, 111, 88,
+ 88, 88, 88, 88, 88, 98, 98, 99, 78, 78,
+ 77, 87, 106, 98, 97, 97, 103, 79, 101, 102,
+ 103, 88, 105, 100, 103, 111, 100, 103, 88, 38,
+ 78, 89, 76, 9, 9, 76, 76, 76, 76, 76,
+ 78, 78, 97, 111, 88, 88, 111, 88, 88
+};
+
+#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. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ 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
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#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 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ 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++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (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 *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = 0;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ 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 yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* 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 = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#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 lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead 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;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ 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_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, 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));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead 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 (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ 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 4:
+
+/* Line 1806 of yacc.c */
+#line 71 "a.y"
+ {
+ if((yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 6:
+
+/* Line 1806 of yacc.c */
+#line 78 "a.y"
+ {
+ (yyvsp[(1) - (2)].sym)->type = LLAB;
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 8:
+
+/* Line 1806 of yacc.c */
+#line 84 "a.y"
+ {
+ (yyvsp[(1) - (4)].sym)->type = LVAR;
+ (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 9:
+
+/* Line 1806 of yacc.c */
+#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 10:
+
+/* Line 1806 of yacc.c */
+#line 95 "a.y"
+ {
+ nosched = (yyvsp[(1) - (2)].lval);
+ }
+ break;
+
+ case 14:
+
+/* Line 1806 of yacc.c */
+#line 107 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 15:
+
+/* Line 1806 of yacc.c */
+#line 111 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 16:
+
+/* Line 1806 of yacc.c */
+#line 115 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 17:
+
+/* Line 1806 of yacc.c */
+#line 119 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 18:
+
+/* Line 1806 of yacc.c */
+#line 123 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 19:
+
+/* Line 1806 of yacc.c */
+#line 127 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 20:
+
+/* Line 1806 of yacc.c */
+#line 134 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 21:
+
+/* Line 1806 of yacc.c */
+#line 138 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 22:
+
+/* Line 1806 of yacc.c */
+#line 142 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 23:
+
+/* Line 1806 of yacc.c */
+#line 146 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 24:
+
+/* Line 1806 of yacc.c */
+#line 150 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 25:
+
+/* Line 1806 of yacc.c */
+#line 154 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 26:
+
+/* Line 1806 of yacc.c */
+#line 161 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 27:
+
+/* Line 1806 of yacc.c */
+#line 165 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 28:
+
+/* Line 1806 of yacc.c */
+#line 169 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 29:
+
+/* Line 1806 of yacc.c */
+#line 173 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 30:
+
+/* Line 1806 of yacc.c */
+#line 180 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 31:
+
+/* Line 1806 of yacc.c */
+#line 184 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 32:
+
+/* Line 1806 of yacc.c */
+#line 191 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 33:
+
+/* Line 1806 of yacc.c */
+#line 195 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 34:
+
+/* Line 1806 of yacc.c */
+#line 199 "a.y"
+ {
+ outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 35:
+
+/* Line 1806 of yacc.c */
+#line 203 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 36:
+
+/* Line 1806 of yacc.c */
+#line 207 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 37:
+
+/* Line 1806 of yacc.c */
+#line 211 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ break;
+
+ case 38:
+
+/* Line 1806 of yacc.c */
+#line 218 "a.y"
+ {
+ outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 39:
+
+/* Line 1806 of yacc.c */
+#line 222 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 40:
+
+/* Line 1806 of yacc.c */
+#line 226 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 41:
+
+/* Line 1806 of yacc.c */
+#line 236 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 42:
+
+/* Line 1806 of yacc.c */
+#line 240 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 43:
+
+/* Line 1806 of yacc.c */
+#line 244 "a.y"
+ {
+ outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 44:
+
+/* Line 1806 of yacc.c */
+#line 248 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 45:
+
+/* Line 1806 of yacc.c */
+#line 252 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 46:
+
+/* Line 1806 of yacc.c */
+#line 256 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 47:
+
+/* Line 1806 of yacc.c */
+#line 260 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 48:
+
+/* Line 1806 of yacc.c */
+#line 264 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 49:
+
+/* Line 1806 of yacc.c */
+#line 268 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 50:
+
+/* Line 1806 of yacc.c */
+#line 272 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 51:
+
+/* Line 1806 of yacc.c */
+#line 276 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 52:
+
+/* Line 1806 of yacc.c */
+#line 280 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 53:
+
+/* Line 1806 of yacc.c */
+#line 284 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 54:
+
+/* Line 1806 of yacc.c */
+#line 291 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 55:
+
+/* Line 1806 of yacc.c */
+#line 298 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 56:
+
+/* Line 1806 of yacc.c */
+#line 302 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 57:
+
+/* Line 1806 of yacc.c */
+#line 309 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].addr).reg, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 58:
+
+/* Line 1806 of yacc.c */
+#line 313 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 59:
+
+/* Line 1806 of yacc.c */
+#line 321 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 60:
+
+/* Line 1806 of yacc.c */
+#line 325 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 61:
+
+/* Line 1806 of yacc.c */
+#line 329 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 62:
+
+/* Line 1806 of yacc.c */
+#line 333 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 63:
+
+/* Line 1806 of yacc.c */
+#line 337 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 64:
+
+/* Line 1806 of yacc.c */
+#line 341 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 65:
+
+/* Line 1806 of yacc.c */
+#line 345 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 66:
+
+/* Line 1806 of yacc.c */
+#line 349 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 67:
+
+/* Line 1806 of yacc.c */
+#line 358 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 68:
+
+/* Line 1806 of yacc.c */
+#line 362 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &(yyvsp[(2) - (2)].addr));
+ }
+ break;
+
+ case 69:
+
+/* Line 1806 of yacc.c */
+#line 366 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, NREG, &(yyvsp[(3) - (4)].addr));
+ }
+ break;
+
+ case 70:
+
+/* Line 1806 of yacc.c */
+#line 370 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 71:
+
+/* Line 1806 of yacc.c */
+#line 374 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 72:
+
+/* Line 1806 of yacc.c */
+#line 378 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), &nullgen, NREG, &(yyvsp[(4) - (5)].addr));
+ }
+ break;
+
+ case 73:
+
+/* Line 1806 of yacc.c */
+#line 382 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 74:
+
+/* Line 1806 of yacc.c */
+#line 386 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 75:
+
+/* Line 1806 of yacc.c */
+#line 390 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(5) - (6)].addr));
+ }
+ break;
+
+ case 76:
+
+/* Line 1806 of yacc.c */
+#line 394 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 77:
+
+/* Line 1806 of yacc.c */
+#line 398 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 78:
+
+/* Line 1806 of yacc.c */
+#line 402 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr));
+ }
+ break;
+
+ case 79:
+
+/* Line 1806 of yacc.c */
+#line 406 "a.y"
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = (yyvsp[(2) - (6)].lval);
+ outcode((yyvsp[(1) - (6)].lval), &g, (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 80:
+
+/* Line 1806 of yacc.c */
+#line 414 "a.y"
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = (yyvsp[(2) - (6)].lval);
+ outcode((yyvsp[(1) - (6)].lval), &g, (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 81:
+
+/* Line 1806 of yacc.c */
+#line 422 "a.y"
+ {
+ Addr g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = (yyvsp[(2) - (8)].lval);
+ outcode((yyvsp[(1) - (8)].lval), &g, (yyvsp[(4) - (8)].lval), &(yyvsp[(7) - (8)].addr));
+ }
+ break;
+
+ case 82:
+
+/* Line 1806 of yacc.c */
+#line 433 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ break;
+
+ case 83:
+
+/* Line 1806 of yacc.c */
+#line 437 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen);
+ }
+ break;
+
+ case 84:
+
+/* Line 1806 of yacc.c */
+#line 441 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 85:
+
+/* Line 1806 of yacc.c */
+#line 445 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 86:
+
+/* Line 1806 of yacc.c */
+#line 452 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 87:
+
+/* Line 1806 of yacc.c */
+#line 456 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 88:
+
+/* Line 1806 of yacc.c */
+#line 460 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 89:
+
+/* Line 1806 of yacc.c */
+#line 464 "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 90:
+
+/* Line 1806 of yacc.c */
+#line 468 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 91:
+
+/* Line 1806 of yacc.c */
+#line 472 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 92:
+
+/* Line 1806 of yacc.c */
+#line 479 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 93:
+
+/* Line 1806 of yacc.c */
+#line 483 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 94:
+
+/* Line 1806 of yacc.c */
+#line 487 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 95:
+
+/* Line 1806 of yacc.c */
+#line 491 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr));
+ }
+ break;
+
+ case 96:
+
+/* Line 1806 of yacc.c */
+#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 97:
+
+/* Line 1806 of yacc.c */
+#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 98:
+
+/* Line 1806 of yacc.c */
+#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 99:
+
+/* Line 1806 of yacc.c */
+#line 510 "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 100:
+
+/* Line 1806 of yacc.c */
+#line 517 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 101:
+
+/* Line 1806 of yacc.c */
+#line 521 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 102:
+
+/* Line 1806 of yacc.c */
+#line 529 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 103:
+
+/* Line 1806 of yacc.c */
+#line 533 "a.y"
+ {
+ outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 104:
+
+/* Line 1806 of yacc.c */
+#line 537 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 105:
+
+/* Line 1806 of yacc.c */
+#line 541 "a.y"
+ {
+ outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), NREG, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 106:
+
+/* Line 1806 of yacc.c */
+#line 545 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 107:
+
+/* Line 1806 of yacc.c */
+#line 549 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 108:
+
+/* Line 1806 of yacc.c */
+#line 553 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 109:
+
+/* Line 1806 of yacc.c */
+#line 560 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 110:
+
+/* Line 1806 of yacc.c */
+#line 564 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 111:
+
+/* Line 1806 of yacc.c */
+#line 568 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 112:
+
+/* Line 1806 of yacc.c */
+#line 572 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 113:
+
+/* Line 1806 of yacc.c */
+#line 576 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+ }
+ break;
+
+ case 114:
+
+/* Line 1806 of yacc.c */
+#line 580 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 115:
+
+/* Line 1806 of yacc.c */
+#line 587 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 116:
+
+/* Line 1806 of yacc.c */
+#line 591 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), NREG, &nullgen);
+ }
+ break;
+
+ case 117:
+
+/* Line 1806 of yacc.c */
+#line 598 "a.y"
+ {
+ if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST)
+ yyerror("arguments to PCDATA must be integer constants");
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 118:
+
+/* Line 1806 of yacc.c */
+#line 607 "a.y"
+ {
+ if((yyvsp[(2) - (4)].addr).type != D_CONST)
+ yyerror("index for FUNCDATA must be integer constant");
+ if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG)
+ yyerror("value for FUNCDATA must be symbol reference");
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 119:
+
+/* Line 1806 of yacc.c */
+#line 618 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 120:
+
+/* Line 1806 of yacc.c */
+#line 625 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+ }
+ break;
+
+ case 121:
+
+/* Line 1806 of yacc.c */
+#line 629 "a.y"
+ {
+ (yyvsp[(6) - (6)].addr).offset &= 0xffffffffull;
+ (yyvsp[(6) - (6)].addr).offset |= (vlong)ArgsSizeUnknown << 32;
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 122:
+
+/* Line 1806 of yacc.c */
+#line 635 "a.y"
+ {
+ (yyvsp[(6) - (8)].addr).offset &= 0xffffffffull;
+ (yyvsp[(6) - (8)].addr).offset |= ((yyvsp[(8) - (8)].lval) & 0xffffffffull) << 32;
+ outcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr));
+ }
+ break;
+
+ case 123:
+
+/* Line 1806 of yacc.c */
+#line 644 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 124:
+
+/* Line 1806 of yacc.c */
+#line 648 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 125:
+
+/* Line 1806 of yacc.c */
+#line 652 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+ }
+ break;
+
+ case 126:
+
+/* Line 1806 of yacc.c */
+#line 659 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 127:
+
+/* Line 1806 of yacc.c */
+#line 665 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
+ }
+ break;
+
+ case 128:
+
+/* Line 1806 of yacc.c */
+#line 671 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 129:
+
+/* Line 1806 of yacc.c */
+#line 679 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 130:
+
+/* Line 1806 of yacc.c */
+#line 687 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 133:
+
+/* Line 1806 of yacc.c */
+#line 699 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 134:
+
+/* Line 1806 of yacc.c */
+#line 707 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CREG;
+ (yyval.addr).reg = NREG; /* whole register */
+ }
+ break;
+
+ case 135:
+
+/* Line 1806 of yacc.c */
+#line 715 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 136:
+
+/* Line 1806 of yacc.c */
+#line 723 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_MSR;
+ }
+ break;
+
+ case 137:
+
+/* Line 1806 of yacc.c */
+#line 730 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SPR;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 138:
+
+/* Line 1806 of yacc.c */
+#line 736 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 140:
+
+/* Line 1806 of yacc.c */
+#line 745 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FPSCR;
+ (yyval.addr).reg = NREG;
+ }
+ break;
+
+ case 141:
+
+/* Line 1806 of yacc.c */
+#line 753 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FPSCR;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 142:
+
+/* Line 1806 of yacc.c */
+#line 761 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 143:
+
+/* Line 1806 of yacc.c */
+#line 767 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 144:
+
+/* Line 1806 of yacc.c */
+#line 775 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CREG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 145:
+
+/* Line 1806 of yacc.c */
+#line 781 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 146:
+
+/* Line 1806 of yacc.c */
+#line 789 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 147:
+
+/* Line 1806 of yacc.c */
+#line 797 "a.y"
+ {
+ int mb, me;
+ uint32 v;
+
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_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 148:
+
+/* Line 1806 of yacc.c */
+#line 818 "a.y"
+ {
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
+ (yyval.addr).type = D_CONST;
+ }
+ break;
+
+ case 149:
+
+/* Line 1806 of yacc.c */
+#line 823 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SCONST;
+ memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
+ }
+ break;
+
+ case 150:
+
+/* Line 1806 of yacc.c */
+#line 831 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+ }
+ break;
+
+ case 151:
+
+/* Line 1806 of yacc.c */
+#line 837 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
+ }
+ break;
+
+ case 152:
+
+/* Line 1806 of yacc.c */
+#line 844 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 154:
+
+/* Line 1806 of yacc.c */
+#line 853 "a.y"
+ {
+ if((yyval.lval) < 0 || (yyval.lval) >= NREG)
+ print("register value out of range\n");
+ (yyval.lval) = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 155:
+
+/* Line 1806 of yacc.c */
+#line 861 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
+ (yyval.addr).offset = 0;
+ }
+ break;
+
+ case 156:
+
+/* Line 1806 of yacc.c */
+#line 868 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
+ (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
+ (yyval.addr).offset = 0;
+ }
+ break;
+
+ case 158:
+
+/* Line 1806 of yacc.c */
+#line 879 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 159:
+
+/* Line 1806 of yacc.c */
+#line 888 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = (yyvsp[(3) - (4)].lval);
+ (yyval.addr).sym = nil;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 160:
+
+/* Line 1806 of yacc.c */
+#line 896 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (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 161:
+
+/* Line 1806 of yacc.c */
+#line 904 "a.y"
+ {
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = D_STATIC;
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 0);
+ (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
+ }
+ break;
+
+ case 164:
+
+/* Line 1806 of yacc.c */
+#line 916 "a.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 165:
+
+/* Line 1806 of yacc.c */
+#line 920 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 166:
+
+/* Line 1806 of yacc.c */
+#line 924 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 171:
+
+/* Line 1806 of yacc.c */
+#line 936 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+ }
+ break;
+
+ case 172:
+
+/* Line 1806 of yacc.c */
+#line 940 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 173:
+
+/* Line 1806 of yacc.c */
+#line 944 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 174:
+
+/* Line 1806 of yacc.c */
+#line 948 "a.y"
+ {
+ (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 175:
+
+/* Line 1806 of yacc.c */
+#line 952 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 177:
+
+/* Line 1806 of yacc.c */
+#line 959 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 178:
+
+/* Line 1806 of yacc.c */
+#line 963 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 179:
+
+/* Line 1806 of yacc.c */
+#line 967 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 180:
+
+/* Line 1806 of yacc.c */
+#line 971 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 181:
+
+/* Line 1806 of yacc.c */
+#line 975 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 182:
+
+/* Line 1806 of yacc.c */
+#line 979 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 183:
+
+/* Line 1806 of yacc.c */
+#line 983 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 184:
+
+/* Line 1806 of yacc.c */
+#line 987 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 185:
+
+/* Line 1806 of yacc.c */
+#line 991 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 186:
+
+/* Line 1806 of yacc.c */
+#line 995 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+
+
+/* Line 1806 of yacc.c */
+#line 3566 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ 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:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead 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 lookahead 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 (!yypact_value_is_default (yyn))
+ {
+ 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);
+ }
+
+ *++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;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ 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);
+}
+
+
+
--- /dev/null
- #include "../../pkg/runtime/funcdata.h"
+// cmd/9c/cgen.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
++#include "../../runtime/funcdata.h"
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ int32 v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r, 0, 0);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED) {
+ if(nn != Z || r->addable < INDEXED) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OXOR:
+ if(nn != Z)
+ if(r->op == OCONST && r->vconst == -1){
+ cgen(l, nn);
+ gopcode(OCOM, nn, Z, nn);
+ break;
+ }
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z &&
+ r->op == OCONST &&
+ !typefd[n->type->etype] &&
+ immconst(r)) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OMUL:
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, l, Z); /* note: l used for type, so shifts work! */
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST &&
+ !typefd[n->type->etype] &&
+ immconst(r)) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+ regalloc(&nod1, n, Z);
+ gopcode(OAS, &nod2, Z, &nod1);
+ if(nod1.type->etype != nod.type->etype){
+ regalloc(&nod3, &nod, Z);
+ gmove(&nod1, &nod3);
+ regfree(&nod1);
+ nod1 = nod3;
+ }
+ gopcode(o, &nod, &nod1, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ regalloc(&nod3, r, Z);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ cgen(r, &nod3);
+ } else {
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(n->op, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left, 0, 0);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ if(REGARG >= 0)
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ gpcdata(PCDATA_ArgSize, curarg);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ gpcdata(PCDATA_ArgSize, -1);
+ if(REGARG>=0)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ regret(&nod, n, l->type, 1); // update maxarg if nothing else
+ gpcdata(PCDATA_ArgSize, curarg);
+ gpcdata(PCDATA_ArgSize, -1);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ if(nod.op == OREGISTER)
+ regfree(&nod);
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ cgen(l, nn);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (int32)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+ if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */
+ gins(ANOP, l, Z);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ int32 v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ int32 curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ if(n->op == OCONST) {
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ nodreg(&nod1, n, NREG+FREGZERO);
+ gopcode(o, &nod, Z, &nod1);
+ } else
+ gopcode(o, &nod, Z, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r, 0, 0);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, Z, r);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, Z, &nod);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1L), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0L), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ int32 pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (int32)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no side effects
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regalloc(&nod2, &nod1, Z);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ /* prtree(&nod0, "hand craft"); /* */
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ /* BOTCH -- functions can clobber rathole */
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(!hasdotdotdot(n->left->type)) {
+ cgen(n, Z);
+ if(nn != Z) {
+ curarg -= n->type->width;
+ regret(&nod1, n, n->left->type, 1);
+ if(nn->complex >= FNX) {
+ regsalloc(&nod2, n);
+ cgen(&nod1, &nod2);
+ nod1 = nod2;
+ }
+ cgen(&nod1, nn);
+ }
+ break;
+ }
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, ®node, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1L), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+
+ gopcode(OGT, &nod3, Z, nodconst(0));
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, ®node, Z);
+ regalloc(&t2, ®node, Z);
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
--- /dev/null
- // 4 and 128 = magic constants: see ../../pkg/runtime/asm_power64x.s
+// 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 "opt.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
+ ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
+
+ // fill in final stack size
+ ptxt->to.offset <<= 32;
+ 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, D_REG, REGZERO, 0, D_OREG, REGSP, 8+frame+lo+i);
+ } else if(cnt <= 128*widthptr) {
+ p = appendpp(p, AADD, D_CONST, NREG, 8+frame+lo-8, D_REG, REGRT1, 0);
+ p->reg = REGSP;
+ p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 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, D_CONST, NREG, 8+frame+lo-8, D_REG, REGTMP, 0);
+ p = appendpp(p, AADD, D_REG, REGTMP, 0, D_REG, REGRT1, 0);
+ p->reg = REGSP;
+ p = appendpp(p, AMOVD, D_CONST, NREG, cnt, D_REG, REGTMP, 0);
+ p = appendpp(p, AADD, D_REG, REGTMP, 0, D_REG, REGRT2, 0);
+ p->reg = REGRT1;
+ p1 = p = appendpp(p, AMOVDU, D_REG, REGZERO, 0, D_OREG, REGRT1, widthptr);
+ p = appendpp(p, ACMP, D_REG, REGRT1, 0, D_REG, REGRT2, 0);
+ p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 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;
+}
+
+// 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)
+ p->from.node->used = 1;
+
+ if (p->to.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 == D_AUTO && !p->from.node->used) {
+ *lp = p->link;
+ continue;
+ }
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.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.
+ p->to.type = D_NONE;
+ p->to.node = N;
+ p->as = ANOP;
+ continue;
+ }
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+
+ lp = &p->link;
+ }
+}
+
+/*
+ * 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 = D_SPR;
+ p->to.offset = D_CTR;
+ p = gins(ABL, reg, N);
+ p->to.type = D_SPR;
+ p->to.offset = D_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)
+{
+ int32 arg;
+ Prog *p;
+ Node reg, con, reg2;
+ Node r1;
+
+ if(f->type != T)
+ setmaxarg(f->type);
+
+ arg = -1;
+ // Most functions have a fixed-size argument block, so traceback uses that during unwind.
+ // Not all, though: there are some variadic functions in package runtime,
+ // and for those we emit call-specific metadata recorded by caller.
+ // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
+ // so we do this for all indirect calls as well.
+ if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
+ arg = f->type->argwid;
+ if(proc == 1 || proc == 2)
+ arg += 3*widthptr;
+ }
+
+ if(arg != -1)
+ gargsize(arg);
+
+ 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 Power64 NOP that we will have the right line number.
+ // Power64 NOP is really or r0, r0, r0; use that description
+ // because the NOP pseudo-instruction would be removed by
+ // the linker.
+ nodreg(®, types[TINT], D_R0);
+ gins(AOR, ®, ®);
+ }
+ p = gins(ABL, N, f);
+ afunclit(&p->to, f);
+ if(proc == -1 || noreturn(p))
+ gins(AUNDEF, N, N);
+ break;
+ }
+ nodreg(®, types[tptr], D_R0+REGENV);
+ nodreg(&r1, types[tptr], D_R0+3);
+ gmove(f, ®);
+ reg.op = OINDREG;
+ gmove(®, &r1);
+ reg.op = OREGISTER;
+ ginsBL(®, &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(®, types[TINT64], D_R0+3);
+ nodreg(®2, types[TINT64], D_R0+4);
+ gmove(f, ®);
+
+ p = gins(ASUB, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = 3 * 8;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ gmove(&con, ®2);
+ p = gins(AMOVW, ®2, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 8;
+
+ p = gins(AMOVD, ®, N);
+ p->to.type = D_OREG;
+ 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);
+ }
+
+ p = gins(AADD, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = 3 * 8;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ if(proc == 2) {
+ nodreg(®, types[TINT64], D_R0+3);
+ p = gins(ACMP, ®, N);
+ p->to.type = D_REG;
+ p->to.reg = D_R0;
+ p = gbranch(ABEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
+ }
+ break;
+ }
+
+ if(arg != -1)
+ gargsize(-1);
+}
+
+/*
+ * 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], D_R0+REGSP);
+ nodsp.xoffset = widthptr;
+ nodi.type = types[tptr];
+ nodi.xoffset += widthptr;
+ cgen(&nodi, &nodsp); // 0(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 = D_CONST;
+ }
+
+ 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 = D_R0+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 = D_R0 + 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 = D_EXTERN;
+ p->to.type = D_CONST;
+ p->to.sym = linksym(n->left->sym);
+ }
+}
+
+void
+cgen_asop(Node *n)
+{
+ USED(n);
+ fatal("cgen_asop"); // no longer used
+}
+
+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;
+}
+
+/*
+ * 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 = D_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 = D_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 = D_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;
+ 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], 0); // r0 is always zero
+ nodreg(&dst, types[tptr], D_R0+REGRT1);
+ reg[REGRT1]++;
+ agen(nl, &dst);
+
+ if(q > 128) {
+ p = gins(ASUB, N, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = 8;
+
+ regalloc(&end, types[tptr], N);
+ p = gins(AMOVD, &dst, &end);
+ p->from.type = D_CONST;
+ p->from.offset = q*8;
+
+ p = gins(AMOVDU, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 8;
+ pl = p;
+
+ p = gins(ACMP, &dst, &end);
+ patch(gbranch(ABNE, T, 0), pl);
+
+ regfree(&end);
+ } else if(q >= 4) {
+ p = gins(ASUB, N, &dst);
+ p->from.type = D_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_power64x.s
+ p->to.offset = 4*(128-q);
+ } else
+ for(t = 0; t < q; t++) {
+ p = gins(AMOVD, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 8*t;
+ }
+
+ for(t = 0; t < c; t++) {
+ p = gins(AMOVB, &r0, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = t;
+ }
+ 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 != D_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 = D_CONST;
+ p->from.offset = 4;
+ p->from.reg = NREG;
+ p->reg = 0;
+ p->to.type = D_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 = D_REG;
+ p->to.reg = REGZERO;
+ p1->as = ABNE;
+ //p1->from.type = D_CONST;
+ //p1->from.offset = 1; // likely
+ p1->to.type = D_BRANCH;
+ p1->to.u.branch = p2->link;
+ // crash by write to memory address 0.
+ p2->as = AMOVD;
+ p2->from.type = D_REG;
+ p2->from.reg = 0;
+ p2->to.type = D_OREG;
+ p2->to.reg = 0;
+ p2->to.offset = 0;
+ }
+}
--- /dev/null
- #include "../../pkg/runtime/funcdata.h"
+// 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"
- // At the same time, can raise StackBig in ../../pkg/runtime/stack.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;
+
+void
+clearp(Prog *p)
+{
+ *p = zprog;
+ p->as = AEND;
+ p->pc = pcloc;
+ pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ p->reg = 0; // used for flags
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ return p;
+}
+
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ * -1 unlikely
+ * 0 no opinion
+ * +1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+ Prog *p;
+
+ USED(t);
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.u.branch = P;
+ // TODO(minux): Enable this code.
+ // Note: liblink used Bcc CR0, label form, so we need another way
+ // to set likely/unlikely flag. Also note the y bit is not exactly
+ // likely/unlikely bit.
+ if(0 && as != ABR && likely != 0) {
+ p->from.type = D_CONST;
+ p->from.offset = likely > 0;
+ }
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.u.branch = to;
+ p->to.offset = to->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.u.branch;
+ p->to.u.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = linknewplist(ctxt);
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(ABR, T, 0);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
+ p->to.type = D_CONST;
+ p->to.offset = nam->type->width;
+ if(nam->readonly)
+ p->reg = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->reg |= NOPTR;
+}
+
+void
+gtrack(Sym *s)
+{
+ Prog *p;
+
+ p = gins(AUSEFIELD, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+}
+
+void
+gargsize(vlong size)
+{
+ Node n1, n2;
+
+ nodconst(&n1, types[TINT32], PCDATA_ArgSize);
+ nodconst(&n2, types[TINT32], size);
+ gins(APCDATA, &n1, &n2);
+}
+
+void
+ggloblsym(Sym *s, int32 width, int8 flags)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = linksym(s);
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ p->to.offset = width;
+ p->reg = flags;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a, Node *n)
+{
+ if(a->type == D_CONST && a->name == D_EXTERN) {
+ a->type = D_OREG;
+ a->sym = linksym(n->sym);
+ }
+}
+
+static int resvd[] =
+{
+ REGZERO,
+ REGSP, // reserved for SP, XXX: not reserved in 9c.
+ 30, // for g
+ REGTMP, // REGTMP
+ FREGCVI+NREG,
+ FREGZERO+NREG,
+ FREGHALF+NREG,
+ FREGONE+NREG,
+ FREGTWO+NREG,
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 1;
+ for(i=0; i<NREG; i++)
+ reg[i] = 0;
+ for(i=NREG; i<NREG+NREG; i++)
+ reg[i] = 0;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]++;
+}
+
+static uintptr regpc[nelem(reg)];
+
+void
+gclean(void)
+{
+ int i;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]--;
+
+ for(i=0; i<nelem(reg); i++)
+ if(reg[i])
+ yyerror("reg %R left allocated, %p\n", i, regpc[i]);
+}
+
+int32
+anyregalloc(void)
+{
+ int i, j;
+
+ for(i=0; i<nelem(reg); i++) {
+ if(reg[i] == 0)
+ goto ok;
+ for(j=0; j<nelem(resvd); j++)
+ if(resvd[j] == i)
+ goto ok;
+ return 1;
+ ok:;
+ }
+ return 0;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i, et;
+ int fixfree, fltfree;
+
+ if(t == T)
+ fatal("regalloc: t nil");
+ et = simtype[t->etype];
+
+ if(debug['r']) {
+ fixfree = 0;
+ fltfree = 0;
+ for(i = D_R0; i < D_F0+NREG; i++)
+ if(reg[i] == 0) {
+ if(i < D_F0)
+ fixfree++;
+ else
+ fltfree++;
+ }
+ print("regalloc fix %d flt %d free\n", fixfree, fltfree);
+ }
+
+ switch(et) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TPTR32:
+ case TPTR64:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_R0+REGMIN && i <= D_R0+REGMAX)
+ goto out;
+ }
+ for(i=D_R0+REGMIN; i<=D_R0+REGMAX; i++)
+ if(reg[i] == 0) {
+ regpc[i] = (uintptr)getcallerpc(&n);
+ goto out;
+ }
+ flusherrors();
+ for(i=D_R0; i<D_R0+NREG; i++)
+ print("R%d %p\n", i, regpc[i]);
+ fatal("out of fixed registers");
+
+ case TFLOAT32:
+ case TFLOAT64:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_F0+FREGMIN && i <= D_F0+FREGMAX)
+ goto out;
+ }
+ for(i=D_F0+FREGMIN; i<=D_F0+FREGMAX; i++)
+ if(reg[i] == 0) {
+ regpc[i] = (uintptr)getcallerpc(&n);
+ goto out;
+ }
+ flusherrors();
+ for(i=D_F0; i<D_F0+NREG; i++)
+ print("F%d %p\n", i, regpc[i]);
+ fatal("out of floating registers");
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
+ }
+ fatal("regalloc: unknown type %T", t);
+ return;
+
+out:
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op == ONAME)
+ return;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.u.reg;
+ if(i == D_R0 + REGSP)
+ return;
+ if(i < 0 || i >= nelem(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+ if(reg[i] == 0)
+ regpc[i] = 0;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ NodeList *l;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ if(t->etype == TSTRUCT && t->funarg) {
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ goto fp;
+ }
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ if(fp == 1) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
+ return n;
+ }
+ }
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+ n->orig = t->nname;
+
+fp:
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
+
+ switch(fp) {
+ default:
+ fatal("nodarg %T %d", t, fp);
+
+ case 0: // output arg for calling another function
+ n->op = OINDREG;
+ n->val.u.reg = D_R0+REGSP;
+ n->xoffset += 8;
+ break;
+
+ case 1: // input arg to current function
+ n->class = PPARAM;
+ break;
+
+ case 2: // offset output arg
+fatal("shouldn't be used");
+ n->op = OINDREG;
+ n->val.u.reg = D_R0 + REGSP;
+ n->xoffset += types[tptr]->width;
+ break;
+ }
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * generate
+ * as $c, n
+ */
+void
+ginscon(int as, vlong c, Node *n2)
+{
+ Node n1, ntmp;
+
+ nodconst(&n1, types[TINT64], c);
+
+ if(as != AMOVD && (c < -BIG || c > BIG)) {
+ // cannot have more than 16-bit of immediate in ADD, etc.
+ // instead, MOV into register first.
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVD, &n1, &ntmp);
+ gins(as, &ntmp, n2);
+ regfree(&ntmp);
+ return;
+ }
+ gins(as, &n1, n2);
+}
+
+/*
+ * generate
+ * as n, $c (CMP/CMPU)
+ */
+void
+ginscon2(int as, Node *n2, vlong c)
+{
+ Node n1, ntmp;
+
+ nodconst(&n1, types[TINT64], c);
+
+ switch(as) {
+ default:
+ fatal("ginscon2");
+ case ACMP:
+ if(-BIG <= c && c <= BIG) {
+ gins(as, n2, &n1);
+ return;
+ }
+ break;
+ case ACMPU:
+ if(0 <= c && c <= 2*BIG) {
+ gins(as, n2, &n1);
+ return;
+ }
+ break;
+ }
+ // MOV n1 into register first
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVD, &n1, &ntmp);
+ gins(as, n2, &ntmp);
+ regfree(&ntmp);
+}
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+/*c2go int CASE(int, int); */
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OITAB:
+ case OSPTR:
+ case OLEN:
+ case OCAP:
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ case OCLOSUREVAR:
+ case OADDR:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * set up nodes representing 2^63
+ */
+Node bigi;
+Node bigf;
+
+void
+bignodes(void)
+{
+ static int did;
+
+ if(did)
+ return;
+ did = 1;
+
+ nodconst(&bigi, types[TUINT64], 1);
+ mpshiftfix(bigi.val.u.xval, 63);
+
+ bigf = bigi;
+ bigf.type = types[TFLOAT64];
+ bigf.val.ctype = CTFLT;
+ bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+ mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
+
+/*
+ * generate move:
+ * t = f
+ * hard part is conversions.
+ */
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt;
+ Type *cvt;
+ Node r1, r2, r3, con;
+ Prog *p1, *p2;
+
+ if(debug['M'])
+ print("gmove %lN -> %lN\n", f, t);
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ cvt = t->type;
+
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
+ // cannot have two memory operands
+ if(ismem(f) && ismem(t))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ switch(tt) {
+ default:
+ convconst(&con, t->type, &f->val);
+ break;
+
+ case TINT32:
+ case TINT16:
+ case TINT8:
+ convconst(&con, types[TINT64], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVD, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+ case TUINT32:
+ case TUINT16:
+ case TUINT8:
+ convconst(&con, types[TUINT64], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVD, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+ }
+
+ f = &con;
+ ft = tt; // so big switch will choose a simple mov
+
+ // constants can't move directly to memory.
+ if(ismem(t)) {
+ goto hard;
+ // float constants come from memory.
+ //if(isfloat[tt])
+ // goto hard;
+
+ // 64-bit immediates are also from memory.
+ //if(isint[tt])
+ // goto hard;
+ //// 64-bit immediates are really 32-bit sign-extended
+ //// unless moving into a register.
+ //if(isint[tt]) {
+ // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+ // goto hard;
+ // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+ // goto hard;
+ //}
+ }
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
+ switch(CASE(ft, tt)) {
+ default:
+ fatal("gmove %lT -> %lT", f->type, t->type);
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TUINT8, TINT8):
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ case CASE(TINT64, TINT8):
+ case CASE(TUINT64, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(TINT8, TUINT8): // same size
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TUINT8): // truncate
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ a = AMOVBZ;
+ break;
+
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TUINT16, TINT16):
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ case CASE(TINT64, TINT16):
+ case CASE(TUINT64, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(TINT16, TUINT16): // same size
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TUINT16): // truncate
+ case CASE(TUINT32, TUINT16):
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ a = AMOVHZ;
+ break;
+
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TUINT32, TINT32):
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ a = AMOVW;
+ break;
+
+ case CASE(TINT32, TUINT32): // same size
+ case CASE(TUINT32, TUINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ a = AMOVWZ;
+ break;
+
+ case CASE(TINT64, TINT64): // same size
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TUINT64, TUINT64):
+ a = AMOVD;
+ break;
+
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
+ case CASE(TINT8, TUINT16):
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ case CASE(TINT8, TINT64):
+ case CASE(TINT8, TUINT64):
+ a = AMOVB;
+ goto rdst;
+
+ case CASE(TUINT8, TINT16): // zero extend uint8
+ case CASE(TUINT8, TUINT16):
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ case CASE(TUINT8, TINT64):
+ case CASE(TUINT8, TUINT64):
+ a = AMOVBZ;
+ goto rdst;
+
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ case CASE(TINT16, TINT64):
+ case CASE(TINT16, TUINT64):
+ a = AMOVH;
+ goto rdst;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ case CASE(TUINT16, TINT64):
+ case CASE(TUINT16, TUINT64):
+ a = AMOVHZ;
+ goto rdst;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ a = AMOVW;
+ goto rdst;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ a = AMOVWZ;
+ goto rdst;
+
+ /*
+ * float to integer
+ */
+ case CASE(TFLOAT32, TINT32):
+ case CASE(TFLOAT64, TINT32):
+ case CASE(TFLOAT32, TINT64):
+ case CASE(TFLOAT64, TINT64):
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT32, TUINT32):
+ case CASE(TFLOAT64, TUINT32):
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT64, TUINT64):
+ //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
+ //return;
+ // algorithm is:
+ // if small enough, use native float64 -> int64 conversion.
+ // otherwise, subtract 2^63, convert, and add it back.
+ bignodes();
+ regalloc(&r1, types[ft], f);
+ gmove(f, &r1);
+ if(tt == TUINT64) {
+ regalloc(&r2, types[TFLOAT64], N);
+ gmove(&bigf, &r2);
+ gins(AFCMPU, &r1, &r2);
+ p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1);
+ gins(AFSUB, &r2, &r1);
+ patch(p1, pc);
+ regfree(&r2);
+ }
+ regalloc(&r2, types[TFLOAT64], N);
+ regalloc(&r3, types[TINT64], t);
+ gins(AFCTIDZ, &r1, &r2);
+ p1 = gins(AFMOVD, &r2, N);
+ p1->to.type = D_OREG;
+ p1->to.reg = REGSP;
+ p1->to.offset = -8;
+ p1 = gins(AMOVD, N, &r3);
+ p1->from.type = D_OREG;
+ p1->from.reg = REGSP;
+ p1->from.offset = -8;
+ regfree(&r2);
+ regfree(&r1);
+ if(tt == TUINT64) {
+ p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1); // use CR0 here again
+ nodreg(&r1, types[TINT64], D_R0+REGTMP);
+ gins(AMOVD, &bigi, &r1);
+ gins(AADD, &r1, &r3);
+ patch(p1, pc);
+ }
+ gmove(&r3, t);
+ regfree(&r3);
+ return;
+
+ /*
+ * integer to float
+ */
+ case CASE(TINT32, TFLOAT32):
+ case CASE(TINT32, TFLOAT64):
+ case CASE(TINT64, TFLOAT32):
+ case CASE(TINT64, TFLOAT64):
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT64):
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT64):
+ case CASE(TUINT64, TFLOAT32):
+ case CASE(TUINT64, TFLOAT64):
+ //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
+ //return;
+ // algorithm is:
+ // if small enough, use native int64 -> uint64 conversion.
+ // otherwise, halve (rounding to odd?), convert, and double.
+ bignodes();
+ regalloc(&r1, types[TINT64], N);
+ gmove(f, &r1);
+ if(ft == TUINT64) {
+ nodreg(&r2, types[TUINT64], D_R0+REGTMP);
+ gmove(&bigi, &r2);
+ gins(ACMPU, &r1, &r2);
+ p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1);
+ p2 = gins(ASRD, N, &r1);
+ p2->from.type = D_CONST;
+ p2->from.offset = 1;
+ patch(p1, pc);
+ }
+ regalloc(&r2, types[TFLOAT64], t);
+ p1 = gins(AMOVD, &r1, N);
+ p1->to.type = D_OREG;
+ p1->to.reg = REGSP;
+ p1->to.offset = -8;
+ p1 = gins(AFMOVD, N, &r2);
+ p1->from.type = D_OREG;
+ p1->from.reg = REGSP;
+ p1->from.offset = -8;
+ gins(AFCFID, &r2, &r2);
+ regfree(&r1);
+ if(ft == TUINT64) {
+ p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); // use CR0 here again
+ nodreg(&r1, types[TFLOAT64], D_F0+FREGTWO);
+ gins(AFMUL, &r1, &r2);
+ patch(p1, pc);
+ }
+ gmove(&r2, t);
+ regfree(&r2);
+ return;
+
+ /*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ a = AFMOVS;
+ break;
+
+ case CASE(TFLOAT64, TFLOAT64):
+ a = AFMOVD;
+ break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ a = AFMOVS;
+ goto rdst;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ a = AFRSP;
+ goto rdst;
+ }
+
+ gins(a, f, t);
+ return;
+
+rdst:
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+}
+
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+ //int32 w;
+ Prog *p;
+ Addr af, at;
+
+ memset(&af, 0, sizeof af);
+ memset(&at, 0, sizeof at);
+ if(f != N)
+ naddr(f, &af, 1);
+ if(t != N)
+ naddr(t, &at, 1);
+ p = prog(as);
+ if(f != N)
+ p->from = af;
+ if(t != N)
+ p->to = at;
+ if(as == ATEXT)
+ p->reg = 0;
+ if(debug['g'])
+ print("%P\n", p);
+
+ // TODO(minux): enable these.
+ // right now it fails on MOVD $type."".TypeAssertionError(SB) [width=1], R7 [width=8]
+ /*
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ case AMOVBU:
+ case AMOVBZ:
+ case AMOVBZU:
+ w = 1;
+ break;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVHZ:
+ case AMOVHZU:
+ w = 2;
+ break;
+ case AMOVW:
+ case AMOVWU:
+ case AMOVWZ:
+ case AMOVWZU:
+ w = 4;
+ break;
+ case AMOVD:
+ case AMOVDU:
+ w = 8;
+ break;
+ }
+ if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
+ dump("f", f);
+ dump("t", t);
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+ */
+
+ return p;
+}
+
+void
+fixlargeoffset(Node *n)
+{
+ Node a;
+
+ if(n == N)
+ return;
+ if(n->op != OINDREG)
+ return;
+ if(n->val.u.reg == D_R0+REGSP) // stack offset cannot be large
+ return;
+ if(n->xoffset != (int32)n->xoffset) {
+ // TODO(minux): offset too large, move into R31 and add to R31 instead.
+ // this is used only in test/fixedbugs/issue6036.go.
+ print("offset too large: %N\n", n);
+ noimpl;
+ a = *n;
+ a.op = OREGISTER;
+ a.type = types[tptr];
+ a.xoffset = 0;
+ cgen_checknil(&a);
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
+ n->xoffset = 0;
+ }
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ Sym *s;
+
+ a->type = D_NONE;
+ a->name = D_NONE;
+ a->reg = NREG;
+ a->gotype = nil;
+ a->node = N;
+ a->etype = 0;
+ a->width = 0;
+ if(n == N)
+ return;
+
+ if(n->type != T && n->type->etype != TIDEAL) {
+ dowidth(n->type);
+ a->width = n->type->width;
+ }
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ a->width = 0;
+ a->reg = NREG;
+ if(n->type != T) {
+ a->etype = simtype[n->type->etype];
+ a->width = n->type->width;
+ }
+ a->offset = n->xoffset;
+ s = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
+ if(s == S)
+ s = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ s = pkglookup(s->name, n->type->sym->pkg);
+ }
+
+ a->type = D_OREG;
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->name = D_EXTERN;
+ break;
+ case PAUTO:
+ a->name = D_AUTO;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->name = D_PARAM;
+ break;
+ case PFUNC:
+ a->name = D_EXTERN;
+ a->type = D_CONST;
+ a->width = widthptr;
+ s = funcsym(s);
+ break;
+ }
+ a->sym = linksym(s);
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->u.dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ case CTRUNE:
+ a->sym = nil;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = nil;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = nil;
+ a->type = D_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+ case OREGISTER:
+ if(n->val.u.reg < D_F0) {
+ a->type = D_REG;
+ a->reg = n->val.u.reg;
+ } else {
+ a->type = D_FREG;
+ a->reg = n->val.u.reg - D_F0;
+ }
+ a->sym = nil;
+ break;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->reg = n->val.u.reg;
+ a->sym = linksym(n->sym);
+ a->offset = n->xoffset;
+ if(a->offset != (int32)a->offset)
+ yyerror("offset %lld too large for OINDREG", a->offset);
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = simtype[n->left->type->etype];
+ a->width = n->left->type->width;
+ a->offset = n->xoffset;
+ a->sym = linksym(n->left->sym);
+ a->type = D_OREG;
+ a->name = D_PARAM;
+ a->node = n->left->orig;
+ break;
+
+ case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
+ a->type = D_OREG;
+ a->reg = REGENV;
+ a->offset = n->xoffset;
+ a->sym = nil;
+ break;
+
+ case OCFUNC:
+ naddr(n->left, a, canemitcode);
+ a->sym = linksym(n->left->sym);
+ break;
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[tptr];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ break;
+
+ case OSPTR:
+ // pointer in a string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // ptr(nil)
+ a->etype = simtype[tptr];
+ a->offset += Array_array;
+ a->width = widthptr;
+ break;
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[TINT];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->offset += Array_nel;
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = simtype[TINT];
+ if(a->type == D_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->offset += Array_cap;
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ a->etype = tptr;
+ switch(a->type) {
+ case D_OREG:
+ a->type = D_CONST;
+ break;
+
+ case D_REG:
+ case D_CONST:
+ break;
+
+ default:
+ fatal("naddr: OADDR %d\n", a->type);
+ }
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, simtype[t->etype])) {
+ default:
+ fatal("optoas: no entry for op=%O type=%T", op, t);
+ break;
+
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ a = ABEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ a = ABNE;
+ break;
+
+ case CASE(OLT, TINT8): // ACMP
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ case CASE(OLT, TUINT8): // ACMPU
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ case CASE(OLT, TFLOAT32): // AFCMPU
+ case CASE(OLT, TFLOAT64):
+ a = ABLT;
+ break;
+
+ case CASE(OLE, TINT8): // ACMP
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ case CASE(OLE, TUINT8): // ACMPU
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ case CASE(OLE, TFLOAT32): // AFCMPU
+ case CASE(OLE, TFLOAT64):
+ a = ABLE;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ case CASE(OGT, TFLOAT32):
+ case CASE(OGT, TFLOAT64):
+ a = ABGT;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ case CASE(OGE, TFLOAT32):
+ case CASE(OGE, TFLOAT64):
+ a = ABGE;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TPTR32):
+ case CASE(OCMP, TINT64):
+ a = ACMP;
+ break;
+
+ case CASE(OCMP, TUINT8):
+ case CASE(OCMP, TUINT16):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TUINT64):
+ case CASE(OCMP, TPTR64):
+ a = ACMPU;
+ break;
+
+ case CASE(OCMP, TFLOAT32):
+ case CASE(OCMP, TFLOAT64):
+ a = AFCMPU;
+ break;
+
+ case CASE(OAS, TBOOL):
+ case CASE(OAS, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(OAS, TUINT8):
+ a = AMOVBZ;
+ break;
+
+ case CASE(OAS, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(OAS, TUINT16):
+ a = AMOVHZ;
+ break;
+
+ case CASE(OAS, TINT32):
+ a = AMOVW;
+ break;
+
+ case CASE(OAS, TUINT32):
+ case CASE(OAS, TPTR32):
+ a = AMOVWZ;
+ break;
+
+ case CASE(OAS, TINT64):
+ case CASE(OAS, TUINT64):
+ case CASE(OAS, TPTR64):
+ a = AMOVD;
+ break;
+
+ case CASE(OAS, TFLOAT32):
+ a = AFMOVS;
+ break;
+
+ case CASE(OAS, TFLOAT64):
+ a = AFMOVD;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ case CASE(OADD, TINT64):
+ case CASE(OADD, TUINT64):
+ case CASE(OADD, TPTR64):
+ a = AADD;
+ break;
+
+ case CASE(OADD, TFLOAT32):
+ a = AFADDS;
+ break;
+
+ case CASE(OADD, TFLOAT64):
+ a = AFADD;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ case CASE(OSUB, TINT64):
+ case CASE(OSUB, TUINT64):
+ case CASE(OSUB, TPTR64):
+ a = ASUB;
+ break;
+
+ case CASE(OSUB, TFLOAT32):
+ a = AFSUBS;
+ break;
+
+ case CASE(OSUB, TFLOAT64):
+ a = AFSUB;
+ break;
+
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ case CASE(OMINUS, TINT64):
+ case CASE(OMINUS, TUINT64):
+ case CASE(OMINUS, TPTR64):
+ a = ANEG;
+ break;
+
+ case CASE(OAND, TINT8):
+ case CASE(OAND, TUINT8):
+ case CASE(OAND, TINT16):
+ case CASE(OAND, TUINT16):
+ case CASE(OAND, TINT32):
+ case CASE(OAND, TUINT32):
+ case CASE(OAND, TPTR32):
+ case CASE(OAND, TINT64):
+ case CASE(OAND, TUINT64):
+ case CASE(OAND, TPTR64):
+ a = AAND;
+ break;
+
+ case CASE(OOR, TINT8):
+ case CASE(OOR, TUINT8):
+ case CASE(OOR, TINT16):
+ case CASE(OOR, TUINT16):
+ case CASE(OOR, TINT32):
+ case CASE(OOR, TUINT32):
+ case CASE(OOR, TPTR32):
+ case CASE(OOR, TINT64):
+ case CASE(OOR, TUINT64):
+ case CASE(OOR, TPTR64):
+ a = AOR;
+ break;
+
+ case CASE(OXOR, TINT8):
+ case CASE(OXOR, TUINT8):
+ case CASE(OXOR, TINT16):
+ case CASE(OXOR, TUINT16):
+ case CASE(OXOR, TINT32):
+ case CASE(OXOR, TUINT32):
+ case CASE(OXOR, TPTR32):
+ case CASE(OXOR, TINT64):
+ case CASE(OXOR, TUINT64):
+ case CASE(OXOR, TPTR64):
+ a = AXOR;
+ break;
+
+ // TODO(minux): handle rotates
+ //case CASE(OLROT, TINT8):
+ //case CASE(OLROT, TUINT8):
+ //case CASE(OLROT, TINT16):
+ //case CASE(OLROT, TUINT16):
+ //case CASE(OLROT, TINT32):
+ //case CASE(OLROT, TUINT32):
+ //case CASE(OLROT, TPTR32):
+ //case CASE(OLROT, TINT64):
+ //case CASE(OLROT, TUINT64):
+ //case CASE(OLROT, TPTR64):
+ // a = 0//???; RLDC?
+ // break;
+
+ case CASE(OLSH, TINT8):
+ case CASE(OLSH, TUINT8):
+ case CASE(OLSH, TINT16):
+ case CASE(OLSH, TUINT16):
+ case CASE(OLSH, TINT32):
+ case CASE(OLSH, TUINT32):
+ case CASE(OLSH, TPTR32):
+ case CASE(OLSH, TINT64):
+ case CASE(OLSH, TUINT64):
+ case CASE(OLSH, TPTR64):
+ a = ASLD;
+ break;
+
+ case CASE(ORSH, TUINT8):
+ case CASE(ORSH, TUINT16):
+ case CASE(ORSH, TUINT32):
+ case CASE(ORSH, TPTR32):
+ case CASE(ORSH, TUINT64):
+ case CASE(ORSH, TPTR64):
+ a = ASRD;
+ break;
+
+ case CASE(ORSH, TINT8):
+ case CASE(ORSH, TINT16):
+ case CASE(ORSH, TINT32):
+ case CASE(ORSH, TINT64):
+ a = ASRAD;
+ break;
+
+ // TODO(minux): handle rotates
+ //case CASE(ORROTC, TINT8):
+ //case CASE(ORROTC, TUINT8):
+ //case CASE(ORROTC, TINT16):
+ //case CASE(ORROTC, TUINT16):
+ //case CASE(ORROTC, TINT32):
+ //case CASE(ORROTC, TUINT32):
+ //case CASE(ORROTC, TINT64):
+ //case CASE(ORROTC, TUINT64):
+ // a = 0//??? RLDC??
+ // break;
+
+ case CASE(OHMUL, TINT64):
+ a = AMULHD;
+ break;
+ case CASE(OHMUL, TUINT64):
+ case CASE(OHMUL, TPTR64):
+ a = AMULHDU;
+ break;
+
+ case CASE(OMUL, TINT8):
+ case CASE(OMUL, TINT16):
+ case CASE(OMUL, TINT32):
+ case CASE(OMUL, TINT64):
+ a = AMULLD;
+ break;
+
+ case CASE(OMUL, TUINT8):
+ case CASE(OMUL, TUINT16):
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ // don't use word multiply, the high 32-bit are undefined.
+ // fallthrough
+ case CASE(OMUL, TUINT64):
+ case CASE(OMUL, TPTR64):
+ a = AMULLD; // for 64-bit multiplies, signedness doesn't matter.
+ break;
+
+ case CASE(OMUL, TFLOAT32):
+ a = AFMULS;
+ break;
+
+ case CASE(OMUL, TFLOAT64):
+ a = AFMUL;
+ break;
+
+ case CASE(ODIV, TINT8):
+ case CASE(ODIV, TINT16):
+ case CASE(ODIV, TINT32):
+ case CASE(ODIV, TINT64):
+ a = ADIVD;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ case CASE(ODIV, TUINT16):
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ case CASE(ODIV, TUINT64):
+ case CASE(ODIV, TPTR64):
+ a = ADIVDU;
+ break;
+
+ case CASE(ODIV, TFLOAT32):
+ a = AFDIVS;
+ break;
+
+ case CASE(ODIV, TFLOAT64):
+ a = AFDIV;
+ break;
+
+ }
+ return a;
+}
+
+enum
+{
+ ODynam = 1<<0,
+ OAddable = 1<<1,
+};
+
+int
+xgen(Node *n, Node *a, int o)
+{
+ // TODO(minux)
+ USED(n); USED(a); USED(o);
+ return -1;
+}
+
+void
+sudoclean(void)
+{
+ return;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+ // TODO(minux)
+ USED(as); USED(n); USED(a);
+ return 0;
+}
--- /dev/null
- #include "../pkg/runtime/stack.h"
+// cmd/9l/optab.c, cmd/9l/asmout.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.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/9l/9.out.h"
++#include "../runtime/stack.h"
+
+enum {
+ FuncAlign = 8,
+};
+
+enum {
+ r0iszero = 1,
+};
+
+typedef struct Optab Optab;
+
+struct Optab
+{
+ short as;
+ uchar a1;
+ uchar a2;
+ uchar a3;
+ uchar a4;
+ char type;
+ char size;
+ char param;
+};
+
+static Optab optab[] = {
+ { ATEXT, C_LEXT, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_NONE, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, C_LCON, 0, 0, 0 },
+
+ /* move register */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
+
+ { AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, no literal */
+ { AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+
+ { AANDCC, C_ANDCON,C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_ANDCON,C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+ { AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+
+ { ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
+
+ { AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, literal not cc (or/xor) */
+ { AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op r1[,r2],r3 */
+ { ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, /* op r2[,r1],r3 */
+ { ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+
+ { ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0 },
+ { ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0 },
+ { ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0 },
+ { ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0 },
+
+ { ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
+
+ { ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0 },
+ { ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0 },
+ { ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0 },
+
+ { ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
+ { ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
+ { ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0 },
+ { ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0 },
+
+ { AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0 },
+ { AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0 },
+ { AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0 },
+ { AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0 },
+ { AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0 },
+
+ /* store, short offset */
+ { AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ /* load, short offset */
+ { AMOVD, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVW, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB },
+ { AMOVD, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVW, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVWZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_NONE, C_REG, 9, 8, REGSP },
+ { AMOVD, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVW, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+
+ /* store, long offset */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ /* load, long offset */
+ { AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB },
+ { AMOVD, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVW, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVWZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVBZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_NONE, C_REG, 37, 12, REGSP },
+ { AMOVD, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVW, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVWZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVBZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_NONE, C_REG, 37, 12, REGZERO },
+ { AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0 },
+
+ /* load constant */
+ { AMOVD, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVD, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVD, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVD, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVD, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVW, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
+ { AMOVW, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVW, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVWZ, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
+ { AMOVWZ, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVWZ, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVWZ, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVWZ, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+
+ /* load unsigned/long constants (TO DO: check) */
+ { AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+ { ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
+ { ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
+
+ { ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
+ { ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB },
+ { AFMOVD, C_SAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP },
+ { AFMOVD, C_SOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO },
+
+ { AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB },
+ { AFMOVD, C_LAUTO,C_NONE, C_NONE, C_FREG, 36, 8, REGSP },
+ { AFMOVD, C_LOREG,C_NONE, C_NONE, C_FREG, 36, 8, REGZERO },
+ { AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0 },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ { ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0 },
+ { ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
+ { ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
+
+ { AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+ { AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+
+ { ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+ { ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0 },
+ { AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0 },
+ { AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
+ { AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
+
+ { AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0 },
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0 },
+
+ { AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0 }, /* mfmsr */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsrd */
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsr */
+
+ /* 64-bit special registers */
+ { AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ /* 32-bit special registers (gloss over sign-extension or not?) */
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0 },
+ { AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0 },
+ { AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
+ { AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+ { AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+
+ { ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0 },
+
+ { ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0 },
+
+ { AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0 },
+ { AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0 },
+
+ { ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0 },
+ { ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0 },
+
+ { ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0 },
+ { ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0 },
+
+ { AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+
+ { AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0 },
+ { ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0 },
+ { ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
+ { ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
+
+ { ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0 },
+
+ { AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0 },
+ { AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
+ { APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0 },
+
+ { ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
+ { ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
+
+ { ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
+
+static int ocmp(const void *, const void *);
+static int cmp(int, int);
+static void buildop(Link*);
+static void prasm(Prog *);
+static int isint32(vlong);
+static int isuint32(uvlong);
+static int aclass(Link*, Addr*);
+static Optab* oplook(Link*, Prog*);
+static void asmout(Link*, Prog*, Optab*, int32*);
+static vlong vregoff(Link*, Addr*);
+static int32 regoff(Link*, Addr*);
+static int32 oprrr(Link*, int);
+static int32 opirr(Link*, int);
+static int32 opload(Link*, int);
+static int32 opstore(Link*, int);
+static int32 oploadx(Link*, int);
+static int32 opstorex(Link*, int);
+static int getmask(uchar*, uint32);
+static void maskgen(Link*, Prog*, uchar*, uint32);
+static int getmask64(uchar*, uvlong);
+static void maskgen64(Link*, Prog*, uchar*, uvlong);
+static uint32 loadu32(int, vlong);
+static void addaddrreloc(Link*, LSym*, int*, int*);
+
+static struct
+{
+ Optab* start;
+ Optab* stop;
+} oprange[ALAST];
+
+static char xcmp[C_NCLASS][C_NCLASS];
+
+
+void
+span9(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q;
+ Optab *o;
+ int m, bflag;
+ vlong c, otxt;
+ int32 out[6], i, j;
+ uchar *bp, *cast;
+
+ p = cursym->text;
+ if(p == nil || p->link == nil) // handle external functions and ELF section symbols
+ return;
+ ctxt->cursym = cursym;
+ ctxt->autosize = (int32)(p->to.offset & 0xffffffffll) + 8;
+
+ if(oprange[AANDN].start == nil)
+ buildop(ctxt);
+
+ bflag = 0;
+ c = 0;
+ p->pc = c;
+
+ for(p = p->link; p != nil; p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt, p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ bflag = 1;
+ while(bflag) {
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = 0;
+ for(p = cursym->text->link; p != nil; p = p->link) {
+ p->pc = c;
+ o = oplook(ctxt, p);
+
+ // very large conditional branches
+ if((o->type == 16 || o->type == 17) && p->pcond) {
+ otxt = p->pcond->pc - c;
+ if(otxt < -(1L<<15)+10 || otxt >= (1L<<15)-10) {
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = ABR;
+ q->to.type = D_BRANCH;
+ q->pcond = p->pcond;
+ p->pcond = q;
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = ABR;
+ q->to.type = D_BRANCH;
+ q->pcond = q->link->link;
+ //addnop(p->link);
+ //addnop(p);
+ bflag = 1;
+ }
+ }
+
+ m = o->size;
+ if(m == 0) {
+ if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+ }
+
+ c += -c&(FuncAlign-1);
+ cursym->size = c;
+
+ /*
+ * lay out the code, emitting code and data relocations.
+ */
+ if(ctxt->tlsg == nil)
+ ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+
+ symgrow(ctxt, cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = cursym->text->link; p != nil; p = p->link) {
+ ctxt->pc = p->pc;
+ ctxt->curp = p;
+ o = oplook(ctxt, p);
+ if(o->size > 4*nelem(out))
+ sysfatal("out array in span9 is too small, need at least %d for %P", o->size/4, p);
+ asmout(ctxt, p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ cast = (uchar*)&out[i];
+ for(j=0; j<4; j++)
+ *bp++ = cast[inuxi4[j]];
+ }
+ }
+}
+
+static int
+isint32(vlong v)
+{
+ return (int32)v == v;
+}
+
+static int
+isuint32(uvlong v)
+{
+ return (uint32)v == v;
+}
+
+static int
+aclass(Link *ctxt, Addr *a)
+{
+ LSym *s;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_CREG:
+ return C_CREG;
+
+ case D_SPR:
+ if(a->offset == D_LR)
+ return C_LR;
+ if(a->offset == D_XER)
+ return C_XER;
+ if(a->offset == D_CTR)
+ return C_CTR;
+ return C_SPR;
+
+ case D_DCR:
+ return C_SPR;
+
+ case D_FPSCR:
+ return C_FPSCR;
+
+ case D_MSR:
+ return C_MSR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == nil)
+ break;
+ ctxt->instoffset = a->offset;
+ if(a->sym != nil) // use relocation
+ return C_ADDR;
+ return C_LEXT;
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 8L;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(ctxt->instoffset == 0)
+ return C_ZOREG;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_OPT:
+ ctxt->instoffset = a->offset & 31L;
+ if(a->name == D_NONE)
+ return C_SCON;
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(a->reg != NREG) {
+ if(-BIG <= ctxt->instoffset && ctxt->instoffset <= BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ consize:
+ if(ctxt->instoffset >= 0) {
+ if(ctxt->instoffset == 0)
+ return C_ZCON;
+ if(ctxt->instoffset <= 0x7fff)
+ return C_SCON;
+ if(ctxt->instoffset <= 0xffff)
+ return C_ANDCON;
+ if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
+ return C_UCON;
+ if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
+ return C_LCON;
+ return C_DCON;
+ }
+ if(ctxt->instoffset >= -0x8000)
+ return C_ADDCON;
+ if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
+ return C_UCON;
+ if(isint32(ctxt->instoffset))
+ return C_LCON;
+ return C_DCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == nil)
+ break;
+ if(s->type == SCONST) {
+ ctxt->instoffset = s->value + a->offset;
+ goto consize;
+ }
+ ctxt->instoffset = s->value + a->offset;
+ /* not sure why this barfs */
+ return C_LCON;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 8L;
+ if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+static void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, Prog *p)
+{
+ int a1, a2, a3, a4, r;
+ char *c1, *c3, *c4;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(ctxt, &p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->from3.class;
+ if(a3 == 0) {
+ a3 = aclass(ctxt, &p->from3) + 1;
+ p->from3.class = a3;
+ }
+ a3--;
+ a4 = p->to.class;
+ if(a4 == 0) {
+ a4 = aclass(ctxt, &p->to) + 1;
+ p->to.class = a4;
+ }
+ a4--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+//print("oplook %P %d %d %d %d\n", p, a1, a2, a3, a4);
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0)
+ o = oprange[r].stop; /* just generate an error */
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ c4 = xcmp[a4];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3])
+ if(c4[o->a4]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ ctxt->diag("illegal combination %A %^ %^ %^ %^",
+ p->as, a1, a2, a3, a4);
+ prasm(p);
+ if(o == 0)
+ o = optab;
+ return o;
+}
+
+static int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_SPR:
+ if(b == C_LR || b == C_XER || b == C_CTR)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return r0iszero;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+
+ case C_ANY:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ocmp(const void *a1, const void *a2)
+{
+ const Optab *p1, *p2;
+ int n;
+
+ p1 = a1;
+ p2 = a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ n = p1->a4 - p2->a4;
+ if(n)
+ return n;
+ return 0;
+}
+
+static void
+buildop(Link *ctxt)
+{
+ int i, n, r;
+
+ for(i=0; i<C_NCLASS; i++)
+ for(n=0; n<C_NCLASS; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ ctxt->diag("unknown op in build: %A", r);
+ sysfatal("bad code");
+ case ADCBF: /* unary indexed: op (b+a); op (b) */
+ oprange[ADCBI] = oprange[r];
+ oprange[ADCBST] = oprange[r];
+ oprange[ADCBT] = oprange[r];
+ oprange[ADCBTST] = oprange[r];
+ oprange[ADCBZ] = oprange[r];
+ oprange[AICBI] = oprange[r];
+ break;
+ case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
+ oprange[ASTWCCC] = oprange[r];
+ oprange[ASTDCCC] = oprange[r];
+ break;
+ case AREM: /* macro */
+ oprange[AREMCC] = oprange[r];
+ oprange[AREMV] = oprange[r];
+ oprange[AREMVCC] = oprange[r];
+ oprange[AREMU] = oprange[r];
+ oprange[AREMUCC] = oprange[r];
+ oprange[AREMUV] = oprange[r];
+ oprange[AREMUVCC] = oprange[r];
+ break;
+ case AREMD:
+ oprange[AREMDCC] = oprange[r];
+ oprange[AREMDV] = oprange[r];
+ oprange[AREMDVCC] = oprange[r];
+ oprange[AREMDU] = oprange[r];
+ oprange[AREMDUCC] = oprange[r];
+ oprange[AREMDUV] = oprange[r];
+ oprange[AREMDUVCC] = oprange[r];
+ break;
+ case ADIVW: /* op Rb[,Ra],Rd */
+ oprange[AMULHW] = oprange[r];
+ oprange[AMULHWCC] = oprange[r];
+ oprange[AMULHWU] = oprange[r];
+ oprange[AMULHWUCC] = oprange[r];
+ oprange[AMULLWCC] = oprange[r];
+ oprange[AMULLWVCC] = oprange[r];
+ oprange[AMULLWV] = oprange[r];
+ oprange[ADIVWCC] = oprange[r];
+ oprange[ADIVWV] = oprange[r];
+ oprange[ADIVWVCC] = oprange[r];
+ oprange[ADIVWU] = oprange[r];
+ oprange[ADIVWUCC] = oprange[r];
+ oprange[ADIVWUV] = oprange[r];
+ oprange[ADIVWUVCC] = oprange[r];
+ oprange[AADDCC] = oprange[r];
+ oprange[AADDCV] = oprange[r];
+ oprange[AADDCVCC] = oprange[r];
+ oprange[AADDV] = oprange[r];
+ oprange[AADDVCC] = oprange[r];
+ oprange[AADDE] = oprange[r];
+ oprange[AADDECC] = oprange[r];
+ oprange[AADDEV] = oprange[r];
+ oprange[AADDEVCC] = oprange[r];
+ oprange[ACRAND] = oprange[r];
+ oprange[ACRANDN] = oprange[r];
+ oprange[ACREQV] = oprange[r];
+ oprange[ACRNAND] = oprange[r];
+ oprange[ACRNOR] = oprange[r];
+ oprange[ACROR] = oprange[r];
+ oprange[ACRORN] = oprange[r];
+ oprange[ACRXOR] = oprange[r];
+ oprange[AMULHD] = oprange[r];
+ oprange[AMULHDCC] = oprange[r];
+ oprange[AMULHDU] = oprange[r];
+ oprange[AMULHDUCC] = oprange[r];
+ oprange[AMULLD] = oprange[r];
+ oprange[AMULLDCC] = oprange[r];
+ oprange[AMULLDVCC] = oprange[r];
+ oprange[AMULLDV] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[ADIVDCC] = oprange[r];
+ oprange[ADIVDVCC] = oprange[r];
+ oprange[ADIVDV] = oprange[r];
+ oprange[ADIVDU] = oprange[r];
+ oprange[ADIVDUCC] = oprange[r];
+ oprange[ADIVDUVCC] = oprange[r];
+ oprange[ADIVDUCC] = oprange[r];
+ break;
+ case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
+ oprange[AMOVH] = oprange[r];
+ oprange[AMOVHZ] = oprange[r];
+ break;
+ case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x, ld[x]u, std[u]x */
+ oprange[AMOVHU] = oprange[r];
+ oprange[AMOVHZU] = oprange[r];
+ oprange[AMOVWU] = oprange[r];
+ oprange[AMOVWZU] = oprange[r];
+ oprange[AMOVDU] = oprange[r];
+ oprange[AMOVMW] = oprange[r];
+ break;
+ case AAND: /* logical op Rb,Rs,Ra; no literal */
+ oprange[AANDN] = oprange[r];
+ oprange[AANDNCC] = oprange[r];
+ oprange[AEQV] = oprange[r];
+ oprange[AEQVCC] = oprange[r];
+ oprange[ANAND] = oprange[r];
+ oprange[ANANDCC] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ oprange[ANORCC] = oprange[r];
+ oprange[AORCC] = oprange[r];
+ oprange[AORN] = oprange[r];
+ oprange[AORNCC] = oprange[r];
+ oprange[AXORCC] = oprange[r];
+ break;
+ case AADDME: /* op Ra, Rd */
+ oprange[AADDMECC] = oprange[r];
+ oprange[AADDMEV] = oprange[r];
+ oprange[AADDMEVCC] = oprange[r];
+ oprange[AADDZE] = oprange[r];
+ oprange[AADDZECC] = oprange[r];
+ oprange[AADDZEV] = oprange[r];
+ oprange[AADDZEVCC] = oprange[r];
+ oprange[ASUBME] = oprange[r];
+ oprange[ASUBMECC] = oprange[r];
+ oprange[ASUBMEV] = oprange[r];
+ oprange[ASUBMEVCC] = oprange[r];
+ oprange[ASUBZE] = oprange[r];
+ oprange[ASUBZECC] = oprange[r];
+ oprange[ASUBZEV] = oprange[r];
+ oprange[ASUBZEVCC] = oprange[r];
+ break;
+ case AADDC:
+ oprange[AADDCCC] = oprange[r];
+ break;
+ case ABEQ:
+ oprange[ABGE] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABNE] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ break;
+ case ABR:
+ oprange[ABL] = oprange[r];
+ break;
+ case ABC:
+ oprange[ABCL] = oprange[r];
+ break;
+ case AEXTSB: /* op Rs, Ra */
+ oprange[AEXTSBCC] = oprange[r];
+ oprange[AEXTSH] = oprange[r];
+ oprange[AEXTSHCC] = oprange[r];
+ oprange[ACNTLZW] = oprange[r];
+ oprange[ACNTLZWCC] = oprange[r];
+ oprange[ACNTLZD] = oprange[r];
+ oprange[AEXTSW] = oprange[r];
+ oprange[AEXTSWCC] = oprange[r];
+ oprange[ACNTLZDCC] = oprange[r];
+ break;
+ case AFABS: /* fop [s,]d */
+ oprange[AFABSCC] = oprange[r];
+ oprange[AFNABS] = oprange[r];
+ oprange[AFNABSCC] = oprange[r];
+ oprange[AFNEG] = oprange[r];
+ oprange[AFNEGCC] = oprange[r];
+ oprange[AFRSP] = oprange[r];
+ oprange[AFRSPCC] = oprange[r];
+ oprange[AFCTIW] = oprange[r];
+ oprange[AFCTIWCC] = oprange[r];
+ oprange[AFCTIWZ] = oprange[r];
+ oprange[AFCTIWZCC] = oprange[r];
+ oprange[AFCTID] = oprange[r];
+ oprange[AFCTIDCC] = oprange[r];
+ oprange[AFCTIDZ] = oprange[r];
+ oprange[AFCTIDZCC] = oprange[r];
+ oprange[AFCFID] = oprange[r];
+ oprange[AFCFIDCC] = oprange[r];
+ oprange[AFRES] = oprange[r];
+ oprange[AFRESCC] = oprange[r];
+ oprange[AFRSQRTE] = oprange[r];
+ oprange[AFRSQRTECC] = oprange[r];
+ oprange[AFSQRT] = oprange[r];
+ oprange[AFSQRTCC] = oprange[r];
+ oprange[AFSQRTS] = oprange[r];
+ oprange[AFSQRTSCC] = oprange[r];
+ break;
+ case AFADD:
+ oprange[AFADDS] = oprange[r];
+ oprange[AFADDCC] = oprange[r];
+ oprange[AFADDSCC] = oprange[r];
+ oprange[AFDIV] = oprange[r];
+ oprange[AFDIVS] = oprange[r];
+ oprange[AFDIVCC] = oprange[r];
+ oprange[AFDIVSCC] = oprange[r];
+ oprange[AFSUB] = oprange[r];
+ oprange[AFSUBS] = oprange[r];
+ oprange[AFSUBCC] = oprange[r];
+ oprange[AFSUBSCC] = oprange[r];
+ break;
+ case AFMADD:
+ oprange[AFMADDCC] = oprange[r];
+ oprange[AFMADDS] = oprange[r];
+ oprange[AFMADDSCC] = oprange[r];
+ oprange[AFMSUB] = oprange[r];
+ oprange[AFMSUBCC] = oprange[r];
+ oprange[AFMSUBS] = oprange[r];
+ oprange[AFMSUBSCC] = oprange[r];
+ oprange[AFNMADD] = oprange[r];
+ oprange[AFNMADDCC] = oprange[r];
+ oprange[AFNMADDS] = oprange[r];
+ oprange[AFNMADDSCC] = oprange[r];
+ oprange[AFNMSUB] = oprange[r];
+ oprange[AFNMSUBCC] = oprange[r];
+ oprange[AFNMSUBS] = oprange[r];
+ oprange[AFNMSUBSCC] = oprange[r];
+ oprange[AFSEL] = oprange[r];
+ oprange[AFSELCC] = oprange[r];
+ break;
+ case AFMUL:
+ oprange[AFMULS] = oprange[r];
+ oprange[AFMULCC] = oprange[r];
+ oprange[AFMULSCC] = oprange[r];
+ break;
+ case AFCMPO:
+ oprange[AFCMPU] = oprange[r];
+ break;
+ case AMTFSB0:
+ oprange[AMTFSB0CC] = oprange[r];
+ oprange[AMTFSB1] = oprange[r];
+ oprange[AMTFSB1CC] = oprange[r];
+ break;
+ case ANEG: /* op [Ra,] Rd */
+ oprange[ANEGCC] = oprange[r];
+ oprange[ANEGV] = oprange[r];
+ oprange[ANEGVCC] = oprange[r];
+ break;
+ case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
+ oprange[AXOR] = oprange[r];
+ break;
+ case ASLW:
+ oprange[ASLWCC] = oprange[r];
+ oprange[ASRW] = oprange[r];
+ oprange[ASRWCC] = oprange[r];
+ break;
+ case ASLD:
+ oprange[ASLDCC] = oprange[r];
+ oprange[ASRD] = oprange[r];
+ oprange[ASRDCC] = oprange[r];
+ break;
+ case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+ oprange[ASRAWCC] = oprange[r];
+ break;
+ case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+ oprange[ASRADCC] = oprange[r];
+ break;
+ case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
+ oprange[ASUB] = oprange[r];
+ oprange[ASUBCC] = oprange[r];
+ oprange[ASUBV] = oprange[r];
+ oprange[ASUBVCC] = oprange[r];
+ oprange[ASUBCCC] = oprange[r];
+ oprange[ASUBCV] = oprange[r];
+ oprange[ASUBCVCC] = oprange[r];
+ oprange[ASUBE] = oprange[r];
+ oprange[ASUBECC] = oprange[r];
+ oprange[ASUBEV] = oprange[r];
+ oprange[ASUBEVCC] = oprange[r];
+ break;
+ case ASYNC:
+ oprange[AISYNC] = oprange[r];
+ oprange[APTESYNC] = oprange[r];
+ oprange[ATLBSYNC] = oprange[r];
+ break;
+ case ARLWMI:
+ oprange[ARLWMICC] = oprange[r];
+ oprange[ARLWNM] = oprange[r];
+ oprange[ARLWNMCC] = oprange[r];
+ break;
+ case ARLDMI:
+ oprange[ARLDMICC] = oprange[r];
+ break;
+ case ARLDC:
+ oprange[ARLDCCC] = oprange[r];
+ break;
+ case ARLDCL:
+ oprange[ARLDCR] = oprange[r];
+ oprange[ARLDCLCC] = oprange[r];
+ oprange[ARLDCRCC] = oprange[r];
+ break;
+ case AFMOVD:
+ oprange[AFMOVDCC] = oprange[r];
+ oprange[AFMOVDU] = oprange[r];
+ oprange[AFMOVS] = oprange[r];
+ oprange[AFMOVSU] = oprange[r];
+ break;
+ case AECIWX:
+ oprange[ALWAR] = oprange[r];
+ oprange[ALDAR] = oprange[r];
+ break;
+ case ASYSCALL: /* just the op; flow of control */
+ oprange[ARFI] = oprange[r];
+ oprange[ARFCI] = oprange[r];
+ oprange[ARFID] = oprange[r];
+ oprange[AHRFID] = oprange[r];
+ break;
+ case AMOVHBR:
+ oprange[AMOVWBR] = oprange[r];
+ break;
+ case ASLBMFEE:
+ oprange[ASLBMFEV] = oprange[r];
+ break;
+ case ATW:
+ oprange[ATD] = oprange[r];
+ break;
+ case ATLBIE:
+ oprange[ASLBIE] = oprange[r];
+ oprange[ATLBIEL] = oprange[r];
+ break;
+ case AEIEIO:
+ oprange[ASLBIA] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ACMPW] = oprange[r];
+ break;
+ case ACMPU:
+ oprange[ACMPWU] = oprange[r];
+ break;
+ case AADD:
+ case AANDCC: /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+ case ALSW:
+ case AMOVW: /* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
+ case AMOVWZ: /* load/store/move word with zero extension; move 32-bit literals */
+ case AMOVD: /* load/store/move 64-bit values, including 32-bit literals with/without sign-extension */
+ case AMOVB: /* macro: move byte with sign extension */
+ case AMOVBU: /* macro: move byte with sign extension & update */
+ case AMOVFL:
+ case AMULLW: /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
+ case ASUBC: /* op r1,$s,r3; op r1[,r2],r3 */
+ case ASTSW:
+ case ASLBMTE:
+ case AWORD:
+ case ADWORD:
+ case ANOP:
+ case ATEXT:
+ case AUNDEF:
+ case AUSEFIELD:
+ case AFUNCDATA:
+ case APCDATA:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ break;
+ }
+ }
+}
+
+#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))
+#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))
+#define OP(o,xo) OPVCC((o),(xo),0,0)
+
+/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
+#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))
+#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))
+#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))
+#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))
+#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))
+#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+
+#define OP_ADD OPVCC(31,266,0,0)
+#define OP_ADDI OPVCC(14,0,0,0)
+#define OP_ADDIS OPVCC(15,0,0,0)
+#define OP_ANDI OPVCC(28,0,0,0)
+#define OP_EXTSB OPVCC(31,954,0,0)
+#define OP_EXTSH OPVCC(31,922,0,0)
+#define OP_EXTSW OPVCC(31,986,0,0)
+#define OP_MCRF OPVCC(19,0,0,0)
+#define OP_MCRFS OPVCC(63,64,0,0)
+#define OP_MCRXR OPVCC(31,512,0,0)
+#define OP_MFCR OPVCC(31,19,0,0)
+#define OP_MFFS OPVCC(63,583,0,0)
+#define OP_MFMSR OPVCC(31,83,0,0)
+#define OP_MFSPR OPVCC(31,339,0,0)
+#define OP_MFSR OPVCC(31,595,0,0)
+#define OP_MFSRIN OPVCC(31,659,0,0)
+#define OP_MTCRF OPVCC(31,144,0,0)
+#define OP_MTFSF OPVCC(63,711,0,0)
+#define OP_MTFSFI OPVCC(63,134,0,0)
+#define OP_MTMSR OPVCC(31,146,0,0)
+#define OP_MTMSRD OPVCC(31,178,0,0)
+#define OP_MTSPR OPVCC(31,467,0,0)
+#define OP_MTSR OPVCC(31,210,0,0)
+#define OP_MTSRIN OPVCC(31,242,0,0)
+#define OP_MULLW OPVCC(31,235,0,0)
+#define OP_MULLD OPVCC(31,233,0,0)
+#define OP_OR OPVCC(31,444,0,0)
+#define OP_ORI OPVCC(24,0,0,0)
+#define OP_ORIS OPVCC(25,0,0,0)
+#define OP_RLWINM OPVCC(21,0,0,0)
+#define OP_SUBF OPVCC(31,40,0,0)
+#define OP_RLDIC OPVCC(30,4,0,0)
+#define OP_RLDICR OPVCC(30,2,0,0)
+#define OP_RLDICL OPVCC(30,0,0,0)
+
+#define oclass(v) ((v).class-1)
+
+// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
+static void
+addaddrreloc(Link *ctxt, LSym *s, int *o1, int *o2)
+{
+ Reloc *rel;
+
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 8;
+ rel->sym = s;
+ rel->add = ((uvlong)*o1<<32) | (uint32)*o2;
+ rel->type = R_ADDRPOWER;
+}
+
+/*
+ * 32-bit masks
+ */
+static int
+getmask(uchar *m, uint32 v)
+{
+ int i;
+
+ m[0] = m[1] = 0;
+ if(v != ~0U && v & (1<<31) && v & 1){ /* MB > ME */
+ if(getmask(m, ~v)){
+ i = m[0]; m[0] = m[1]+1; m[1] = i-1;
+ return 1;
+ }
+ return 0;
+ }
+ for(i=0; i<32; i++)
+ if(v & (1<<(31-i))){
+ m[0] = i;
+ do {
+ m[1] = i;
+ } while(++i<32 && (v & (1<<(31-i))) != 0);
+ for(; i<32; i++)
+ if(v & (1<<(31-i)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+maskgen(Link *ctxt, Prog *p, uchar *m, uint32 v)
+{
+ if(!getmask(m, v))
+ ctxt->diag("cannot generate mask #%lux\n%P", v, p);
+}
+
+/*
+ * 64-bit masks (rldic etc)
+ */
+static int
+getmask64(uchar *m, uvlong v)
+{
+ int i;
+
+ m[0] = m[1] = 0;
+ for(i=0; i<64; i++)
+ if(v & ((uvlong)1<<(63-i))){
+ m[0] = i;
+ do {
+ m[1] = i;
+ } while(++i<64 && (v & ((uvlong)1<<(63-i))) != 0);
+ for(; i<64; i++)
+ if(v & ((uvlong)1<<(63-i)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+maskgen64(Link *ctxt, Prog *p, uchar *m, uvlong v)
+{
+ if(!getmask64(m, v))
+ ctxt->diag("cannot generate mask #%llux\n%P", v, p);
+}
+
+static uint32
+loadu32(int r, vlong d)
+{
+ int32 v;
+
+ v = d>>16;
+ if(isuint32(d))
+ return LOP_IRR(OP_ORIS, r, REGZERO, v);
+ return AOP_IRR(OP_ADDIS, r, REGZERO, v);
+}
+
+static uint16
+high16adjusted(int32 d)
+{
+ if(d & 0x8000)
+ return (d>>16) + 1;
+ return d>>16;
+}
+
+static void
+asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
+{
+ int32 o1, o2, o3, o4, o5, v, t;
+ vlong d;
+ int r, a;
+ uchar mask[2];
+ Reloc *rel;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+
+//print("%P => case %d\n", p, o->type);
+ switch(o->type) {
+ default:
+ ctxt->diag("unknown type %d", o->type);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ break;
+
+ case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
+ if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+ v = regoff(ctxt, &p->from);
+ if(r0iszero && v != 0) {
+ //nerrors--;
+ ctxt->diag("literal operation on R0\n%P", p);
+ }
+ o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
+ break;
+ }
+ o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg);
+ break;
+
+ case 2: /* int/cr/fp op Rb,[Ra],Rd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
+ d = vregoff(ctxt, &p->from);
+ v = d;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0))
+ ctxt->diag("literal operation on R0\n%P", p);
+ a = OP_ADDI;
+ if(o->a1 == C_UCON) {
+ if((d&0xffff) != 0)
+ sysfatal("invalid handling of %P", p);
+ v >>= 16;
+ if(r == REGZERO && isuint32(d)){
+ o1 = LOP_IRR(OP_ORIS, p->to.reg, REGZERO, v);
+ break;
+ }
+ a = OP_ADDIS;
+ } else {
+ if((int16)d != d)
+ sysfatal("invalid handling of %P", p);
+ }
+ o1 = AOP_IRR(a, p->to.reg, r, v);
+ break;
+
+ case 4: /* add/mul $scon,[r1],r2 */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(r0iszero && p->to.reg == 0)
+ ctxt->diag("literal operation on R0\n%P", p);
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 5: /* syscall */
+ o1 = oprrr(ctxt, p->as);
+ break;
+
+ case 6: /* logical op Rb,[Rs,]Ra; no literal */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 7: /* mov r, soreg ==> stw o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(ctxt, &p->to);
+ if(p->to.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, p->reg, r);
+ } else {
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, r, v);
+ }
+ break;
+
+ case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(ctxt, &p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
+ } else {
+ if((int16)v != v)
+ sysfatal("mishandled instruction %P", p);
+ o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
+ }
+ break;
+
+ case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(ctxt, &p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ ctxt->diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
+ } else
+ o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
+ o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, r);
+ break;
+
+ case 11: /* br/bl lbra */
+ v = 0;
+ if(p->pcond) {
+ v = p->pcond->pc - p->pc;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<25) || v >= (1L<<24))
+ ctxt->diag("branch too far\n%P", p);
+ }
+ o1 = OP_BR(opirr(ctxt, p->as), v, 0);
+ if(p->to.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ v += p->to.offset;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ rel->add = o1 | (v & 0x03FFFFFC);
+ rel->type = R_CALLPOWER;
+ }
+ break;
+
+ case 12: /* movb r,r (extsb); movw r,r (extsw) */
+ if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+ v = regoff(ctxt, &p->from);
+ if(r0iszero && v != 0) {
+ ctxt->diag("literal operation on R0\n%P", p);
+ }
+ o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
+ break;
+ }
+ if(p->as == AMOVW)
+ o1 = LOP_RRR(OP_EXTSW, p->to.reg, p->from.reg, 0);
+ else
+ o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0);
+ break;
+
+ case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */
+ if(p->as == AMOVBZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31);
+ else if(p->as == AMOVH)
+ o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0);
+ else if(p->as == AMOVHZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31);
+ else if(p->as == AMOVWZ)
+ o1 = OP_RLW(OP_RLDIC, p->to.reg, p->from.reg, 0, 0, 0) | (1<<5); /* MB=32 */
+ else
+ ctxt->diag("internal: bad mov[bhw]z\n%P", p);
+ break;
+
+ case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ switch(p->as){
+ case ARLDCL: case ARLDCLCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != 63)
+ ctxt->diag("invalid mask for rotate: %llux (end != bit 63)\n%P", d, p);
+ break;
+ case ARLDCR: case ARLDCRCC:
+ a = mask[1]; /* ME */
+ if(mask[0] != 0)
+ ctxt->diag("invalid mask for rotate: %llux (start != 0)\n%P", d, p);
+ break;
+ default:
+ ctxt->diag("unexpected op in rldc case\n%P", p);
+ a = 0;
+ }
+ o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
+ o1 |= (a&31L)<<6;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 17: /* bc bo,bi,lbra (same for now) */
+ case 16: /* bc bo,bi,sbra */
+ a = 0;
+ if(p->from.type == D_CONST)
+ a = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ v = 0;
+ if(p->pcond)
+ v = p->pcond->pc - p->pc;
+ if(v & 03) {
+ ctxt->diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<16) || v >= (1L<<15))
+ ctxt->diag("branch too far\n%P", p);
+ o1 = OP_BC(opirr(ctxt, p->as), a, r, v, 0);
+ break;
+
+ case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(ctxt, &p->to)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11);
+ o2 = OPVCC(19, 16, 0, 0);
+ if(p->as == ABL || p->as == ABCL)
+ o2 |= 1;
+ o2 = OP_BCR(o2, v, r);
+ break;
+
+ case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(ctxt, &p->from)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ switch(oclass(p->to)) {
+ case C_CTR:
+ o1 = OPVCC(19, 528, 0, 0);
+ break;
+ case C_LR:
+ o1 = OPVCC(19, 16, 0, 0);
+ break;
+ default:
+ ctxt->diag("bad optab entry (18): %d\n%P", p->to.class, p);
+ v = 0;
+ }
+ if(p->as == ABL || p->as == ABCL)
+ o1 |= 1;
+ o1 = OP_BCR(o1, v, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> cau+or */
+ d = vregoff(ctxt, &p->from);
+ if(p->from.sym == nil) {
+ o1 = loadu32(p->to.reg, d);
+ o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (int32)d);
+ } else {
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(d));
+ o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, d);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ }
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+
+ case 20: /* add $ucon,,r */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0))
+ ctxt->diag("literal operation on R0\n%P", p);
+ o1 = AOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16);
+ break;
+
+ case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ ctxt->diag("cant synthesize large constant\n%P", p);
+ d = vregoff(ctxt, &p->from);
+ o1 = loadu32(REGTMP, d);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+
+ case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ ctxt->diag("cant synthesize large constant\n%P", p);
+ d = vregoff(ctxt, &p->from);
+ o1 = loadu32(REGTMP, d);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from, p->pc, 0);
+ break;
+/*24*/
+
+ case 25: /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
+ v = regoff(ctxt, &p->from);
+ if(v < 0)
+ v = 0;
+ else if(v > 63)
+ v = 63;
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ switch(p->as){
+ case ASLD: case ASLDCC:
+ a = 63-v;
+ o1 = OP_RLDICR;
+ break;
+ case ASRD: case ASRDCC:
+ a = v;
+ v = 64-v;
+ o1 = OP_RLDICL;
+ break;
+ default:
+ ctxt->diag("unexpected op in sldi case\n%P", p);
+ a = 0;
+ o1 = 0;
+ }
+ o1 = AOP_RRR(o1, r, p->to.reg, (v&0x1F));
+ o1 |= (a&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ if(p->as == ASLDCC || p->as == ASRDCC)
+ o1 |= 1; /* Rc */
+ break;
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
+ if(p->to.reg == REGTMP)
+ ctxt->diag("can't synthesize large constant\n%P", p);
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v);
+ break;
+
+ case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
+ v = regoff(ctxt, &p->from3);
+ r = p->from.reg;
+ o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
+ if(p->to.reg == REGTMP || p->from.reg == REGTMP)
+ ctxt->diag("can't synthesize large constant\n%P", p);
+ v = regoff(ctxt, &p->from3);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
+ o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, REGTMP);
+ if(p->from.sym != nil)
+ ctxt->diag("%P is not supported", p);
+ //if(dlm) reloc(&p->from3, p->pc, 0);
+ break;
+
+ case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
+ v = regoff(ctxt, &p->from);
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ switch(p->as){
+ case ARLDC: case ARLDCCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != (63-v))
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ case ARLDCL: case ARLDCLCC:
+ a = mask[0]; /* MB */
+ if(mask[1] != 63)
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ case ARLDCR: case ARLDCRCC:
+ a = mask[1]; /* ME */
+ if(mask[0] != 0)
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ break;
+ default:
+ ctxt->diag("unexpected op in rldic case\n%P", p);
+ a = 0;
+ }
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
+ o1 |= (a&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(a & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 30: /* rldimi $sh,s,$mask,a */
+ v = regoff(ctxt, &p->from);
+ d = vregoff(ctxt, &p->from3);
+ maskgen64(ctxt, p, mask, d);
+ if(mask[1] != (63-v))
+ ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
+ o1 |= (mask[0]&31L)<<6;
+ if(v & 0x20)
+ o1 |= 1<<1;
+ if(mask[0] & 0x20)
+ o1 |= 1<<5; /* mb[5] is top bit */
+ break;
+
+ case 31: /* dword */
+ d = vregoff(ctxt, &p->from);
+ if(ctxt->arch->endian == BigEndian) {
+ o1 = d>>32;
+ o2 = d;
+ } else {
+ o1 = d;
+ o2 = d>>32;
+ }
+ if(p->from.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 8;
+ rel->sym = p->from.sym;
+ rel->add = p->from.offset;
+ rel->type = R_ADDR;
+ o1 = o2 = 0;
+ }
+ break;
+
+ case 32: /* fmul frc,fra,frd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6);
+ break;
+
+ case 33: /* fabs [frb,]frd; fmr. frb,frd */
+ r = p->from.reg;
+ if(oclass(p->from) == C_NONE)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, r);
+ break;
+
+ case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c); FSELx a<0? (d=b): (d=c) */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, p->reg)|((p->from3.reg&31L)<<6);
+ break;
+
+ case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
+ v = regoff(ctxt, &p->to);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
+ break;
+
+ case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ break;
+
+ case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
+ v = regoff(ctxt, &p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 40: /* word */
+ o1 = regoff(ctxt, &p->from);
+ break;
+
+ case 41: /* stswi */
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->from.reg, p->to.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
+ break;
+
+ case 42: /* lswi */
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->to.reg, p->from.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
+ break;
+
+ case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), 0, r, p->from.reg);
+ break;
+
+ case 44: /* indexed store */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, r, p->to.reg);
+ break;
+ case 45: /* indexed load */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 46: /* plain op */
+ o1 = oprrr(ctxt, p->as);
+ break;
+
+ case 47: /* op Ra, Rd; also op [Ra,] Rd */
+ r = p->from.reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
+ break;
+
+ case 48: /* op Rs, Ra */
+ r = p->from.reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
+ break;
+
+ case 49: /* op Rb; op $n, Rb */
+ if(p->from.type != D_REG){ /* tlbie $L, rB */
+ v = regoff(ctxt, &p->from) & 1;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->to.reg) | (v<<21);
+ }else
+ o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->from.reg);
+ break;
+
+ case 50: /* rem[u] r1[,r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ v = oprrr(ctxt, p->as);
+ t = v & ((1<<10)|1); /* OE|Rc */
+ o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
+ o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, p->from.reg);
+ o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
+ break;
+
+ case 51: /* remd[u] r1[,r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ v = oprrr(ctxt, p->as);
+ t = v & ((1<<10)|1); /* OE|Rc */
+ o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
+ o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, p->from.reg);
+ o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
+ break;
+
+ case 52: /* mtfsbNx cr(n) */
+ v = regoff(ctxt, &p->from)&31L;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), v, 0, 0);
+ break;
+
+ case 53: /* mffsX ,fr1 */
+ o1 = AOP_RRR(OP_MFFS, p->to.reg, 0, 0);
+ break;
+
+ case 54: /* mov msr,r1; mov r1, msr*/
+ if(oclass(p->from) == C_REG){
+ if(p->as == AMOVD)
+ o1 = AOP_RRR(OP_MTMSRD, p->from.reg, 0, 0);
+ else
+ o1 = AOP_RRR(OP_MTMSR, p->from.reg, 0, 0);
+ }else
+ o1 = AOP_RRR(OP_MFMSR, p->to.reg, 0, 0);
+ break;
+
+ case 55: /* op Rb, Rd */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, p->from.reg);
+ break;
+
+ case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(opirr(ctxt, p->as), r, p->to.reg, v&31L);
+ if(p->as == ASRAD && (v&0x20))
+ o1 |= 1<<1; /* mb[5] */
+ break;
+
+ case 57: /* slw $sh,[s,]a -> rlwinm ... */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ /*
+ * Let user (gs) shoot himself in the foot.
+ * qc has already complained.
+ *
+ if(v < 0 || v > 31)
+ ctxt->diag("illegal shift %ld\n%P", v, p);
+ */
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(p->as == ASRW || p->as == ASRWCC) { /* shift right */
+ mask[0] = v;
+ mask[1] = 31;
+ v = 32-v;
+ } else {
+ mask[0] = 0;
+ mask[1] = 31-v;
+ }
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, r, v, mask[0], mask[1]);
+ if(p->as == ASLWCC || p->as == ASRWCC)
+ o1 |= 1; /* Rc */
+ break;
+
+ case 58: /* logical $andcon,[s],a */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
+ break;
+
+ case 59: /* or/and $ucon,,r */
+ v = regoff(ctxt, &p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16); /* oris, xoris, andis */
+ break;
+
+ case 60: /* tw to,a,b */
+ r = regoff(ctxt, &p->from)&31L;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->reg, p->to.reg);
+ break;
+
+ case 61: /* tw to,a,$simm */
+ r = regoff(ctxt, &p->from)&31L;
+ v = regoff(ctxt, &p->to);
+ o1 = AOP_IRR(opirr(ctxt, p->as), r, p->reg, v);
+ break;
+
+ case 62: /* rlwmi $sh,s,$mask,a */
+ v = regoff(ctxt, &p->from);
+ maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, v);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 63: /* rlwmi b,s,$mask,a */
+ maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
+ o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, p->from.reg);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 64: /* mtfsf fr[, $m] {,fpcsr} */
+ if(p->from3.type != D_NONE)
+ v = regoff(ctxt, &p->from3)&255L;
+ else
+ v = 255;
+ o1 = OP_MTFSF | (v<<17) | (p->from.reg<<11);
+ break;
+
+ case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
+ if(p->to.reg == NREG)
+ ctxt->diag("must specify FPSCR(n)\n%P", p);
+ o1 = OP_MTFSFI | ((p->to.reg&15L)<<23) | ((regoff(ctxt, &p->from)&31L)<<12);
+ break;
+
+ case 66: /* mov spr,r1; mov r1,spr, also dcr */
+ if(p->from.type == D_REG) {
+ r = p->from.reg;
+ v = p->to.offset;
+ if(p->to.type == D_DCR)
+ o1 = OPVCC(31,451,0,0); /* mtdcr */
+ else
+ o1 = OPVCC(31,467,0,0); /* mtspr */
+ } else {
+ r = p->to.reg;
+ v = p->from.offset;
+ if(p->from.type == D_DCR)
+ o1 = OPVCC(31,323,0,0); /* mfdcr */
+ else
+ o1 = OPVCC(31,339,0,0); /* mfspr */
+ }
+ o1 = AOP_RRR(o1, r, 0, 0) | ((v&0x1f)<<16) | (((v>>5)&0x1f)<<11);
+ break;
+
+ case 67: /* mcrf crfD,crfS */
+ if(p->from.type != D_CREG || p->from.reg == NREG ||
+ p->to.type != D_CREG || p->to.reg == NREG)
+ ctxt->diag("illegal CR field number\n%P", p);
+ o1 = AOP_RRR(OP_MCRF, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
+ break;
+
+ case 68: /* mfcr rD; mfocrf CRM,rD */
+ if(p->from.type == D_CREG && p->from.reg != NREG){
+ v = 1<<(7-(p->to.reg&7)); /* CR(n) */
+ o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0) | (1<<20) | (v<<12); /* new form, mfocrf */
+ }else
+ o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0); /* old form, whole register */
+ break;
+
+ case 69: /* mtcrf CRM,rS */
+ if(p->from3.type != D_NONE) {
+ if(p->to.reg != NREG)
+ ctxt->diag("can't use both mask and CR(n)\n%P", p);
+ v = regoff(ctxt, &p->from3) & 0xff;
+ } else {
+ if(p->to.reg == NREG)
+ v = 0xff; /* CR */
+ else
+ v = 1<<(7-(p->to.reg&7)); /* CR(n) */
+ }
+ o1 = AOP_RRR(OP_MTCRF, p->from.reg, 0, 0) | (v<<12);
+ break;
+
+ case 70: /* [f]cmp r,r,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 71: /* cmp[l] r,i,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(opirr(ctxt, p->as), r, p->from.reg, 0) | (regoff(ctxt, &p->to)&0xffff);
+ break;
+
+ case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
+ o1 = AOP_RRR(oprrr(ctxt, p->as), p->from.reg, 0, p->to.reg);
+ break;
+
+ case 73: /* mcrfs crfD,crfS */
+ if(p->from.type != D_FPSCR || p->from.reg == NREG ||
+ p->to.type != D_CREG || p->to.reg == NREG)
+ ctxt->diag("illegal FPSCR/CR field number\n%P", p);
+ o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
+ break;
+
+ case 77: /* syscall $scon, syscall Rx */
+ if(p->from.type == D_CONST) {
+ if(p->from.offset > BIG || p->from.offset < -BIG)
+ ctxt->diag("illegal syscall, sysnum too large: %P", p);
+ o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, p->from.offset);
+ } else if(p->from.type == D_REG) {
+ o1 = LOP_RRR(OP_OR, REGZERO, p->from.reg, p->from.reg);
+ } else {
+ ctxt->diag("illegal syscall: %P", p);
+ o1 = 0x7fe00008; // trap always
+ }
+ o2 = oprrr(ctxt, p->as);
+ o3 = AOP_RRR(oprrr(ctxt, AXOR), REGZERO, REGZERO, REGZERO); // XOR R0, R0
+ break;
+
+ case 78: /* undef */
+ o1 = 0; /* "An instruction consisting entirely of binary 0s is guaranteed
+ always to be an illegal instruction." */
+ break;
+
+ /* relocation operations */
+
+ case 74:
+ v = regoff(ctxt, &p->to);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->to.sym, &o1, &o2);
+ //if(dlm) reloc(&p->to, p->pc, 1);
+ break;
+
+ case 75:
+ v = regoff(ctxt, &p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ //if(dlm) reloc(&p->from, p->pc, 1);
+ break;
+
+ case 76:
+ v = regoff(ctxt, &p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
+ o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
+ addaddrreloc(ctxt, p->from.sym, &o1, &o2);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ //if(dlm) reloc(&p->from, p->pc, 1);
+ break;
+
+ }
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ return;
+
+#if NOTDEF
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ lput(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ lput(o1);
+ lput(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ lput(o5);
+ break;
+ }
+ return 0;
+#endif
+}
+
+static vlong
+vregoff(Link *ctxt, Addr *a)
+{
+
+ ctxt->instoffset = 0;
+ aclass(ctxt, a);
+ return ctxt->instoffset;
+}
+
+static int32
+regoff(Link *ctxt, Addr *a)
+{
+ return vregoff(ctxt, a);
+}
+
+static int32
+oprrr(Link *ctxt, int a)
+{
+ switch(a) {
+ case AADD: return OPVCC(31,266,0,0);
+ case AADDCC: return OPVCC(31,266,0,1);
+ case AADDV: return OPVCC(31,266,1,0);
+ case AADDVCC: return OPVCC(31,266,1,1);
+ case AADDC: return OPVCC(31,10,0,0);
+ case AADDCCC: return OPVCC(31,10,0,1);
+ case AADDCV: return OPVCC(31,10,1,0);
+ case AADDCVCC: return OPVCC(31,10,1,1);
+ case AADDE: return OPVCC(31,138,0,0);
+ case AADDECC: return OPVCC(31,138,0,1);
+ case AADDEV: return OPVCC(31,138,1,0);
+ case AADDEVCC: return OPVCC(31,138,1,1);
+ case AADDME: return OPVCC(31,234,0,0);
+ case AADDMECC: return OPVCC(31,234,0,1);
+ case AADDMEV: return OPVCC(31,234,1,0);
+ case AADDMEVCC: return OPVCC(31,234,1,1);
+ case AADDZE: return OPVCC(31,202,0,0);
+ case AADDZECC: return OPVCC(31,202,0,1);
+ case AADDZEV: return OPVCC(31,202,1,0);
+ case AADDZEVCC: return OPVCC(31,202,1,1);
+
+ case AAND: return OPVCC(31,28,0,0);
+ case AANDCC: return OPVCC(31,28,0,1);
+ case AANDN: return OPVCC(31,60,0,0);
+ case AANDNCC: return OPVCC(31,60,0,1);
+
+ case ACMP: return OPVCC(31,0,0,0)|(1<<21); /* L=1 */
+ case ACMPU: return OPVCC(31,32,0,0)|(1<<21);
+ case ACMPW: return OPVCC(31,0,0,0); /* L=0 */
+ case ACMPWU: return OPVCC(31,32,0,0);
+
+ case ACNTLZW: return OPVCC(31,26,0,0);
+ case ACNTLZWCC: return OPVCC(31,26,0,1);
+ case ACNTLZD: return OPVCC(31,58,0,0);
+ case ACNTLZDCC: return OPVCC(31,58,0,1);
+
+ case ACRAND: return OPVCC(19,257,0,0);
+ case ACRANDN: return OPVCC(19,129,0,0);
+ case ACREQV: return OPVCC(19,289,0,0);
+ case ACRNAND: return OPVCC(19,225,0,0);
+ case ACRNOR: return OPVCC(19,33,0,0);
+ case ACROR: return OPVCC(19,449,0,0);
+ case ACRORN: return OPVCC(19,417,0,0);
+ case ACRXOR: return OPVCC(19,193,0,0);
+
+ case ADCBF: return OPVCC(31,86,0,0);
+ case ADCBI: return OPVCC(31,470,0,0);
+ case ADCBST: return OPVCC(31,54,0,0);
+ case ADCBT: return OPVCC(31,278,0,0);
+ case ADCBTST: return OPVCC(31,246,0,0);
+ case ADCBZ: return OPVCC(31,1014,0,0);
+
+ case AREM:
+ case ADIVW: return OPVCC(31,491,0,0);
+ case AREMCC:
+ case ADIVWCC: return OPVCC(31,491,0,1);
+ case AREMV:
+ case ADIVWV: return OPVCC(31,491,1,0);
+ case AREMVCC:
+ case ADIVWVCC: return OPVCC(31,491,1,1);
+ case AREMU:
+ case ADIVWU: return OPVCC(31,459,0,0);
+ case AREMUCC:
+ case ADIVWUCC: return OPVCC(31,459,0,1);
+ case AREMUV:
+ case ADIVWUV: return OPVCC(31,459,1,0);
+ case AREMUVCC:
+ case ADIVWUVCC: return OPVCC(31,459,1,1);
+
+ case AREMD:
+ case ADIVD: return OPVCC(31,489,0,0);
+ case AREMDCC:
+ case ADIVDCC: return OPVCC(31,489,0,1);
+ case AREMDV:
+ case ADIVDV: return OPVCC(31,489,1,0);
+ case AREMDVCC:
+ case ADIVDVCC: return OPVCC(31,489,1,1);
+ case AREMDU:
+ case ADIVDU: return OPVCC(31,457,0,0);
+ case AREMDUCC:
+ case ADIVDUCC: return OPVCC(31,457,0,1);
+ case AREMDUV:
+ case ADIVDUV: return OPVCC(31,457,1,0);
+ case AREMDUVCC:
+ case ADIVDUVCC: return OPVCC(31,457,1,1);
+
+ case AEIEIO: return OPVCC(31,854,0,0);
+
+ case AEQV: return OPVCC(31,284,0,0);
+ case AEQVCC: return OPVCC(31,284,0,1);
+
+ case AEXTSB: return OPVCC(31,954,0,0);
+ case AEXTSBCC: return OPVCC(31,954,0,1);
+ case AEXTSH: return OPVCC(31,922,0,0);
+ case AEXTSHCC: return OPVCC(31,922,0,1);
+ case AEXTSW: return OPVCC(31,986,0,0);
+ case AEXTSWCC: return OPVCC(31,986,0,1);
+
+ case AFABS: return OPVCC(63,264,0,0);
+ case AFABSCC: return OPVCC(63,264,0,1);
+ case AFADD: return OPVCC(63,21,0,0);
+ case AFADDCC: return OPVCC(63,21,0,1);
+ case AFADDS: return OPVCC(59,21,0,0);
+ case AFADDSCC: return OPVCC(59,21,0,1);
+ case AFCMPO: return OPVCC(63,32,0,0);
+ case AFCMPU: return OPVCC(63,0,0,0);
+ case AFCFID: return OPVCC(63,846,0,0);
+ case AFCFIDCC: return OPVCC(63,846,0,1);
+ case AFCTIW: return OPVCC(63,14,0,0);
+ case AFCTIWCC: return OPVCC(63,14,0,1);
+ case AFCTIWZ: return OPVCC(63,15,0,0);
+ case AFCTIWZCC: return OPVCC(63,15,0,1);
+ case AFCTID: return OPVCC(63,814,0,0);
+ case AFCTIDCC: return OPVCC(63,814,0,1);
+ case AFCTIDZ: return OPVCC(63,815,0,0);
+ case AFCTIDZCC: return OPVCC(63,815,0,1);
+ case AFDIV: return OPVCC(63,18,0,0);
+ case AFDIVCC: return OPVCC(63,18,0,1);
+ case AFDIVS: return OPVCC(59,18,0,0);
+ case AFDIVSCC: return OPVCC(59,18,0,1);
+ case AFMADD: return OPVCC(63,29,0,0);
+ case AFMADDCC: return OPVCC(63,29,0,1);
+ case AFMADDS: return OPVCC(59,29,0,0);
+ case AFMADDSCC: return OPVCC(59,29,0,1);
+ case AFMOVS:
+ case AFMOVD: return OPVCC(63,72,0,0); /* load */
+ case AFMOVDCC: return OPVCC(63,72,0,1);
+ case AFMSUB: return OPVCC(63,28,0,0);
+ case AFMSUBCC: return OPVCC(63,28,0,1);
+ case AFMSUBS: return OPVCC(59,28,0,0);
+ case AFMSUBSCC: return OPVCC(59,28,0,1);
+ case AFMUL: return OPVCC(63,25,0,0);
+ case AFMULCC: return OPVCC(63,25,0,1);
+ case AFMULS: return OPVCC(59,25,0,0);
+ case AFMULSCC: return OPVCC(59,25,0,1);
+ case AFNABS: return OPVCC(63,136,0,0);
+ case AFNABSCC: return OPVCC(63,136,0,1);
+ case AFNEG: return OPVCC(63,40,0,0);
+ case AFNEGCC: return OPVCC(63,40,0,1);
+ case AFNMADD: return OPVCC(63,31,0,0);
+ case AFNMADDCC: return OPVCC(63,31,0,1);
+ case AFNMADDS: return OPVCC(59,31,0,0);
+ case AFNMADDSCC: return OPVCC(59,31,0,1);
+ case AFNMSUB: return OPVCC(63,30,0,0);
+ case AFNMSUBCC: return OPVCC(63,30,0,1);
+ case AFNMSUBS: return OPVCC(59,30,0,0);
+ case AFNMSUBSCC: return OPVCC(59,30,0,1);
+ case AFRES: return OPVCC(59,24,0,0);
+ case AFRESCC: return OPVCC(59,24,0,1);
+ case AFRSP: return OPVCC(63,12,0,0);
+ case AFRSPCC: return OPVCC(63,12,0,1);
+ case AFRSQRTE: return OPVCC(63,26,0,0);
+ case AFRSQRTECC: return OPVCC(63,26,0,1);
+ case AFSEL: return OPVCC(63,23,0,0);
+ case AFSELCC: return OPVCC(63,23,0,1);
+ case AFSQRT: return OPVCC(63,22,0,0);
+ case AFSQRTCC: return OPVCC(63,22,0,1);
+ case AFSQRTS: return OPVCC(59,22,0,0);
+ case AFSQRTSCC: return OPVCC(59,22,0,1);
+ case AFSUB: return OPVCC(63,20,0,0);
+ case AFSUBCC: return OPVCC(63,20,0,1);
+ case AFSUBS: return OPVCC(59,20,0,0);
+ case AFSUBSCC: return OPVCC(59,20,0,1);
+
+ case AICBI: return OPVCC(31,982,0,0);
+ case AISYNC: return OPVCC(19,150,0,0);
+
+ case AMTFSB0: return OPVCC(63,70,0,0);
+ case AMTFSB0CC: return OPVCC(63,70,0,1);
+ case AMTFSB1: return OPVCC(63,38,0,0);
+ case AMTFSB1CC: return OPVCC(63,38,0,1);
+
+ case AMULHW: return OPVCC(31,75,0,0);
+ case AMULHWCC: return OPVCC(31,75,0,1);
+ case AMULHWU: return OPVCC(31,11,0,0);
+ case AMULHWUCC: return OPVCC(31,11,0,1);
+ case AMULLW: return OPVCC(31,235,0,0);
+ case AMULLWCC: return OPVCC(31,235,0,1);
+ case AMULLWV: return OPVCC(31,235,1,0);
+ case AMULLWVCC: return OPVCC(31,235,1,1);
+
+ case AMULHD: return OPVCC(31,73,0,0);
+ case AMULHDCC: return OPVCC(31,73,0,1);
+ case AMULHDU: return OPVCC(31,9,0,0);
+ case AMULHDUCC: return OPVCC(31,9,0,1);
+ case AMULLD: return OPVCC(31,233,0,0);
+ case AMULLDCC: return OPVCC(31,233,0,1);
+ case AMULLDV: return OPVCC(31,233,1,0);
+ case AMULLDVCC: return OPVCC(31,233,1,1);
+
+ case ANAND: return OPVCC(31,476,0,0);
+ case ANANDCC: return OPVCC(31,476,0,1);
+ case ANEG: return OPVCC(31,104,0,0);
+ case ANEGCC: return OPVCC(31,104,0,1);
+ case ANEGV: return OPVCC(31,104,1,0);
+ case ANEGVCC: return OPVCC(31,104,1,1);
+ case ANOR: return OPVCC(31,124,0,0);
+ case ANORCC: return OPVCC(31,124,0,1);
+ case AOR: return OPVCC(31,444,0,0);
+ case AORCC: return OPVCC(31,444,0,1);
+ case AORN: return OPVCC(31,412,0,0);
+ case AORNCC: return OPVCC(31,412,0,1);
+
+ case ARFI: return OPVCC(19,50,0,0);
+ case ARFCI: return OPVCC(19,51,0,0);
+ case ARFID: return OPVCC(19,18,0,0);
+ case AHRFID: return OPVCC(19,274,0,0);
+
+ case ARLWMI: return OPVCC(20,0,0,0);
+ case ARLWMICC: return OPVCC(20,0,0,1);
+ case ARLWNM: return OPVCC(23,0,0,0);
+ case ARLWNMCC: return OPVCC(23,0,0,1);
+
+ case ARLDCL: return OPVCC(30,8,0,0);
+ case ARLDCR: return OPVCC(30,9,0,0);
+
+ case ASYSCALL: return OPVCC(17,1,0,0);
+
+ case ASLW: return OPVCC(31,24,0,0);
+ case ASLWCC: return OPVCC(31,24,0,1);
+ case ASLD: return OPVCC(31,27,0,0);
+ case ASLDCC: return OPVCC(31,27,0,1);
+
+ case ASRAW: return OPVCC(31,792,0,0);
+ case ASRAWCC: return OPVCC(31,792,0,1);
+ case ASRAD: return OPVCC(31,794,0,0);
+ case ASRADCC: return OPVCC(31,794,0,1);
+
+ case ASRW: return OPVCC(31,536,0,0);
+ case ASRWCC: return OPVCC(31,536,0,1);
+ case ASRD: return OPVCC(31,539,0,0);
+ case ASRDCC: return OPVCC(31,539,0,1);
+
+ case ASUB: return OPVCC(31,40,0,0);
+ case ASUBCC: return OPVCC(31,40,0,1);
+ case ASUBV: return OPVCC(31,40,1,0);
+ case ASUBVCC: return OPVCC(31,40,1,1);
+ case ASUBC: return OPVCC(31,8,0,0);
+ case ASUBCCC: return OPVCC(31,8,0,1);
+ case ASUBCV: return OPVCC(31,8,1,0);
+ case ASUBCVCC: return OPVCC(31,8,1,1);
+ case ASUBE: return OPVCC(31,136,0,0);
+ case ASUBECC: return OPVCC(31,136,0,1);
+ case ASUBEV: return OPVCC(31,136,1,0);
+ case ASUBEVCC: return OPVCC(31,136,1,1);
+ case ASUBME: return OPVCC(31,232,0,0);
+ case ASUBMECC: return OPVCC(31,232,0,1);
+ case ASUBMEV: return OPVCC(31,232,1,0);
+ case ASUBMEVCC: return OPVCC(31,232,1,1);
+ case ASUBZE: return OPVCC(31,200,0,0);
+ case ASUBZECC: return OPVCC(31,200,0,1);
+ case ASUBZEV: return OPVCC(31,200,1,0);
+ case ASUBZEVCC: return OPVCC(31,200,1,1);
+
+ case ASYNC: return OPVCC(31,598,0,0);
+ case APTESYNC: return OPVCC(31,598,0,0) | (2<<21);
+
+ case ATLBIE: return OPVCC(31,306,0,0);
+ case ATLBIEL: return OPVCC(31,274,0,0);
+ case ATLBSYNC: return OPVCC(31,566,0,0);
+ case ASLBIA: return OPVCC(31,498,0,0);
+ case ASLBIE: return OPVCC(31,434,0,0);
+ case ASLBMFEE: return OPVCC(31,915,0,0);
+ case ASLBMFEV: return OPVCC(31,851,0,0);
+ case ASLBMTE: return OPVCC(31,402,0,0);
+
+ case ATW: return OPVCC(31,4,0,0);
+ case ATD: return OPVCC(31,68,0,0);
+
+ case AXOR: return OPVCC(31,316,0,0);
+ case AXORCC: return OPVCC(31,316,0,1);
+ }
+ ctxt->diag("bad r/r opcode %A", a);
+ return 0;
+}
+
+static int32
+opirr(Link *ctxt, int a)
+{
+ switch(a) {
+ case AADD: return OPVCC(14,0,0,0);
+ case AADDC: return OPVCC(12,0,0,0);
+ case AADDCCC: return OPVCC(13,0,0,0);
+ case AADD+AEND: return OPVCC(15,0,0,0); /* ADDIS/CAU */
+
+ case AANDCC: return OPVCC(28,0,0,0);
+ case AANDCC+AEND: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */
+
+ case ABR: return OPVCC(18,0,0,0);
+ case ABL: return OPVCC(18,0,0,0) | 1;
+ case ADUFFZERO: return OPVCC(18,0,0,0) | 1;
+ case ADUFFCOPY: return OPVCC(18,0,0,0) | 1;
+ case ABC: return OPVCC(16,0,0,0);
+ case ABCL: return OPVCC(16,0,0,0) | 1;
+
+ case ABEQ: return AOP_RRR(16<<26,12,2,0);
+ case ABGE: return AOP_RRR(16<<26,4,0,0);
+ case ABGT: return AOP_RRR(16<<26,12,1,0);
+ case ABLE: return AOP_RRR(16<<26,4,1,0);
+ case ABLT: return AOP_RRR(16<<26,12,0,0);
+ case ABNE: return AOP_RRR(16<<26,4,2,0);
+ case ABVC: return AOP_RRR(16<<26,4,3,0);
+ case ABVS: return AOP_RRR(16<<26,12,3,0);
+
+ case ACMP: return OPVCC(11,0,0,0)|(1<<21); /* L=1 */
+ case ACMPU: return OPVCC(10,0,0,0)|(1<<21);
+ case ACMPW: return OPVCC(11,0,0,0); /* L=0 */
+ case ACMPWU: return OPVCC(10,0,0,0);
+ case ALSW: return OPVCC(31,597,0,0);
+
+ case AMULLW: return OPVCC(7,0,0,0);
+
+ case AOR: return OPVCC(24,0,0,0);
+ case AOR+AEND: return OPVCC(25,0,0,0); /* ORIS/ORIU */
+
+ case ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */
+ case ARLWMICC: return OPVCC(20,0,0,1);
+ case ARLDMI: return OPVCC(30,0,0,0) | (3<<2); /* rldimi */
+ case ARLDMICC: return OPVCC(30,0,0,1) | (3<<2);
+
+ case ARLWNM: return OPVCC(21,0,0,0); /* rlwinm */
+ case ARLWNMCC: return OPVCC(21,0,0,1);
+
+ case ARLDCL: return OPVCC(30,0,0,0); /* rldicl */
+ case ARLDCLCC: return OPVCC(30,0,0,1);
+ case ARLDCR: return OPVCC(30,1,0,0); /* rldicr */
+ case ARLDCRCC: return OPVCC(30,1,0,1);
+ case ARLDC: return OPVCC(30,0,0,0) | (2<<2);
+ case ARLDCCC: return OPVCC(30,0,0,1) | (2<<2);
+
+ case ASRAW: return OPVCC(31,824,0,0);
+ case ASRAWCC: return OPVCC(31,824,0,1);
+ case ASRAD: return OPVCC(31,(413<<1),0,0);
+ case ASRADCC: return OPVCC(31,(413<<1),0,1);
+
+ case ASTSW: return OPVCC(31,725,0,0);
+
+ case ASUBC: return OPVCC(8,0,0,0);
+
+ case ATW: return OPVCC(3,0,0,0);
+ case ATD: return OPVCC(2,0,0,0);
+
+ case AXOR: return OPVCC(26,0,0,0); /* XORIL */
+ case AXOR+AEND: return OPVCC(27,0,0,0); /* XORIU */
+ }
+ ctxt->diag("bad opcode i/r %A", a);
+ return 0;
+}
+
+/*
+ * load o(a),d
+ */
+static int32
+opload(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVD: return OPVCC(58,0,0,0); /* ld */
+ case AMOVDU: return OPVCC(58,0,0,1); /* ldu */
+ case AMOVWZ: return OPVCC(32,0,0,0); /* lwz */
+ case AMOVWZU: return OPVCC(33,0,0,0); /* lwzu */
+ case AMOVW: return OPVCC(58,0,0,0)|(1<<1); /* lwa */
+ /* no AMOVWU */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(34,0,0,0); /* load */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(35,0,0,0);
+ case AFMOVD: return OPVCC(50,0,0,0);
+ case AFMOVDU: return OPVCC(51,0,0,0);
+ case AFMOVS: return OPVCC(48,0,0,0);
+ case AFMOVSU: return OPVCC(49,0,0,0);
+ case AMOVH: return OPVCC(42,0,0,0);
+ case AMOVHU: return OPVCC(43,0,0,0);
+ case AMOVHZ: return OPVCC(40,0,0,0);
+ case AMOVHZU: return OPVCC(41,0,0,0);
+ case AMOVMW: return OPVCC(46,0,0,0); /* lmw */
+ }
+ ctxt->diag("bad load opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed load a(b),d
+ */
+static int32
+oploadx(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVWZ: return OPVCC(31,23,0,0); /* lwzx */
+ case AMOVWZU: return OPVCC(31,55,0,0); /* lwzux */
+ case AMOVW: return OPVCC(31,341,0,0); /* lwax */
+ case AMOVWU: return OPVCC(31,373,0,0); /* lwaux */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,87,0,0); /* lbzx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,119,0,0); /* lbzux */
+ case AFMOVD: return OPVCC(31,599,0,0); /* lfdx */
+ case AFMOVDU: return OPVCC(31,631,0,0); /* lfdux */
+ case AFMOVS: return OPVCC(31,535,0,0); /* lfsx */
+ case AFMOVSU: return OPVCC(31,567,0,0); /* lfsux */
+ case AMOVH: return OPVCC(31,343,0,0); /* lhax */
+ case AMOVHU: return OPVCC(31,375,0,0); /* lhaux */
+ case AMOVHBR: return OPVCC(31,790,0,0); /* lhbrx */
+ case AMOVWBR: return OPVCC(31,534,0,0); /* lwbrx */
+ case AMOVHZ: return OPVCC(31,279,0,0); /* lhzx */
+ case AMOVHZU: return OPVCC(31,311,0,0); /* lhzux */
+ case AECIWX: return OPVCC(31,310,0,0); /* eciwx */
+ case ALWAR: return OPVCC(31,20,0,0); /* lwarx */
+ case ALDAR: return OPVCC(31,84,0,0);
+ case ALSW: return OPVCC(31,533,0,0); /* lswx */
+ case AMOVD: return OPVCC(31,21,0,0); /* ldx */
+ case AMOVDU: return OPVCC(31,53,0,0); /* ldux */
+ }
+ ctxt->diag("bad loadx opcode %A", a);
+ return 0;
+}
+
+/*
+ * store s,o(d)
+ */
+static int32
+opstore(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(38,0,0,0); /* stb */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(39,0,0,0); /* stbu */
+ case AFMOVD: return OPVCC(54,0,0,0); /* stfd */
+ case AFMOVDU: return OPVCC(55,0,0,0); /* stfdu */
+ case AFMOVS: return OPVCC(52,0,0,0); /* stfs */
+ case AFMOVSU: return OPVCC(53,0,0,0); /* stfsu */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(44,0,0,0); /* sth */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(45,0,0,0); /* sthu */
+ case AMOVMW: return OPVCC(47,0,0,0); /* stmw */
+ case ASTSW: return OPVCC(31,725,0,0); /* stswi */
+ case AMOVWZ:
+ case AMOVW: return OPVCC(36,0,0,0); /* stw */
+ case AMOVWZU:
+ case AMOVWU: return OPVCC(37,0,0,0); /* stwu */
+ case AMOVD: return OPVCC(62,0,0,0); /* std */
+ case AMOVDU: return OPVCC(62,0,0,1); /* stdu */
+ }
+ ctxt->diag("unknown store opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed store s,a(b)
+ */
+static int32
+opstorex(Link *ctxt, int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,215,0,0); /* stbx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,247,0,0); /* stbux */
+ case AFMOVD: return OPVCC(31,727,0,0); /* stfdx */
+ case AFMOVDU: return OPVCC(31,759,0,0); /* stfdux */
+ case AFMOVS: return OPVCC(31,663,0,0); /* stfsx */
+ case AFMOVSU: return OPVCC(31,695,0,0); /* stfsux */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(31,407,0,0); /* sthx */
+ case AMOVHBR: return OPVCC(31,918,0,0); /* sthbrx */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(31,439,0,0); /* sthux */
+ case AMOVWZ:
+ case AMOVW: return OPVCC(31,151,0,0); /* stwx */
+ case AMOVWZU:
+ case AMOVWU: return OPVCC(31,183,0,0); /* stwux */
+ case ASTSW: return OPVCC(31,661,0,0); /* stswx */
+ case AMOVWBR: return OPVCC(31,662,0,0); /* stwbrx */
+ case ASTWCCC: return OPVCC(31,150,0,1); /* stwcx. */
+ case ASTDCCC: return OPVCC(31,214,0,1); /* stwdx. */
+ case AECOWX: return OPVCC(31,438,0,0); /* ecowx */
+ case AMOVD: return OPVCC(31,149,0,0); /* stdx */
+ case AMOVDU: return OPVCC(31,181,0,0); /* stdux */
+ }
+ ctxt->diag("unknown storex opcode %A", a);
+ return 0;
+}
+
--- /dev/null
- #include "../pkg/runtime/stack.h"
- #include "../pkg/runtime/funcdata.h"
+// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/9l/9.out.h"
++#include "../runtime/stack.h"
++#include "../runtime/funcdata.h"
+
+static Prog zprg = {
+ .as = AGOK,
+ .reg = NREG,
+ .from = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .from3 = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .to = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+};
+
+static int
+symtype(Addr *a)
+{
+ return a->name;
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ABL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->reg;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->reg;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->reg = f;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ char literal[64];
+ LSym *s;
+
+ USED(ctxt);
+
+ p->from.class = 0;
+ p->to.class = 0;
+
+ // Rewrite BR/BL to symbol as D_BRANCH.
+ switch(p->as) {
+ case ABR:
+ case ABL:
+ case ARETURN:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ if(p->to.sym != nil)
+ p->to.type = D_BRANCH;
+ break;
+ }
+
+ // Rewrite float constants to values stored in memory.
+ switch(p->as) {
+ case AFMOVS:
+ if(p->from.type == D_FCONST) {
+ int32 i32;
+ float32 f32;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ sprint(literal, "$f32.%08ux", (uint32)i32);
+ s = linklookup(ctxt, literal, 0);
+ s->size = 4;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+ case AFMOVD:
+ if(p->from.type == D_FCONST) {
+ int64 i64;
+ memmove(&i64, &p->from.u.dval, 8);
+ sprint(literal, "$f64.%016llux", (uvlong)i64);
+ s = linklookup(ctxt, literal, 0);
+ s->size = 8;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+ case AMOVD:
+ if(p->from.type == D_CONST && p->from.name == D_NONE && (int64)(uint32)p->from.offset != p->from.offset) {
+ sprint(literal, "$i64.%016llux", (uvlong)p->from.offset);
+ s = linklookup(ctxt, literal, 0);
+ s->size = 8;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ }
+
+ // Rewrite SUB constants into ADD.
+ switch(p->as) {
+ case ASUBC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDC;
+ }
+ break;
+
+ case ASUBCCC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDCCC;
+ }
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ break;
+ }
+}
+
+static Prog* stacksplit(Link*, Prog*, int32, int);
+
+static void
+parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
+{
+ *textstksiz = arg & 0xffffffffLL;
+ if(*textstksiz & 0x80000000LL)
+ *textstksiz = -(-*textstksiz & 0xffffffffLL);
+
+ *textarg = (arg >> 32) & 0xffffffffLL;
+ if(*textarg & 0x80000000LL)
+ *textarg = 0;
+ *textarg = (*textarg+7) & ~7LL;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q, *q1;
+ int o, mov, aoffset;
+ vlong textstksiz, textarg;
+ int32 autoffset, autosize;
+
+ if(ctxt->symmorestack[0] == nil) {
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+ ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+ // TODO(minux): add morestack short-cuts with small fixed frame-size.
+ }
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ parsetextconst(p->to.offset, &textstksiz, &textarg);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ cursym->args = p->to.offset>>32;
+ cursym->locals = textstksiz;
+
+ /*
+ * find leaf subroutines
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f noops\n", cputime());
+ Bflush(ctxt->bso);
+
+ q = nil;
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ /* too hard, just leave alone */
+ case ATEXT:
+ q = p;
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ break;
+
+ case ANOR:
+ q = p;
+ if(p->to.type == D_REG)
+ if(p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ALWAR:
+ case ASTWCCC:
+ case AECIWX:
+ case AECOWX:
+ case AEIEIO:
+ case AICBI:
+ case AISYNC:
+ case ATLBIE:
+ case ATLBIEL:
+ case ASLBIA:
+ case ASLBIE:
+ case ASLBMFEE:
+ case ASLBMFEV:
+ case ASLBMTE:
+ case ADCBF:
+ case ADCBI:
+ case ADCBST:
+ case ADCBT:
+ case ADCBTST:
+ case ADCBZ:
+ case ASYNC:
+ case ATLBSYNC:
+ case APTESYNC:
+ case ATW:
+ case AWORD:
+ case ARFI:
+ case ARFCI:
+ case ARFID:
+ case AHRFID:
+ q = p;
+ p->mark |= LABEL|SYNC;
+ continue;
+
+ case AMOVW:
+ case AMOVWZ:
+ case AMOVD:
+ q = p;
+ switch(p->from.type) {
+ case D_MSR:
+ case D_SPR:
+ case D_FPSCR:
+ case D_CREG:
+ case D_DCR:
+ p->mark |= LABEL|SYNC;
+ }
+ switch(p->to.type) {
+ case D_MSR:
+ case D_SPR:
+ case D_FPSCR:
+ case D_CREG:
+ case D_DCR:
+ p->mark |= LABEL|SYNC;
+ }
+ continue;
+
+ case AFABS:
+ case AFABSCC:
+ case AFADD:
+ case AFADDCC:
+ case AFCTIW:
+ case AFCTIWCC:
+ case AFCTIWZ:
+ case AFCTIWZCC:
+ case AFDIV:
+ case AFDIVCC:
+ case AFMADD:
+ case AFMADDCC:
+ case AFMOVD:
+ case AFMOVDU:
+ /* case AFMOVDS: */
+ case AFMOVS:
+ case AFMOVSU:
+ /* case AFMOVSD: */
+ case AFMSUB:
+ case AFMSUBCC:
+ case AFMUL:
+ case AFMULCC:
+ case AFNABS:
+ case AFNABSCC:
+ case AFNEG:
+ case AFNEGCC:
+ case AFNMADD:
+ case AFNMADDCC:
+ case AFNMSUB:
+ case AFNMSUBCC:
+ case AFRSP:
+ case AFRSPCC:
+ case AFSUB:
+ case AFSUBCC:
+ q = p;
+ p->mark |= FLOAT;
+ continue;
+
+ case ABL:
+ case ABCL:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ cursym->text->mark &= ~LEAF;
+
+ case ABC:
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABR:
+ case ABVC:
+ case ABVS:
+ p->mark |= BRANCH;
+ q = p;
+ q1 = p->pcond;
+ if(q1 != nil) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->pcond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != nil)
+ q1->mark |= LABEL;
+ continue;
+
+ case AFCMPO:
+ case AFCMPU:
+ q = p;
+ p->mark |= FCMP|FLOAT;
+ continue;
+
+ case ARETURN:
+ q = p;
+ if(p->link != nil)
+ p->link->mark |= LABEL;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ default:
+ q = p;
+ continue;
+ }
+ }
+
+ autosize = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ mov = AMOVD;
+ aoffset = 0;
+ autosize = textstksiz + 8;
+ if((p->mark & LEAF) && autosize <= 8)
+ autosize = 0;
+ else
+ if(autosize & 4)
+ autosize += 4;
+ p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
+
+ if(!(p->reg & NOSPLIT))
+ p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+
+ q = p;
+ if(autosize) {
+ /* use MOVDU to adjust R1 when saving R31, if autosize is small */
+ if(!(cursym->text->mark & LEAF) && autosize >= -BIG && autosize <= BIG) {
+ mov = AMOVDU;
+ aoffset = -autosize;
+ } else {
+ q = appendp(ctxt, p);
+ q->as = AADD;
+ q->lineno = p->lineno;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->spadj = +autosize;
+ }
+ } else
+ if(!(cursym->text->mark & LEAF)) {
+ if(ctxt->debugvlog) {
+ Bprint(ctxt->bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(ctxt->bso);
+ }
+ cursym->text->mark |= LEAF;
+ }
+
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ break;
+ }
+
+ q = appendp(ctxt, q);
+ q->as = AMOVD;
+ q->lineno = p->lineno;
+ q->from.type = D_SPR;
+ q->from.offset = D_LR;
+ q->to.type = D_REG;
+ q->to.reg = REGTMP;
+
+ q = appendp(ctxt, q);
+ q->as = mov;
+ q->lineno = p->lineno;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_OREG;
+ q->to.offset = aoffset;
+ q->to.reg = REGSP;
+ if(q->as == AMOVDU)
+ q->spadj = -aoffset;
+
+ if(cursym->text->reg & WRAPPER) {
+ // g->panicwrap += autosize;
+ // MOVWZ panicwrap_offset(g), R3
+ // ADD $autosize, R3
+ // MOVWZ R3, panicwrap_offset(g)
+ p = appendp(ctxt, q);
+ p->as = AMOVWZ;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVWZ;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+
+ break;
+
+ case ARETURN:
+ if(p->from.type == D_CONST) {
+ ctxt->diag("using BECOME (%P) is not supported!", p);
+ break;
+ }
+ if(p->to.sym) { // retjmp
+ p->as = ABR;
+ p->to.type = D_BRANCH;
+ break;
+ }
+ if(cursym->text->reg & WRAPPER) {
+ // g->panicwrap -= autosize;
+ // MOVWZ panicwrap_offset(g), R3
+ // ADD $-autosize, R3
+ // MOVWZ R3, panicwrap_offset(g)
+ p->as = AMOVWZ;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = -autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = AMOVWZ;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+
+ p->as = ARETURN;
+ }
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ p->as = ABR;
+ p->from = zprg.from;
+ p->to.type = D_SPR;
+ p->to.offset = D_LR;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ p->spadj = -autosize;
+
+ q = ctxt->arch->prg();
+ q->as = ABR;
+ q->lineno = p->lineno;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+ q->mark |= BRANCH;
+ q->spadj = +autosize;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+
+ p->as = AMOVD;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = ctxt->arch->prg();
+ q->as = AMOVD;
+ q->lineno = p->lineno;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ if(autosize) {
+ q = ctxt->arch->prg();
+ q->as = AADD;
+ q->lineno = p->lineno;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->spadj = -autosize;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = ctxt->arch->prg();
+ q1->as = ABR;
+ q1->lineno = p->lineno;
+ q1->to.type = D_SPR;
+ q1->to.offset = D_LR;
+ q1->mark |= BRANCH;
+ q1->spadj = +autosize;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case AADD:
+ if(p->to.type == D_REG && p->to.reg == REGSP && p->from.type == D_CONST)
+ p->spadj = -p->from.offset;
+ break;
+ }
+ }
+
+#if 0 // instruction scheduling
+ if(debug['Q'] == 0)
+ return;
+
+ curtext = nil;
+ q = nil; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != nil; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != nil; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+#endif
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
+{
+ int32 arg;
+ Prog *q, *q1;
+
+ // MOVD g_stackguard(g), R3
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ q = nil;
+ if(framesize <= StackSmall) {
+ // small stack: SP < stackguard
+ // CMP stackguard, SP
+ p = appendp(ctxt, p);
+ p->as = ACMPU;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize < stackguard-StackSmall
+ // ADD $-framesize, SP, R4
+ // CMP stackguard, R4
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = -framesize;
+ p->reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPU;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+ } else {
+ // Such a large stack we need to protect against wraparound.
+ // If SP is close to zero:
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // // stackguard is R3
+ // CMP R3, $StackPreempt
+ // BEQ label-of-call-to-morestack
+ // ADD $StackGuard, SP, R4
+ // SUB R3, R4
+ // MOVD $(framesize+(StackGuard-StackSmall)), R31
+ // CMPU R31, R4
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_CONST;
+ p->to.offset = StackPreempt;
+
+ q = p = appendp(ctxt, p);
+ p->as = ABEQ;
+ p->to.type = D_BRANCH;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = StackGuard;
+ p->reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ p = appendp(ctxt, p);
+ p->as = ASUB;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_CONST;
+ p->from.offset = framesize + StackGuard - StackSmall;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPU;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+ }
+
+ // q1: BLT done
+ q1 = p = appendp(ctxt, p);
+ p->as = ABLT;
+ p->to.type = D_BRANCH;
+
+ // MOVD $framesize, R3
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_CONST;
+ p->from.offset = framesize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ if(q)
+ q->pcond = p;
+
+ // MOVD $args, R4
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_CONST;
+ arg = (ctxt->cursym->text->to.offset >> 32) & 0xffffffffull;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ else if(arg == ArgsSizeUnknown)
+ ctxt->diag("%s: arg size unknown, but split stack", ctxt->cursym->name);
+ if(arg&7)
+ ctxt->diag("misaligned argument size in stack split: %d", arg);
+ p->from.offset = arg;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
+ // MOVD LR, R5
+ p = appendp(ctxt, p);
+ p->as = AMOVD;
+ p->from.type = D_SPR;
+ p->from.offset = D_LR;
+ p->to.type = D_REG;
+ p->to.reg = 5;
+
+ // BL runtime.morestack(SB)
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[noctxt];
+
+ // BR start
+ p = appendp(ctxt, p);
+ p->as = ABR;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ // placeholder for q1's jump target
+ p = appendp(ctxt, p);
+ p->as = ANOP; // zero-width place holder
+ q1->pcond = p;
+
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+
+ case ABVC: return ABVS;
+ case ABVS: return ABVC;
+ }
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q, *r;
+ int a, b, i;
+
+loop:
+ if(p == nil)
+ return;
+ a = p->as;
+ if(a == ABR) {
+ q = p->pcond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ p = p->link;
+ xfol(ctxt, p, last);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != nil) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == *last || (q->mark&NOSCHED))
+ break;
+ b = 0; /* set */
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
+ goto copy;
+ if(!q->pcond || (q->pcond->mark&FOLL))
+ continue;
+ b = relinv(a);
+ if(!b)
+ continue;
+ copy:
+ for(;;) {
+ r = ctxt->arch->prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ (*last)->link = r;
+ *last = r;
+ continue;
+ }
+ (*last)->link = r;
+ *last = r;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
+ return;
+ r->as = b;
+ r->pcond = p->link;
+ r->link = p->pcond;
+ if(!(r->link->mark&FOLL))
+ xfol(ctxt, r->link, last);
+ if(!(r->pcond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+
+ a = ABR;
+ q = ctxt->arch->prg();
+ q->as = a;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->pcond != nil)
+ if(a != ABL && p->link != nil) {
+ xfol(ctxt, p->link, last);
+ p = p->pcond;
+ if(p == nil || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+LinkArch linkpower64 = {
+ .name = "power64",
+ .thechar = '9',
+ .endian = BigEndian,
+
+ .addstacksplit = addstacksplit,
+ .assemble = span9,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 4,
+ .ptrsize = 8,
+ .regsize = 8,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ABL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = ABR,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARETURN,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};
+
+LinkArch linkpower64le = {
+ .name = "power64le",
+ .thechar = '9',
+ .endian = LittleEndian,
+
+ .addstacksplit = addstacksplit,
+ .assemble = span9,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 4,
+ .ptrsize = 8,
+ .regsize = 8,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ABL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = ABR,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARETURN,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};