Commit 4dee747f authored by Russ Cox's avatar Russ Cox

8a, 8c, and 8l from inferno distribution

R=r
DELTA=19539  (19539 added, 0 deleted, 0 changed)
OCL=22109
CL=22109
parent 2d259c81
// Inferno utils/8a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <lib9.h>
#include <bio.h>
#include "../8c/8.out.h"
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Sym Sym;
typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
#define NSYMB 500
#define BUFSIZ 8192
#define HISTSZ 20
#define NINCLUDE 10
#define NHUNK 10000
#define EOF (-1)
#define IGN (-2)
#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
#define NHASH 503
#define STRINGSZ 200
#define NMACRO 10
struct Sym
{
Sym* link;
Ref* ref;
char* macro;
long value;
ushort type;
char *name;
char sym;
};
#define S ((Sym*)0)
struct Ref
{
int class;
};
EXTERN struct
{
char* p;
int c;
} fi;
struct Io
{
Io* link;
char b[BUFSIZ];
char* p;
short c;
short f;
};
#define I ((Io*)0)
EXTERN struct
{
Sym* sym;
short type;
} h[NSYM];
struct Gen
{
double dval;
char sval[8];
long offset;
Sym* sym;
short type;
short index;
short scale;
};
struct Gen2
{
Gen from;
Gen to;
};
struct Hist
{
Hist* link;
char* name;
long line;
long offset;
};
#define H ((Hist*)0)
enum
{
CLAST,
CMACARG,
CMACRO,
CPREPROC,
};
EXTERN char debug[256];
EXTERN Sym* hash[NHASH];
EXTERN char* Dlist[30];
EXTERN int nDlist;
EXTERN Hist* ehist;
EXTERN int newflag;
EXTERN Hist* hist;
EXTERN char* hunk;
EXTERN char* include[NINCLUDE];
EXTERN Io* iofree;
EXTERN Io* ionext;
EXTERN Io* iostack;
EXTERN long lineno;
EXTERN int nerrors;
EXTERN long nhunk;
EXTERN int ninclude;
EXTERN Gen nullgen;
EXTERN char* outfile;
EXTERN int pass;
EXTERN char* pathname;
EXTERN long pc;
EXTERN int peekc;
EXTERN int sym;
EXTERN char symb[NSYMB];
EXTERN int thechar;
EXTERN char* thestring;
EXTERN long thunk;
EXTERN Biobuf obuf;
void* allocn(void*, long, long);
void errorexit(void);
void pushio(void);
void newio(void);
void newfile(char*, int);
Sym* slookup(char*);
Sym* lookup(void);
void syminit(Sym*);
long yylex(void);
int getc(void);
int getnsc(void);
void unget(int);
int escchar(int);
void cinit(void);
void checkscale(int);
void pinit(char*);
void cclean(void);
int isreg(Gen*);
void outcode(int, Gen2*);
void outhist(void);
void zaddr(Gen*, int);
void zname(char*, int, int);
void ieeedtod(Ieee*, double);
int filbuf(void);
Sym* getsym(void);
void domacro(void);
void macund(void);
void macdef(void);
void macexpand(Sym*, char*);
void macinc(void);
void macprag(void);
void maclin(void);
void macif(int);
void macend(void);
void dodefine(char*);
void prfile(long);
void linehist(char*, int);
void gethunk(void);
void yyerror(char*, ...);
int yyparse(void);
void setinclude(char*);
int assemble(char*);
/*
* Posix.c/Inferno.c/Nt.c
*/
enum /* keep in synch with ../cc/cc.h */
{
Plan9 = 1<<0,
Unix = 1<<1,
Windows = 1<<2
};
int mywait(int*);
int mycreat(char*, int);
int systemtype(int);
int pathchar(void);
char* mygetwd(char*, int);
int myexec(char*, char*[]);
int mydup(int, int);
int myfork(void);
int mypipe(int*);
void* mysbrk(ulong);
// Inferno utils/8a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
%{
#include "a.h"
%}
%union {
Sym *sym;
long lval;
double dval;
char sval[8];
Gen gen;
Gen2 gen2;
}
%left '|'
%left '^'
%left '&'
%left '<' '>'
%left '+' '-'
%left '*' '/' '%'
%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI
%token <lval> LCONST LFP LPC LSB
%token <lval> LBREG LLREG LSREG LFREG
%token <dval> LFCONST
%token <sval> LSCONST LSP
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset
%type <gen> mem imm reg nam rel rem rim rom omem nmem
%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7
%%
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
| ';'
| inst ';'
| error ';'
inst:
LNAME '=' expr
{
$1->type = LVAR;
$1->value = $3;
}
| LVAR '=' expr
{
if($1->value != $3)
yyerror("redeclaration of %s", $1->name);
$1->value = $3;
}
| LTYPE0 nonnon { outcode($1, &$2); }
| LTYPE1 nonrem { outcode($1, &$2); }
| LTYPE2 rimnon { outcode($1, &$2); }
| LTYPE3 rimrem { outcode($1, &$2); }
| LTYPE4 remrim { outcode($1, &$2); }
| LTYPER nonrel { outcode($1, &$2); }
| LTYPED spec1 { outcode($1, &$2); }
| LTYPET spec2 { outcode($1, &$2); }
| LTYPEC spec3 { outcode($1, &$2); }
| LTYPEN spec4 { outcode($1, &$2); }
| LTYPES spec5 { outcode($1, &$2); }
| LTYPEM spec6 { outcode($1, &$2); }
| LTYPEI spec7 { outcode($1, &$2); }
nonnon:
{
$$.from = nullgen;
$$.to = nullgen;
}
| ','
{
$$.from = nullgen;
$$.to = nullgen;
}
rimrem:
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
remrim:
rem ',' rim
{
$$.from = $1;
$$.to = $3;
}
rimnon:
rim ','
{
$$.from = $1;
$$.to = nullgen;
}
| rim
{
$$.from = $1;
$$.to = nullgen;
}
nonrem:
',' rem
{
$$.from = nullgen;
$$.to = $2;
}
| rem
{
$$.from = nullgen;
$$.to = $1;
}
nonrel:
',' rel
{
$$.from = nullgen;
$$.to = $2;
}
| rel
{
$$.from = nullgen;
$$.to = $1;
}
spec1: /* DATA */
nam '/' con ',' imm
{
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
}
spec2: /* TEXT */
mem ',' imm
{
$$.from = $1;
$$.to = $3;
}
| mem ',' con ',' imm
{
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
}
spec3: /* JMP/CALL */
',' rom
{
$$.from = nullgen;
$$.to = $2;
}
| rom
{
$$.from = nullgen;
$$.to = $1;
}
spec4: /* NOP */
nonnon
| nonrem
spec5: /* SHL/SHR */
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
| rim ',' rem ':' LLREG
{
$$.from = $1;
$$.to = $3;
if($$.from.index != D_NONE)
yyerror("dp shift with lhs index");
$$.from.index = $5;
}
spec6: /* MOVW/MOVL */
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
| rim ',' rem ':' LSREG
{
$$.from = $1;
$$.to = $3;
if($$.to.index != D_NONE)
yyerror("dp move with lhs index");
$$.to.index = $5;
}
spec7:
rim ','
{
$$.from = $1;
$$.to = nullgen;
}
| rim
{
$$.from = $1;
$$.to = nullgen;
}
| rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
rem:
reg
| mem
rom:
rel
| nmem
| '*' reg
{
$$ = $2;
}
| '*' omem
{
$$ = $2;
}
| reg
| omem
rim:
rem
| imm
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;
$$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
$$.sym = $1;
$$.offset = $1->value + $2;
}
reg:
LBREG
{
$$ = nullgen;
$$.type = $1;
}
| LFREG
{
$$ = nullgen;
$$.type = $1;
}
| LLREG
{
$$ = nullgen;
$$.type = $1;
}
| LSP
{
$$ = nullgen;
$$.type = D_SP;
}
| LSREG
{
$$ = nullgen;
$$.type = $1;
}
imm:
'$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' nam
{
$$ = $2;
$$.index = $2.type;
$$.type = D_ADDR;
/*
if($2.type == D_AUTO || $2.type == D_PARAM)
yyerror("constant cannot be automatic: %s",
$2.sym->name);
*/
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memcpy($$.sval, $2, sizeof($$.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $3;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = -$3;
}
mem:
omem
| nmem
omem:
con
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.offset = $1;
}
| con '(' LLREG ')'
{
$$ = nullgen;
$$.type = D_INDIR+$3;
$$.offset = $1;
}
| con '(' LSP ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_SP;
$$.offset = $1;
}
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.offset = $1;
$$.index = $3;
$$.scale = $5;
checkscale($$.scale);
}
| con '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+$3;
$$.offset = $1;
$$.index = $6;
$$.scale = $8;
checkscale($$.scale);
}
| '(' LLREG ')'
{
$$ = nullgen;
$$.type = D_INDIR+$2;
}
| '(' LSP ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_SP;
}
| '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.index = $2;
$$.scale = $4;
checkscale($$.scale);
}
| '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+$2;
$$.index = $5;
$$.scale = $7;
checkscale($$.scale);
}
nmem:
nam
{
$$ = $1;
}
| nam '(' LLREG '*' con ')'
{
$$ = $1;
$$.index = $3;
$$.scale = $5;
checkscale($$.scale);
}
nam:
LNAME offset '(' pointer ')'
{
$$ = nullgen;
$$.type = $4;
$$.sym = $1;
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
$$.type = D_STATIC;
$$.sym = $1;
$$.offset = $4;
}
offset:
{
$$ = 0;
}
| '+' con
{
$$ = $2;
}
| '-' con
{
$$ = -$2;
}
pointer:
LSB
| LSP
{
$$ = D_AUTO;
}
| LFP
con:
LCONST
| LVAR
{
$$ = $1->value;
}
| '-' con
{
$$ = -$2;
}
| '+' con
{
$$ = $2;
}
| '~' con
{
$$ = ~$2;
}
| '(' expr ')'
{
$$ = $2;
}
expr:
con
| expr '+' expr
{
$$ = $1 + $3;
}
| expr '-' expr
{
$$ = $1 - $3;
}
| expr '*' expr
{
$$ = $1 * $3;
}
| expr '/' expr
{
$$ = $1 / $3;
}
| expr '%' expr
{
$$ = $1 % $3;
}
| expr '<' '<' expr
{
$$ = $1 << $4;
}
| expr '>' '>' expr
{
$$ = $1 >> $4;
}
| expr '&' expr
{
$$ = $1 & $3;
}
| expr '^' expr
{
$$ = $1 ^ $3;
}
| expr '|' expr
{
$$ = $1 | $3;
}
// Inferno utils/8a/l.s
// http://code.google.com/p/inferno-os/source/browse/utils/8a/l.s
//
// 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.
/*
* Memory and machine-specific definitions. Used in C and assembler.
*/
/*
* Sizes
*/
#define BI2BY 8 /* bits per byte */
#define BI2WD 32 /* bits per word */
#define BY2WD 4 /* bytes per word */
#define BY2PG 4096 /* bytes per page */
#define WD2PG (BY2PG/BY2WD) /* words per page */
#define PGSHIFT 12 /* log(BY2PG) */
#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
#define MAXMACH 1 /* max # cpus system can run */
/*
* Time
*/
#define HZ (20) /* clock frequency */
#define MS2HZ (1000/HZ) /* millisec per clock tick */
#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
/*
* Fundamental addresses
*/
/*
* Address spaces
*
* User is at 0-2GB
* Kernel is at 2GB-4GB
*
* To avoid an extra page map, both the user stack (USTKTOP) and
* the temporary user stack (TSTKTOP) should be in the the same
* 4 meg.
*/
#define UZERO 0 /* base of user address space */
#define UTZERO (UZERO+BY2PG) /* first address in user text */
#define KZERO 0x80000000 /* base of kernel address space */
#define KTZERO KZERO /* first address in kernel text */
#define USERADDR 0xC0000000 /* struct User */
#define UREGADDR (USERADDR+BY2PG-4*19)
#define TSTKTOP USERADDR /* end of new stack in sysexec */
#define TSTKSIZ 10
#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */
#define ROMBIOS (KZERO|0xF0000)
#define MACHSIZE 4096
#define isphys(x) (((ulong)x)&KZERO)
/*
* known 80386 segments (in GDT) and their selectors
*/
#define NULLSEG 0 /* null segment */
#define KDSEG 1 /* kernel data/stack */
#define KESEG 2 /* kernel executable */
#define UDSEG 3 /* user data/stack */
#define UESEG 4 /* user executable */
#define TSSSEG 5 /* task segment */
#define SELGDT (0<<3) /* selector is in gdt */
#define SELLDT (1<<3) /* selector is in ldt */
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
#define KESEL SELECTOR(KESEG, SELGDT, 0)
#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
#define UESEL SELECTOR(UESEG, SELGDT, 3)
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
/*
* fields in segment descriptors
*/
#define SEGDATA (0x10<<8) /* data/stack segment */
#define SEGEXEC (0x18<<8) /* executable segment */
#define SEGTSS (0x9<<8) /* TSS segment */
#define SEGCG (0x0C<<8) /* call gate */
#define SEGIG (0x0E<<8) /* interrupt gate */
#define SEGTG (0x0F<<8) /* task gate */
#define SEGTYPE (0x1F<<8)
#define SEGP (1<<15) /* segment present */
#define SEGPL(x) ((x)<<13) /* priority level */
#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
#define SEGG (1<<23) /* granularity 1==4k (for other) */
#define SEGE (1<<10) /* expand down */
#define SEGW (1<<9) /* writable (for data/stack) */
#define SEGR (1<<9) /* readable (for code) */
#define SEGD (1<<22) /* default 1==32bit (for code) */
/*
* virtual MMU
*/
#define PTEMAPMEM (1024*1024) /* ??? */
#define SEGMAPSIZE 16 /* ??? */
#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */
#define PPN(x) ((x)&~(BY2PG-1))
/*
* physical MMU
*/
#define PTEVALID (1<<0)
#define PTEUNCACHED 0 /* everything is uncached */
#define PTEWRITE (1<<1)
#define PTERONLY (0<<1)
#define PTEKERNEL (0<<2)
#define PTEUSER (1<<2)
/*
* flag register bits that we care about
*/
#define IFLAG 0x200
#define OP16 BYTE $0x66
/*
* about to walk all over ms/dos - turn off interrupts
*/
TEXT origin(SB),$0
CLI
#ifdef BOOT
/*
* This part of l.s is used only in the boot kernel.
* It assumes that we are in real address mode, i.e.,
* that we look like an 8086.
*/
/*
* relocate everything to a half meg and jump there
* - looks wierd because it is being assembled by a 32 bit
* assembler for a 16 bit world
*/
MOVL $0,BX
INCL BX
SHLL $15,BX
MOVL BX,CX
MOVW BX,ES
MOVL $0,SI
MOVL SI,DI
CLD; REP; MOVSL
/* JMPFAR 0X8000:$lowcore(SB) /**/
BYTE $0xEA
WORD $lowcore(SB)
WORD $0X8000
TEXT lowcore(SB),$0
/*
* now that we're in low core, update the DS
*/
MOVW BX,DS
/*
* goto protected mode
*/
/* MOVL tgdtptr(SB),GDTR /**/
BYTE $0x0f
BYTE $0x01
BYTE $0x16
WORD $tgdtptr(SB)
MOVL CR0,AX
ORL $1,AX
MOVL AX,CR0
/*
* clear prefetch queue (wierd code to avoid optimizations)
*/
CLC
JCC flush
MOVL AX,AX
flush:
/*
* set all segs
*/
/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/
BYTE $0xc7
BYTE $0xc0
WORD $SELECTOR(1, SELGDT, 0)
MOVW AX,DS
MOVW AX,SS
MOVW AX,ES
MOVW AX,FS
MOVW AX,GS
/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
BYTE $0x66
BYTE $0xEA
LONG $mode32bit-KZERO(SB)
WORD $SELECTOR(2, SELGDT, 0)
TEXT mode32bit(SB),$0
#endif BOOT
/*
* Clear BSS
*/
LEAL edata-KZERO(SB),SI
MOVL SI,DI
ADDL $4,DI
MOVL $0,AX
MOVL AX,(SI)
LEAL end-KZERO(SB),CX
SUBL DI,CX
SHRL $2,CX
CLD; REP; MOVSL
/*
* make a bottom level page table page that maps the first
* 16 meg of physical memory
*/
LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
ADDL $(BY2PG-1),AX /* must be page alligned */
ANDL $(~(BY2PG-1)),AX /* ... */
MOVL $(4*1024),CX /* pte's per page */
MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
setpte:
MOVL BX,-4(AX)(CX*4)
SUBL $(1<<PGSHIFT),BX
LOOP setpte
/*
* make a top level page table page that maps the first
* 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
*/
MOVL AX,BX
ADDL $(4*BY2PG),AX
ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
MOVL BX,0(AX)
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
ADDL $BY2PG,BX
MOVL BX,4(AX)
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
ADDL $BY2PG,BX
MOVL BX,8(AX)
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
ADDL $BY2PG,BX
MOVL BX,12(AX)
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)
/*
* point processor to top level page & turn on paging
*/
MOVL AX,CR3
MOVL CR0,AX
ORL $0X80000000,AX
ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */
MOVL AX,CR0
/*
* use a jump to an absolute location to get the PC into
* KZERO.
*/
LEAL tokzero(SB),AX
JMP* AX
TEXT tokzero(SB),$0
/*
* stack and mach
*/
MOVL $mach0(SB),SP
MOVL SP,m(SB)
MOVL $0,0(SP)
ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
MOVL $0, u(SB)
/*
* clear flags
*/
MOVL $0,AX
PUSHL AX
POPFL
CALL main(SB)
loop:
JMP loop
GLOBL mach0+0(SB), $MACHSIZE
GLOBL u(SB), $4
GLOBL m(SB), $4
GLOBL tpt(SB), $(BY2PG*6)
/*
* gdt to get us to 32-bit/segmented/unpaged mode
*/
TEXT tgdt(SB),$0
/* null descriptor */
LONG $0
LONG $0
/* data segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
/* exec segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
/*
* pointer to initial gdt
*/
TEXT tgdtptr(SB),$0
WORD $(3*8)
LONG $tgdt-KZERO(SB)
/*
* input a byte
*/
TEXT inb(SB),$0
MOVL p+0(FP),DX
XORL AX,AX
INB
RET
/*
* output a byte
*/
TEXT outb(SB),$0
MOVL p+0(FP),DX
MOVL b+4(FP),AX
OUTB
RET
/*
* input a string of shorts from a port
*/
TEXT inss(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),DI
MOVL c+8(FP),CX
CLD; REP; OP16; INSL
RET
/*
* output a string of shorts to a port
*/
TEXT outss(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),SI
MOVL c+8(FP),CX
CLD; REP; OP16; OUTSL
RET
/*
* test and set
*/
TEXT tas(SB),$0
MOVL $0xdeadead,AX
MOVL l+0(FP),BX
XCHGL AX,(BX)
RET
/*
* routines to load/read various system registers
*/
GLOBL idtptr(SB),$6
TEXT putidt(SB),$0 /* interrupt descriptor table */
MOVL t+0(FP),AX
MOVL AX,idtptr+2(SB)
MOVL l+4(FP),AX
MOVW AX,idtptr(SB)
MOVL idtptr(SB),IDTR
RET
GLOBL gdtptr(SB),$6
TEXT putgdt(SB),$0 /* global descriptor table */
MOVL t+0(FP),AX
MOVL AX,gdtptr+2(SB)
MOVL l+4(FP),AX
MOVW AX,gdtptr(SB)
MOVL gdtptr(SB),GDTR
RET
TEXT putcr3(SB),$0 /* top level page table pointer */
MOVL t+0(FP),AX
MOVL AX,CR3
RET
TEXT puttr(SB),$0 /* task register */
MOVL t+0(FP),AX
MOVW AX,TASK
RET
TEXT getcr0(SB),$0 /* coprocessor bits */
MOVL CR0,AX
RET
TEXT getcr2(SB),$0 /* fault address */
MOVL CR2,AX
RET
#define FPOFF\
WAIT;\
MOVL CR0,AX;\
ORL $0x4,AX /* EM=1 */;\
MOVL AX,CR0
#define FPON\
MOVL CR0,AX;\
ANDL $~0x4,AX /* EM=0 */;\
MOVL AX,CR0
TEXT fpoff(SB),$0 /* turn off floating point */
FPOFF
RET
TEXT fpinit(SB),$0 /* turn on & init the floating point */
FPON
FINIT
WAIT
PUSHW $0x0330
FLDCW 0(SP) /* ignore underflow/precision, signal others */
POPW AX
WAIT
RET
TEXT fpsave(SB),$0 /* save floating point state and turn off */
MOVL p+0(FP),AX
WAIT
FSAVE 0(AX)
FPOFF
RET
TEXT fprestore(SB),$0 /* turn on floating point and restore regs */
FPON
MOVL p+0(FP),AX
FRSTOR 0(AX)
WAIT
RET
TEXT fpstatus(SB),$0 /* get floating point status */
FSTSW AX
RET
/*
* special traps
*/
TEXT intr0(SB),$0
PUSHL $0
PUSHL $0
JMP intrcommon
TEXT intr1(SB),$0
PUSHL $0
PUSHL $1
JMP intrcommon
TEXT intr2(SB),$0
PUSHL $0
PUSHL $2
JMP intrcommon
TEXT intr3(SB),$0
PUSHL $0
PUSHL $3
JMP intrcommon
TEXT intr4(SB),$0
PUSHL $0
PUSHL $4
JMP intrcommon
TEXT intr5(SB),$0
PUSHL $0
PUSHL $5
JMP intrcommon
TEXT intr6(SB),$0
PUSHL $0
PUSHL $6
JMP intrcommon
TEXT intr7(SB),$0
PUSHL $0
PUSHL $7
JMP intrcommon
TEXT intr8(SB),$0
PUSHL $8
JMP intrscommon
TEXT intr9(SB),$0
PUSHL $0
PUSHL $9
JMP intrcommon
TEXT intr10(SB),$0
PUSHL $10
JMP intrscommon
TEXT intr11(SB),$0
PUSHL $11
JMP intrscommon
TEXT intr12(SB),$0
PUSHL $12
JMP intrscommon
TEXT intr13(SB),$0
PUSHL $13
JMP intrscommon
TEXT intr14(SB),$0
PUSHL $14
JMP intrscommon
TEXT intr15(SB),$0
PUSHL $0
PUSHL $15
JMP intrcommon
TEXT intr16(SB),$0
PUSHL $0
PUSHL $16
JMP intrcommon
TEXT intr24(SB),$0
PUSHL $0
PUSHL $24
JMP intrcommon
TEXT intr25(SB),$0
PUSHL $0
PUSHL $25
JMP intrcommon
TEXT intr26(SB),$0
PUSHL $0
PUSHL $26
JMP intrcommon
TEXT intr27(SB),$0
PUSHL $0
PUSHL $27
JMP intrcommon
TEXT intr28(SB),$0
PUSHL $0
PUSHL $28
JMP intrcommon
TEXT intr29(SB),$0
PUSHL $0
PUSHL $29
JMP intrcommon
TEXT intr30(SB),$0
PUSHL $0
PUSHL $30
JMP intrcommon
TEXT intr31(SB),$0
PUSHL $0
PUSHL $31
JMP intrcommon
TEXT intr32(SB),$0
PUSHL $0
PUSHL $16
JMP intrcommon
TEXT intr33(SB),$0
PUSHL $0
PUSHL $33
JMP intrcommon
TEXT intr34(SB),$0
PUSHL $0
PUSHL $34
JMP intrcommon
TEXT intr35(SB),$0
PUSHL $0
PUSHL $35
JMP intrcommon
TEXT intr36(SB),$0
PUSHL $0
PUSHL $36
JMP intrcommon
TEXT intr37(SB),$0
PUSHL $0
PUSHL $37
JMP intrcommon
TEXT intr38(SB),$0
PUSHL $0
PUSHL $38
JMP intrcommon
TEXT intr39(SB),$0
PUSHL $0
PUSHL $39
JMP intrcommon
TEXT intr64(SB),$0
PUSHL $0
PUSHL $64
JMP intrcommon
TEXT intrbad(SB),$0
PUSHL $0
PUSHL $0x1ff
JMP intrcommon
intrcommon:
PUSHL DS
PUSHL ES
PUSHL FS
PUSHL GS
PUSHAL
MOVL $(KDSEL),AX
MOVW AX,DS
MOVW AX,ES
LEAL 0(SP),AX
PUSHL AX
CALL trap(SB)
POPL AX
POPAL
POPL GS
POPL FS
POPL ES
POPL DS
ADDL $8,SP /* error code and trap type */
IRETL
intrscommon:
PUSHL DS
PUSHL ES
PUSHL FS
PUSHL GS
PUSHAL
MOVL $(KDSEL),AX
MOVW AX,DS
MOVW AX,ES
LEAL 0(SP),AX
PUSHL AX
CALL trap(SB)
POPL AX
POPAL
POPL GS
POPL FS
POPL ES
POPL DS
ADDL $8,SP /* error code and trap type */
IRETL
/*
* interrupt level is interrupts on or off
*/
TEXT spllo(SB),$0
PUSHFL
POPL AX
STI
RET
TEXT splhi(SB),$0
PUSHFL
POPL AX
CLI
RET
TEXT splx(SB),$0
MOVL s+0(FP),AX
PUSHL AX
POPFL
RET
/*
* do nothing whatsoever till interrupt happens
*/
TEXT idle(SB),$0
HLT
RET
/*
* label consists of a stack pointer and a PC
*/
TEXT gotolabel(SB),$0
MOVL l+0(FP),AX
MOVL 0(AX),SP /* restore sp */
MOVL 4(AX),AX /* put return pc on the stack */
MOVL AX,0(SP)
MOVL $1,AX /* return 1 */
RET
TEXT setlabel(SB),$0
MOVL l+0(FP),AX
MOVL SP,0(AX) /* store sp */
MOVL 0(SP),BX /* store return pc */
MOVL BX,4(AX)
MOVL $0,AX /* return 0 */
RET
/*
* Used to get to the first process.
* Set up an interrupt return frame and IRET to user level.
*/
TEXT touser(SB),$0
PUSHL $(UDSEL) /* old ss */
PUSHL $(USTKTOP) /* old sp */
PUSHFL /* old flags */
PUSHL $(UESEL) /* old cs */
PUSHL $(UTZERO+32) /* old pc */
MOVL $(UDSEL),AX
MOVW AX,DS
MOVW AX,ES
MOVW AX,GS
MOVW AX,FS
IRETL
/*
* set configuration register
*/
TEXT config(SB),$0
MOVL l+0(FP),AX
MOVL $0x3F3,DX
OUTB
OUTB
RET
// Inferno utils/8a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define EXTERN
#include "a.h"
#include "y.tab.h"
#include <ctype.h>
void
main(int argc, char *argv[])
{
char *p;
int nout, nproc, status, i, c;
thechar = '8';
thestring = "386";
memset(debug, 0, sizeof(debug));
cinit();
outfile = 0;
include[ninclude++] = ".";
ARGBEGIN {
default:
c = ARGC();
if(c >= 0 || c < sizeof(debug))
debug[c] = 1;
break;
case 'o':
outfile = ARGF();
break;
case 'D':
p = ARGF();
if(p)
Dlist[nDlist++] = p;
break;
case 'I':
p = ARGF();
setinclude(p);
break;
} ARGEND
if(*argv == 0) {
print("usage: %ca [-options] file.s\n", thechar);
errorexit();
}
if(argc > 1 && systemtype(Windows)){
print("can't assemble multiple files on windows\n");
errorexit();
}
if(argc > 1 && !systemtype(Windows)) {
nproc = 1;
if(p = getenv("NPROC"))
nproc = atol(p); /* */
c = 0;
nout = 0;
for(;;) {
while(nout < nproc && argc > 0) {
i = myfork();
if(i < 0) {
i = mywait(&status);
if(i < 0)
errorexit();
if(status)
c++;
nout--;
continue;
}
if(i == 0) {
print("%s:\n", *argv);
if(assemble(*argv))
errorexit();
exits(0);
}
nout++;
argc--;
argv++;
}
i = mywait(&status);
if(i < 0) {
if(c)
errorexit();
exits(0);
}
if(status)
c++;
nout--;
}
}
if(assemble(argv[0]))
errorexit();
exits(0);
}
int
assemble(char *file)
{
char ofile[100], incfile[20], *p;
int i, of;
strcpy(ofile, file);
p = utfrrune(ofile, pathchar());
if(p) {
include[0] = ofile;
*p++ = 0;
} else
p = ofile;
if(outfile == 0) {
outfile = p;
if(outfile){
p = utfrrune(outfile, '.');
if(p)
if(p[1] == 's' && p[2] == 0)
p[0] = 0;
p = utfrune(outfile, 0);
p[0] = '.';
p[1] = thechar;
p[2] = 0;
} else
outfile = "/dev/null";
}
p = getenv("INCLUDE");
if(p) {
setinclude(p);
} else {
if(systemtype(Plan9)) {
sprint(incfile,"/%s/include", thestring);
setinclude(strdup(incfile));
}
}
of = mycreat(outfile, 0664);
if(of < 0) {
yyerror("%ca: cannot create %s", thechar, outfile);
errorexit();
}
Binit(&obuf, of, OWRITE);
pass = 1;
pinit(file);
for(i=0; i<nDlist; i++)
dodefine(Dlist[i]);
yyparse();
if(nerrors) {
cclean();
return nerrors;
}
pass = 2;
outhist();
pinit(file);
for(i=0; i<nDlist; i++)
dodefine(Dlist[i]);
yyparse();
cclean();
return nerrors;
}
struct
{
char *name;
ushort type;
ushort value;
} itab[] =
{
"SP", LSP, D_AUTO,
"SB", LSB, D_EXTERN,
"FP", LFP, D_PARAM,
"PC", LPC, D_BRANCH,
"AL", LBREG, D_AL,
"CL", LBREG, D_CL,
"DL", LBREG, D_DL,
"BL", LBREG, D_BL,
"AH", LBREG, D_AH,
"CH", LBREG, D_CH,
"DH", LBREG, D_DH,
"BH", LBREG, D_BH,
"AX", LLREG, D_AX,
"CX", LLREG, D_CX,
"DX", LLREG, D_DX,
"BX", LLREG, D_BX,
/* "SP", LLREG, D_SP, */
"BP", LLREG, D_BP,
"SI", LLREG, D_SI,
"DI", LLREG, D_DI,
"F0", LFREG, D_F0+0,
"F1", LFREG, D_F0+1,
"F2", LFREG, D_F0+2,
"F3", LFREG, D_F0+3,
"F4", LFREG, D_F0+4,
"F5", LFREG, D_F0+5,
"F6", LFREG, D_F0+6,
"F7", LFREG, D_F0+7,
"CS", LSREG, D_CS,
"SS", LSREG, D_SS,
"DS", LSREG, D_DS,
"ES", LSREG, D_ES,
"FS", LSREG, D_FS,
"GS", LSREG, D_GS,
"GDTR", LBREG, D_GDTR,
"IDTR", LBREG, D_IDTR,
"LDTR", LBREG, D_LDTR,
"MSW", LBREG, D_MSW,
"TASK", LBREG, D_TASK,
"CR0", LBREG, D_CR+0,
"CR1", LBREG, D_CR+1,
"CR2", LBREG, D_CR+2,
"CR3", LBREG, D_CR+3,
"CR4", LBREG, D_CR+4,
"CR5", LBREG, D_CR+5,
"CR6", LBREG, D_CR+6,
"CR7", LBREG, D_CR+7,
"DR0", LBREG, D_DR+0,
"DR1", LBREG, D_DR+1,
"DR2", LBREG, D_DR+2,
"DR3", LBREG, D_DR+3,
"DR4", LBREG, D_DR+4,
"DR5", LBREG, D_DR+5,
"DR6", LBREG, D_DR+6,
"DR7", LBREG, D_DR+7,
"TR0", LBREG, D_TR+0,
"TR1", LBREG, D_TR+1,
"TR2", LBREG, D_TR+2,
"TR3", LBREG, D_TR+3,
"TR4", LBREG, D_TR+4,
"TR5", LBREG, D_TR+5,
"TR6", LBREG, D_TR+6,
"TR7", LBREG, D_TR+7,
"AAA", LTYPE0, AAAA,
"AAD", LTYPE0, AAAD,
"AAM", LTYPE0, AAAM,
"AAS", LTYPE0, AAAS,
"ADCB", LTYPE3, AADCB,
"ADCL", LTYPE3, AADCL,
"ADCW", LTYPE3, AADCW,
"ADDB", LTYPE3, AADDB,
"ADDL", LTYPE3, AADDL,
"ADDW", LTYPE3, AADDW,
"ADJSP", LTYPE2, AADJSP,
"ANDB", LTYPE3, AANDB,
"ANDL", LTYPE3, AANDL,
"ANDW", LTYPE3, AANDW,
"ARPL", LTYPE3, AARPL,
"BOUNDL", LTYPE3, ABOUNDL,
"BOUNDW", LTYPE3, ABOUNDW,
"BSFL", LTYPE3, ABSFL,
"BSFW", LTYPE3, ABSFW,
"BSRL", LTYPE3, ABSRL,
"BSRW", LTYPE3, ABSRW,
"BTCL", LTYPE3, ABTCL,
"BTCW", LTYPE3, ABTCW,
"BTL", LTYPE3, ABTL,
"BTRL", LTYPE3, ABTRL,
"BTRW", LTYPE3, ABTRW,
"BTSL", LTYPE3, ABTSL,
"BTSW", LTYPE3, ABTSW,
"BTW", LTYPE3, ABTW,
"BYTE", LTYPE2, ABYTE,
"CALL", LTYPEC, ACALL,
"CLC", LTYPE0, ACLC,
"CLD", LTYPE0, ACLD,
"CLI", LTYPE0, ACLI,
"CLTS", LTYPE0, ACLTS,
"CMC", LTYPE0, ACMC,
"CMPB", LTYPE4, ACMPB,
"CMPL", LTYPE4, ACMPL,
"CMPW", LTYPE4, ACMPW,
"CMPSB", LTYPE0, ACMPSB,
"CMPSL", LTYPE0, ACMPSL,
"CMPSW", LTYPE0, ACMPSW,
"DAA", LTYPE0, ADAA,
"DAS", LTYPE0, ADAS,
"DATA", LTYPED, ADATA,
"DECB", LTYPE1, ADECB,
"DECL", LTYPE1, ADECL,
"DECW", LTYPE1, ADECW,
"DIVB", LTYPE2, ADIVB,
"DIVL", LTYPE2, ADIVL,
"DIVW", LTYPE2, ADIVW,
"END", LTYPE0, AEND,
"ENTER", LTYPE2, AENTER,
"GLOBL", LTYPET, AGLOBL,
"HLT", LTYPE0, AHLT,
"IDIVB", LTYPE2, AIDIVB,
"IDIVL", LTYPE2, AIDIVL,
"IDIVW", LTYPE2, AIDIVW,
"IMULB", LTYPE2, AIMULB,
"IMULL", LTYPE2, AIMULL,
"IMULW", LTYPE2, AIMULW,
"INB", LTYPE0, AINB,
"INL", LTYPE0, AINL,
"INW", LTYPE0, AINW,
"INCB", LTYPE1, AINCB,
"INCL", LTYPE1, AINCL,
"INCW", LTYPE1, AINCW,
"INSB", LTYPE0, AINSB,
"INSL", LTYPE0, AINSL,
"INSW", LTYPE0, AINSW,
"INT", LTYPE2, AINT,
"INTO", LTYPE0, AINTO,
"IRETL", LTYPE0, AIRETL,
"IRETW", LTYPE0, AIRETW,
"JOS", LTYPER, AJOS,
"JO", LTYPER, AJOS, /* alternate */
"JOC", LTYPER, AJOC,
"JNO", LTYPER, AJOC, /* alternate */
"JCS", LTYPER, AJCS,
"JB", LTYPER, AJCS, /* alternate */
"JC", LTYPER, AJCS, /* alternate */
"JNAE", LTYPER, AJCS, /* alternate */
"JLO", LTYPER, AJCS, /* alternate */
"JCC", LTYPER, AJCC,
"JAE", LTYPER, AJCC, /* alternate */
"JNB", LTYPER, AJCC, /* alternate */
"JNC", LTYPER, AJCC, /* alternate */
"JHS", LTYPER, AJCC, /* alternate */
"JEQ", LTYPER, AJEQ,
"JE", LTYPER, AJEQ, /* alternate */
"JZ", LTYPER, AJEQ, /* alternate */
"JNE", LTYPER, AJNE,
"JNZ", LTYPER, AJNE, /* alternate */
"JLS", LTYPER, AJLS,
"JBE", LTYPER, AJLS, /* alternate */
"JNA", LTYPER, AJLS, /* alternate */
"JHI", LTYPER, AJHI,
"JA", LTYPER, AJHI, /* alternate */
"JNBE", LTYPER, AJHI, /* alternate */
"JMI", LTYPER, AJMI,
"JS", LTYPER, AJMI, /* alternate */
"JPL", LTYPER, AJPL,
"JNS", LTYPER, AJPL, /* alternate */
"JPS", LTYPER, AJPS,
"JP", LTYPER, AJPS, /* alternate */
"JPE", LTYPER, AJPS, /* alternate */
"JPC", LTYPER, AJPC,
"JNP", LTYPER, AJPC, /* alternate */
"JPO", LTYPER, AJPC, /* alternate */
"JLT", LTYPER, AJLT,
"JL", LTYPER, AJLT, /* alternate */
"JNGE", LTYPER, AJLT, /* alternate */
"JGE", LTYPER, AJGE,
"JNL", LTYPER, AJGE, /* alternate */
"JLE", LTYPER, AJLE,
"JNG", LTYPER, AJLE, /* alternate */
"JGT", LTYPER, AJGT,
"JG", LTYPER, AJGT, /* alternate */
"JNLE", LTYPER, AJGT, /* alternate */
"JCXZ", LTYPER, AJCXZ,
"JMP", LTYPEC, AJMP,
"LAHF", LTYPE0, ALAHF,
"LARL", LTYPE3, ALARL,
"LARW", LTYPE3, ALARW,
"LEAL", LTYPE3, ALEAL,
"LEAW", LTYPE3, ALEAW,
"LEAVEL", LTYPE0, ALEAVEL,
"LEAVEW", LTYPE0, ALEAVEW,
"LOCK", LTYPE0, ALOCK,
"LODSB", LTYPE0, ALODSB,
"LODSL", LTYPE0, ALODSL,
"LODSW", LTYPE0, ALODSW,
"LONG", LTYPE2, ALONG,
"LOOP", LTYPER, ALOOP,
"LOOPEQ", LTYPER, ALOOPEQ,
"LOOPNE", LTYPER, ALOOPNE,
"LSLL", LTYPE3, ALSLL,
"LSLW", LTYPE3, ALSLW,
"MOVB", LTYPE3, AMOVB,
"MOVL", LTYPEM, AMOVL,
"MOVW", LTYPEM, AMOVW,
"MOVBLSX", LTYPE3, AMOVBLSX,
"MOVBLZX", LTYPE3, AMOVBLZX,
"MOVBWSX", LTYPE3, AMOVBWSX,
"MOVBWZX", LTYPE3, AMOVBWZX,
"MOVWLSX", LTYPE3, AMOVWLSX,
"MOVWLZX", LTYPE3, AMOVWLZX,
"MOVSB", LTYPE0, AMOVSB,
"MOVSL", LTYPE0, AMOVSL,
"MOVSW", LTYPE0, AMOVSW,
"MULB", LTYPE2, AMULB,
"MULL", LTYPE2, AMULL,
"MULW", LTYPE2, AMULW,
"NEGB", LTYPE1, ANEGB,
"NEGL", LTYPE1, ANEGL,
"NEGW", LTYPE1, ANEGW,
"NOP", LTYPEN, ANOP,
"NOTB", LTYPE1, ANOTB,
"NOTL", LTYPE1, ANOTL,
"NOTW", LTYPE1, ANOTW,
"ORB", LTYPE3, AORB,
"ORL", LTYPE3, AORL,
"ORW", LTYPE3, AORW,
"OUTB", LTYPE0, AOUTB,
"OUTL", LTYPE0, AOUTL,
"OUTW", LTYPE0, AOUTW,
"OUTSB", LTYPE0, AOUTSB,
"OUTSL", LTYPE0, AOUTSL,
"OUTSW", LTYPE0, AOUTSW,
"POPAL", LTYPE0, APOPAL,
"POPAW", LTYPE0, APOPAW,
"POPFL", LTYPE0, APOPFL,
"POPFW", LTYPE0, APOPFW,
"POPL", LTYPE1, APOPL,
"POPW", LTYPE1, APOPW,
"PUSHAL", LTYPE0, APUSHAL,
"PUSHAW", LTYPE0, APUSHAW,
"PUSHFL", LTYPE0, APUSHFL,
"PUSHFW", LTYPE0, APUSHFW,
"PUSHL", LTYPE2, APUSHL,
"PUSHW", LTYPE2, APUSHW,
"RCLB", LTYPE3, ARCLB,
"RCLL", LTYPE3, ARCLL,
"RCLW", LTYPE3, ARCLW,
"RCRB", LTYPE3, ARCRB,
"RCRL", LTYPE3, ARCRL,
"RCRW", LTYPE3, ARCRW,
"REP", LTYPE0, AREP,
"REPN", LTYPE0, AREPN,
"RET", LTYPE0, ARET,
"ROLB", LTYPE3, AROLB,
"ROLL", LTYPE3, AROLL,
"ROLW", LTYPE3, AROLW,
"RORB", LTYPE3, ARORB,
"RORL", LTYPE3, ARORL,
"RORW", LTYPE3, ARORW,
"SAHF", LTYPE0, ASAHF,
"SALB", LTYPE3, ASALB,
"SALL", LTYPE3, ASALL,
"SALW", LTYPE3, ASALW,
"SARB", LTYPE3, ASARB,
"SARL", LTYPE3, ASARL,
"SARW", LTYPE3, ASARW,
"SBBB", LTYPE3, ASBBB,
"SBBL", LTYPE3, ASBBL,
"SBBW", LTYPE3, ASBBW,
"SCASB", LTYPE0, ASCASB,
"SCASL", LTYPE0, ASCASL,
"SCASW", LTYPE0, ASCASW,
"SETCC", LTYPE1, ASETCC,
"SETCS", LTYPE1, ASETCS,
"SETEQ", LTYPE1, ASETEQ,
"SETGE", LTYPE1, ASETGE,
"SETGT", LTYPE1, ASETGT,
"SETHI", LTYPE1, ASETHI,
"SETLE", LTYPE1, ASETLE,
"SETLS", LTYPE1, ASETLS,
"SETLT", LTYPE1, ASETLT,
"SETMI", LTYPE1, ASETMI,
"SETNE", LTYPE1, ASETNE,
"SETOC", LTYPE1, ASETOC,
"SETOS", LTYPE1, ASETOS,
"SETPC", LTYPE1, ASETPC,
"SETPL", LTYPE1, ASETPL,
"SETPS", LTYPE1, ASETPS,
"CDQ", LTYPE0, ACDQ,
"CWD", LTYPE0, ACWD,
"SHLB", LTYPE3, ASHLB,
"SHLL", LTYPES, ASHLL,
"SHLW", LTYPES, ASHLW,
"SHRB", LTYPE3, ASHRB,
"SHRL", LTYPES, ASHRL,
"SHRW", LTYPES, ASHRW,
"STC", LTYPE0, ASTC,
"STD", LTYPE0, ASTD,
"STI", LTYPE0, ASTI,
"STOSB", LTYPE0, ASTOSB,
"STOSL", LTYPE0, ASTOSL,
"STOSW", LTYPE0, ASTOSW,
"SUBB", LTYPE3, ASUBB,
"SUBL", LTYPE3, ASUBL,
"SUBW", LTYPE3, ASUBW,
"SYSCALL", LTYPE0, ASYSCALL,
"TESTB", LTYPE3, ATESTB,
"TESTL", LTYPE3, ATESTL,
"TESTW", LTYPE3, ATESTW,
"TEXT", LTYPET, ATEXT,
"VERR", LTYPE2, AVERR,
"VERW", LTYPE2, AVERW,
"WAIT", LTYPE0, AWAIT,
"WORD", LTYPE2, AWORD,
"XCHGB", LTYPE3, AXCHGB,
"XCHGL", LTYPE3, AXCHGL,
"XCHGW", LTYPE3, AXCHGW,
"XLAT", LTYPE2, AXLAT,
"XORB", LTYPE3, AXORB,
"XORL", LTYPE3, AXORL,
"XORW", LTYPE3, AXORW,
"FMOVB", LTYPE3, AFMOVB,
"FMOVBP", LTYPE3, AFMOVBP,
"FMOVD", LTYPE3, AFMOVD,
"FMOVDP", LTYPE3, AFMOVDP,
"FMOVF", LTYPE3, AFMOVF,
"FMOVFP", LTYPE3, AFMOVFP,
"FMOVL", LTYPE3, AFMOVL,
"FMOVLP", LTYPE3, AFMOVLP,
"FMOVV", LTYPE3, AFMOVV,
"FMOVVP", LTYPE3, AFMOVVP,
"FMOVW", LTYPE3, AFMOVW,
"FMOVWP", LTYPE3, AFMOVWP,
"FMOVX", LTYPE3, AFMOVX,
"FMOVXP", LTYPE3, AFMOVXP,
"FCOMB", LTYPE3, AFCOMB,
"FCOMBP", LTYPE3, AFCOMBP,
"FCOMD", LTYPE3, AFCOMD,
"FCOMDP", LTYPE3, AFCOMDP,
"FCOMDPP", LTYPE3, AFCOMDPP,
"FCOMF", LTYPE3, AFCOMF,
"FCOMFP", LTYPE3, AFCOMFP,
"FCOML", LTYPE3, AFCOML,
"FCOMLP", LTYPE3, AFCOMLP,
"FCOMW", LTYPE3, AFCOMW,
"FCOMWP", LTYPE3, AFCOMWP,
"FUCOM", LTYPE3, AFUCOM,
"FUCOMP", LTYPE3, AFUCOMP,
"FUCOMPP", LTYPE3, AFUCOMPP,
"FADDW", LTYPE3, AFADDW,
"FADDL", LTYPE3, AFADDL,
"FADDF", LTYPE3, AFADDF,
"FADDD", LTYPE3, AFADDD,
"FADDDP", LTYPE3, AFADDDP,
"FSUBDP", LTYPE3, AFSUBDP,
"FSUBW", LTYPE3, AFSUBW,
"FSUBL", LTYPE3, AFSUBL,
"FSUBF", LTYPE3, AFSUBF,
"FSUBD", LTYPE3, AFSUBD,
"FSUBRDP", LTYPE3, AFSUBRDP,
"FSUBRW", LTYPE3, AFSUBRW,
"FSUBRL", LTYPE3, AFSUBRL,
"FSUBRF", LTYPE3, AFSUBRF,
"FSUBRD", LTYPE3, AFSUBRD,
"FMULDP", LTYPE3, AFMULDP,
"FMULW", LTYPE3, AFMULW,
"FMULL", LTYPE3, AFMULL,
"FMULF", LTYPE3, AFMULF,
"FMULD", LTYPE3, AFMULD,
"FDIVDP", LTYPE3, AFDIVDP,
"FDIVW", LTYPE3, AFDIVW,
"FDIVL", LTYPE3, AFDIVL,
"FDIVF", LTYPE3, AFDIVF,
"FDIVD", LTYPE3, AFDIVD,
"FDIVRDP", LTYPE3, AFDIVRDP,
"FDIVRW", LTYPE3, AFDIVRW,
"FDIVRL", LTYPE3, AFDIVRL,
"FDIVRF", LTYPE3, AFDIVRF,
"FDIVRD", LTYPE3, AFDIVRD,
"FXCHD", LTYPE3, AFXCHD,
"FFREE", LTYPE1, AFFREE,
"FLDCW", LTYPE2, AFLDCW,
"FLDENV", LTYPE1, AFLDENV,
"FRSTOR", LTYPE2, AFRSTOR,
"FSAVE", LTYPE1, AFSAVE,
"FSTCW", LTYPE1, AFSTCW,
"FSTENV", LTYPE1, AFSTENV,
"FSTSW", LTYPE1, AFSTSW,
"F2XM1", LTYPE0, AF2XM1,
"FABS", LTYPE0, AFABS,
"FCHS", LTYPE0, AFCHS,
"FCLEX", LTYPE0, AFCLEX,
"FCOS", LTYPE0, AFCOS,
"FDECSTP", LTYPE0, AFDECSTP,
"FINCSTP", LTYPE0, AFINCSTP,
"FINIT", LTYPE0, AFINIT,
"FLD1", LTYPE0, AFLD1,
"FLDL2E", LTYPE0, AFLDL2E,
"FLDL2T", LTYPE0, AFLDL2T,
"FLDLG2", LTYPE0, AFLDLG2,
"FLDLN2", LTYPE0, AFLDLN2,
"FLDPI", LTYPE0, AFLDPI,
"FLDZ", LTYPE0, AFLDZ,
"FNOP", LTYPE0, AFNOP,
"FPATAN", LTYPE0, AFPATAN,
"FPREM", LTYPE0, AFPREM,
"FPREM1", LTYPE0, AFPREM1,
"FPTAN", LTYPE0, AFPTAN,
"FRNDINT", LTYPE0, AFRNDINT,
"FSCALE", LTYPE0, AFSCALE,
"FSIN", LTYPE0, AFSIN,
"FSINCOS", LTYPE0, AFSINCOS,
"FSQRT", LTYPE0, AFSQRT,
"FTST", LTYPE0, AFTST,
"FXAM", LTYPE0, AFXAM,
"FXTRACT", LTYPE0, AFXTRACT,
"FYL2X", LTYPE0, AFYL2X,
"FYL2XP1", LTYPE0, AFYL2XP1,
0
};
void
cinit(void)
{
Sym *s;
int i;
nullgen.sym = S;
nullgen.offset = 0;
if(FPCHIP)
nullgen.dval = 0;
for(i=0; i<sizeof(nullgen.sval); i++)
nullgen.sval[i] = 0;
nullgen.type = D_NONE;
nullgen.index = D_NONE;
nullgen.scale = 0;
nerrors = 0;
iostack = I;
iofree = I;
peekc = IGN;
nhunk = 0;
for(i=0; i<NHASH; i++)
hash[i] = S;
for(i=0; itab[i].name; i++) {
s = slookup(itab[i].name);
if(s->type != LNAME)
yyerror("double initialization %s", itab[i].name);
s->type = itab[i].type;
s->value = itab[i].value;
}
pathname = allocn(pathname, 0, 100);
if(mygetwd(pathname, 99) == 0) {
pathname = allocn(pathname, 100, 900);
if(mygetwd(pathname, 999) == 0)
strcpy(pathname, "/???");
}
}
void
checkscale(int scale)
{
switch(scale) {
case 1:
case 2:
case 4:
case 8:
return;
}
yyerror("scale must be 1248: %d", scale);
}
void
syminit(Sym *s)
{
s->type = LNAME;
s->value = 0;
}
void
cclean(void)
{
Gen2 g2;
g2.from = nullgen;
g2.to = nullgen;
outcode(AEND, &g2);
Bflush(&obuf);
}
void
zname(char *n, int t, int s)
{
Bputc(&obuf, ANAME); /* as(2) */
Bputc(&obuf, ANAME>>8);
Bputc(&obuf, t); /* type */
Bputc(&obuf, s); /* sym */
while(*n) {
Bputc(&obuf, *n);
n++;
}
Bputc(&obuf, 0);
}
void
zaddr(Gen *a, int s)
{
long l;
int i, t;
char *n;
Ieee e;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(a->offset != 0)
t |= T_OFFSET;
if(s != 0)
t |= T_SYM;
switch(a->type) {
default:
t |= T_TYPE;
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
case D_NONE:
break;
}
Bputc(&obuf, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(&obuf, a->index);
Bputc(&obuf, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(&obuf, l);
Bputc(&obuf, l>>8);
Bputc(&obuf, l>>16);
Bputc(&obuf, l>>24);
}
if(t & T_SYM) /* implies sym */
Bputc(&obuf, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e.l;
Bputc(&obuf, l);
Bputc(&obuf, l>>8);
Bputc(&obuf, l>>16);
Bputc(&obuf, l>>24);
l = e.h;
Bputc(&obuf, l);
Bputc(&obuf, l>>8);
Bputc(&obuf, l>>16);
Bputc(&obuf, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(&obuf, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(&obuf, a->type);
}
void
outcode(int a, Gen2 *g2)
{
int sf, st, t;
Sym *s;
if(pass == 1)
goto out;
jackpot:
sf = 0;
s = g2->from.sym;
while(s != S) {
sf = s->sym;
if(sf < 0 || sf >= NSYM)
sf = 0;
t = g2->from.type;
if(t == D_ADDR)
t = g2->from.index;
if(h[sf].type == t)
if(h[sf].sym == s)
break;
zname(s->name, t, sym);
s->sym = sym;
h[sym].sym = s;
h[sym].type = t;
sf = sym;
sym++;
if(sym >= NSYM)
sym = 1;
break;
}
st = 0;
s = g2->to.sym;
while(s != S) {
st = s->sym;
if(st < 0 || st >= NSYM)
st = 0;
t = g2->to.type;
if(t == D_ADDR)
t = g2->to.index;
if(h[st].type == t)
if(h[st].sym == s)
break;
zname(s->name, t, sym);
s->sym = sym;
h[sym].sym = s;
h[sym].type = t;
st = sym;
sym++;
if(sym >= NSYM)
sym = 1;
if(st == sf)
goto jackpot;
break;
}
Bputc(&obuf, a);
Bputc(&obuf, a>>8);
Bputc(&obuf, lineno);
Bputc(&obuf, lineno>>8);
Bputc(&obuf, lineno>>16);
Bputc(&obuf, lineno>>24);
zaddr(&g2->from, sf);
zaddr(&g2->to, st);
out:
if(a != AGLOBL && a != ADATA)
pc++;
}
void
outhist(void)
{
Gen g;
Hist *h;
char *p, *q, *op, c;
int n;
g = nullgen;
c = pathchar();
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
p += 2;
c = *p;
}
if(p && p[0] != c && h->offset == 0 && pathname){
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
p = pathname+2;
c = *p;
} else if(pathname[0] == c){
op = p;
p = pathname;
}
}
while(p) {
q = strchr(p, c);
if(q) {
n = q-p;
if(n == 0){
n = 1; /* leading "/" */
*p = '/'; /* don't emit "\" on windows */
}
q++;
} else {
n = strlen(p);
q = 0;
}
if(n) {
Bputc(&obuf, ANAME);
Bputc(&obuf, ANAME>>8);
Bputc(&obuf, D_FILE); /* type */
Bputc(&obuf, 1); /* sym */
Bputc(&obuf, '<');
Bwrite(&obuf, p, n);
Bputc(&obuf, 0);
}
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
g.offset = h->offset;
Bputc(&obuf, AHISTORY);
Bputc(&obuf, AHISTORY>>8);
Bputc(&obuf, h->line);
Bputc(&obuf, h->line>>8);
Bputc(&obuf, h->line>>16);
Bputc(&obuf, h->line>>24);
zaddr(&nullgen, 0);
zaddr(&g, 0);
}
}
#include "../cc/lexbody"
#include "../cc/macbody"
// Inferno utils/8c/8.out.h
// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define NSYM 50
#define NSNAME 8
#define NOPROF (1<<0)
#define DUPOK (1<<1)
enum as
{
AXXX,
AAAA,
AAAD,
AAAM,
AAAS,
AADCB,
AADCL,
AADCW,
AADDB,
AADDL,
AADDW,
AADJSP,
AANDB,
AANDL,
AANDW,
AARPL,
ABOUNDL,
ABOUNDW,
ABSFL,
ABSFW,
ABSRL,
ABSRW,
ABTL,
ABTW,
ABTCL,
ABTCW,
ABTRL,
ABTRW,
ABTSL,
ABTSW,
ABYTE,
ACALL,
ACLC,
ACLD,
ACLI,
ACLTS,
ACMC,
ACMPB,
ACMPL,
ACMPW,
ACMPSB,
ACMPSL,
ACMPSW,
ADAA,
ADAS,
ADATA,
ADECB,
ADECL,
ADECW,
ADIVB,
ADIVL,
ADIVW,
AENTER,
AGLOBL,
AGOK,
AHISTORY,
AHLT,
AIDIVB,
AIDIVL,
AIDIVW,
AIMULB,
AIMULL,
AIMULW,
AINB,
AINL,
AINW,
AINCB,
AINCL,
AINCW,
AINSB,
AINSL,
AINSW,
AINT,
AINTO,
AIRETL,
AIRETW,
AJCC,
AJCS,
AJCXZ,
AJEQ,
AJGE,
AJGT,
AJHI,
AJLE,
AJLS,
AJLT,
AJMI,
AJMP,
AJNE,
AJOC,
AJOS,
AJPC,
AJPL,
AJPS,
ALAHF,
ALARL,
ALARW,
ALEAL,
ALEAW,
ALEAVEL,
ALEAVEW,
ALOCK,
ALODSB,
ALODSL,
ALODSW,
ALONG,
ALOOP,
ALOOPEQ,
ALOOPNE,
ALSLL,
ALSLW,
AMOVB,
AMOVL,
AMOVW,
AMOVBLSX,
AMOVBLZX,
AMOVBWSX,
AMOVBWZX,
AMOVWLSX,
AMOVWLZX,
AMOVSB,
AMOVSL,
AMOVSW,
AMULB,
AMULL,
AMULW,
ANAME,
ANEGB,
ANEGL,
ANEGW,
ANOP,
ANOTB,
ANOTL,
ANOTW,
AORB,
AORL,
AORW,
AOUTB,
AOUTL,
AOUTW,
AOUTSB,
AOUTSL,
AOUTSW,
APOPAL,
APOPAW,
APOPFL,
APOPFW,
APOPL,
APOPW,
APUSHAL,
APUSHAW,
APUSHFL,
APUSHFW,
APUSHL,
APUSHW,
ARCLB,
ARCLL,
ARCLW,
ARCRB,
ARCRL,
ARCRW,
AREP,
AREPN,
ARET,
AROLB,
AROLL,
AROLW,
ARORB,
ARORL,
ARORW,
ASAHF,
ASALB,
ASALL,
ASALW,
ASARB,
ASARL,
ASARW,
ASBBB,
ASBBL,
ASBBW,
ASCASB,
ASCASL,
ASCASW,
ASETCC,
ASETCS,
ASETEQ,
ASETGE,
ASETGT,
ASETHI,
ASETLE,
ASETLS,
ASETLT,
ASETMI,
ASETNE,
ASETOC,
ASETOS,
ASETPC,
ASETPL,
ASETPS,
ACDQ,
ACWD,
ASHLB,
ASHLL,
ASHLW,
ASHRB,
ASHRL,
ASHRW,
ASTC,
ASTD,
ASTI,
ASTOSB,
ASTOSL,
ASTOSW,
ASUBB,
ASUBL,
ASUBW,
ASYSCALL,
ATESTB,
ATESTL,
ATESTW,
ATEXT,
AVERR,
AVERW,
AWAIT,
AWORD,
AXCHGB,
AXCHGL,
AXCHGW,
AXLAT,
AXORB,
AXORL,
AXORW,
AFMOVB,
AFMOVBP,
AFMOVD,
AFMOVDP,
AFMOVF,
AFMOVFP,
AFMOVL,
AFMOVLP,
AFMOVV,
AFMOVVP,
AFMOVW,
AFMOVWP,
AFMOVX,
AFMOVXP,
AFCOMB,
AFCOMBP,
AFCOMD,
AFCOMDP,
AFCOMDPP,
AFCOMF,
AFCOMFP,
AFCOML,
AFCOMLP,
AFCOMW,
AFCOMWP,
AFUCOM,
AFUCOMP,
AFUCOMPP,
AFADDDP,
AFADDW,
AFADDL,
AFADDF,
AFADDD,
AFMULDP,
AFMULW,
AFMULL,
AFMULF,
AFMULD,
AFSUBDP,
AFSUBW,
AFSUBL,
AFSUBF,
AFSUBD,
AFSUBRDP,
AFSUBRW,
AFSUBRL,
AFSUBRF,
AFSUBRD,
AFDIVDP,
AFDIVW,
AFDIVL,
AFDIVF,
AFDIVD,
AFDIVRDP,
AFDIVRW,
AFDIVRL,
AFDIVRF,
AFDIVRD,
AFXCHD,
AFFREE,
AFLDCW,
AFLDENV,
AFRSTOR,
AFSAVE,
AFSTCW,
AFSTENV,
AFSTSW,
AF2XM1,
AFABS,
AFCHS,
AFCLEX,
AFCOS,
AFDECSTP,
AFINCSTP,
AFINIT,
AFLD1,
AFLDL2E,
AFLDL2T,
AFLDLG2,
AFLDLN2,
AFLDPI,
AFLDZ,
AFNOP,
AFPATAN,
AFPREM,
AFPREM1,
AFPTAN,
AFRNDINT,
AFSCALE,
AFSIN,
AFSINCOS,
AFSQRT,
AFTST,
AFXAM,
AFXTRACT,
AFYL2X,
AFYL2XP1,
AEND,
ADYNT,
AINIT,
ASIGNAME,
ALAST
};
enum
{
D_AL = 0,
D_CL,
D_DL,
D_BL,
D_AH = 4,
D_CH,
D_DH,
D_BH,
D_AX = 8,
D_CX,
D_DX,
D_BX,
D_SP,
D_BP,
D_SI,
D_DI,
D_F0 = 16,
D_CS = 24,
D_SS,
D_DS,
D_ES,
D_FS,
D_GS,
D_GDTR, /* global descriptor table register */
D_IDTR, /* interrupt descriptor table register */
D_LDTR, /* local descriptor table register */
D_MSW, /* machine status word */
D_TASK, /* task register */
D_CR = 35,
D_DR = 43,
D_TR = 51,
D_NONE = 59,
D_BRANCH = 60,
D_EXTERN = 61,
D_STATIC = 62,
D_AUTO = 63,
D_PARAM = 64,
D_CONST = 65,
D_FCONST = 66,
D_SCONST = 67,
D_ADDR = 68,
D_FILE,
D_FILE1,
D_INDIR, /* additive */
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
T_FCONST = 1<<3,
T_SYM = 1<<4,
T_SCONST = 1<<5,
REGARG = 0,
REGRET = D_AX,
FREGRET = D_F0,
REGSP = D_SP,
REGTMP = D_DI,
};
/*
* this is the ranlib header
*/
#define SYMDEF "__.SYMDEF"
/*
* this is the simulated IEEE floating point
*/
typedef struct ieee Ieee;
struct ieee
{
long l; /* contains ls-man 0xffffffff */
long h; /* contains sign 0x80000000
exp 0x7ff00000
ms-man 0x000fffff */
};
// Inferno utils/8c/cgen.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.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 "gc.h"
/* ,x/^(print|prtree)\(/i/\/\/ */
void
cgen(Node *n, Node *nn)
{
Node *l, *r, *t;
Prog *p1;
Node nod, nod1, nod2, nod3, nod4;
int o, hardleft;
long v, curs;
vlong c;
if(debug['g']) {
prtree(nn, "cgen lhs");
prtree(n, "cgen");
}
if(n == Z || n->type == T)
return;
if(typesuv[n->type->etype]) {
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(l->complex >= FNX)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
if(cond(o) && typesuv[l->type->etype])
break;
regret(&nod, r);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &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;
}
hardleft = l->addable < INDEXED || l->complex >= FNX;
switch(o) {
default:
diag(n, "unknown op in cgen: %O", o);
break;
case ONEG:
case OCOM:
if(nn == Z) {
nullwarn(l, Z);
break;
}
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, n->type, Z, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
case OAS:
if(typefd[n->type->etype]) {
cgen(r, &fregnode0);
if(nn != Z)
gins(AFMOVD, &fregnode0, &fregnode0);
if(l->addable < INDEXED) {
reglcgen(&nod, l, Z);
gmove(&fregnode0, &nod);
regfree(&nod);
} else
gmove(&fregnode0, l);
if(nn != Z)
gmove(&fregnode0, nn);
return;
}
if(l->op == OBIT)
goto bitas;
if(!hardleft) {
if(nn != Z || r->addable < INDEXED) {
if(r->complex >= FNX && nn == Z)
regret(&nod, r);
else
regalloc(&nod, r, nn);
cgen(r, &nod);
gmove(&nod, l);
if(nn != Z)
gmove(&nod, nn);
regfree(&nod);
} else
gmove(r, l);
break;
}
if(l->complex >= r->complex) {
if(l->op == OINDEX && r->op == OCONST) {
gmove(r, l);
break;
}
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);
gmove(&nod1, &nod2);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
case OBIT:
if(nn == Z) {
nullwarn(l, Z);
break;
}
bitload(n, &nod, Z, Z, nn);
gmove(&nod, nn);
regfree(&nod);
break;
case OLSHR:
case OASHL:
case OASHR:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(r->op == OCONST) {
if(r->vconst == 0) {
cgen(l, nn);
break;
}
regalloc(&nod, l, nn);
cgen(l, &nod);
if(o == OASHL && r->vconst == 1)
gopcode(OADD, n->type, &nod, &nod);
else
gopcode(o, n->type, r, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
}
/*
* get nod to be D_CX
*/
if(nodreg(&nod, nn, D_CX)) {
regsalloc(&nod1, n);
gmove(&nod, &nod1);
cgen(n, &nod); /* probably a bug */
gmove(&nod, nn);
gmove(&nod1, &nod);
break;
}
reg[D_CX]++;
if(nn->op == OREGISTER && nn->reg == D_CX)
regalloc(&nod1, l, Z);
else
regalloc(&nod1, l, nn);
if(r->complex >= l->complex) {
cgen(r, &nod);
cgen(l, &nod1);
} else {
cgen(l, &nod1);
cgen(r, &nod);
}
gopcode(o, n->type, &nod, &nod1);
gmove(&nod1, nn);
regfree(&nod);
regfree(&nod1);
break;
case OADD:
case OSUB:
case OOR:
case OXOR:
case OAND:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(typefd[n->type->etype])
goto fop;
if(r->op == OCONST) {
if(r->vconst == 0 && o != OAND) {
cgen(l, nn);
break;
}
}
if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
c = l->right->vconst;
if(c > 0 && c <= 3) {
if(l->left->complex >= r->complex) {
regalloc(&nod, l->left, nn);
cgen(l->left, &nod);
if(r->addable < INDEXED) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
genmuladd(&nod, &nod, 1 << c, &nod1);
regfree(&nod1);
}
else
genmuladd(&nod, &nod, 1 << c, r);
}
else {
regalloc(&nod, r, nn);
cgen(r, &nod);
regalloc(&nod1, l->left, Z);
cgen(l->left, &nod1);
genmuladd(&nod, &nod1, 1 << c, &nod);
regfree(&nod1);
}
gmove(&nod, nn);
regfree(&nod);
break;
}
}
if(r->addable >= INDEXED) {
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, n->type, r, &nod);
gmove(&nod, nn);
regfree(&nod);
break;
}
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, n->type, &nod1, &nod);
} else {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
regalloc(&nod, l, Z);
cgen(l, &nod);
gopcode(o, n->type, &nod1, &nod);
}
gmove(&nod, nn);
regfree(&nod);
regfree(&nod1);
break;
case OLMOD:
case OMOD:
case OLMUL:
case OLDIV:
case OMUL:
case ODIV:
if(nn == Z) {
nullwarn(l, r);
break;
}
if(typefd[n->type->etype])
goto fop;
if(r->op == OCONST) {
SET(v);
switch(o) {
case ODIV:
case OMOD:
c = r->vconst;
if(c < 0)
c = -c;
v = log2(c);
if(v < 0)
break;
/* fall thru */
case OMUL:
case OLMUL:
regalloc(&nod, l, nn);
cgen(l, &nod);
switch(o) {
case OMUL:
case OLMUL:
mulgen(n->type, r, &nod);
break;
case ODIV:
sdiv2(r->vconst, v, l, &nod);
break;
case OMOD:
smod2(r->vconst, v, l, &nod);
break;
}
gmove(&nod, nn);
regfree(&nod);
goto done;
case OLDIV:
c = r->vconst;
if((c & 0x80000000) == 0)
break;
regalloc(&nod1, l, Z);
cgen(l, &nod1);
regalloc(&nod, l, nn);
zeroregm(&nod);
gins(ACMPL, &nod1, nodconst(c));
gins(ASBBL, nodconst(-1), &nod);
regfree(&nod1);
gmove(&nod, nn);
regfree(&nod);
goto done;
}
}
if(o == OMUL) {
if(l->addable >= INDEXED) {
t = l;
l = r;
r = t;
}
/* should favour AX */
regalloc(&nod, l, nn);
cgen(l, &nod);
if(r->addable < INDEXED) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(OMUL, n->type, &nod1, &nod);
regfree(&nod1);
}else
gopcode(OMUL, n->type, r, &nod); /* addressible */
gmove(&nod, nn);
regfree(&nod);
break;
}
/*
* get nod to be D_AX
* get nod1 to be D_DX
*/
if(nodreg(&nod, nn, D_AX)) {
regsalloc(&nod2, n);
gmove(&nod, &nod2);
v = reg[D_AX];
reg[D_AX] = 0;
if(isreg(l, D_AX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_AX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod);
reg[D_AX] = v;
break;
}
if(nodreg(&nod1, nn, D_DX)) {
regsalloc(&nod2, n);
gmove(&nod1, &nod2);
v = reg[D_DX];
reg[D_DX] = 0;
if(isreg(l, D_DX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_DX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod1);
reg[D_DX] = v;
break;
}
reg[D_AX]++;
if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
reg[D_DX]++;
if(l->addable < INDEXED) {
regalloc(&nod2, l, Z);
cgen(l, &nod2);
l = &nod2;
}
if(o == ODIV)
sdivgen(l, r, &nod, &nod1);
else
udivgen(l, r, &nod, &nod1);
gmove(&nod1, nn);
if(l == &nod2)
regfree(l);
goto freeaxdx;
}
if(l->complex >= r->complex) {
cgen(l, &nod);
reg[D_DX]++;
if(o == ODIV || o == OMOD)
gins(ACDQ, Z, Z);
if(o == OLDIV || o == OLMOD)
zeroregm(&nod1);
if(r->addable < INDEXED || r->op == OCONST) {
regsalloc(&nod3, r);
cgen(r, &nod3);
gopcode(o, n->type, &nod3, Z);
} else
gopcode(o, n->type, r, Z);
} else {
regsalloc(&nod3, r);
cgen(r, &nod3);
cgen(l, &nod);
reg[D_DX]++;
if(o == ODIV || o == OMOD)
gins(ACDQ, Z, Z);
if(o == OLDIV || o == OLMOD)
zeroregm(&nod1);
gopcode(o, n->type, &nod3, Z);
}
if(o == OMOD || o == OLMOD)
gmove(&nod1, nn);
else
gmove(&nod, nn);
freeaxdx:
regfree(&nod);
regfree(&nod1);
break;
case OASLSHR:
case OASASHL:
case OASASHR:
if(r->op == OCONST)
goto asand;
if(l->op == OBIT)
goto asbitop;
if(typefd[n->type->etype])
goto asfop;
/*
* get nod to be D_CX
*/
if(nodreg(&nod, nn, D_CX)) {
regsalloc(&nod1, n);
gmove(&nod, &nod1);
cgen(n, &nod);
if(nn != Z)
gmove(&nod, nn);
gmove(&nod1, &nod);
break;
}
reg[D_CX]++;
if(r->complex >= l->complex) {
cgen(r, &nod);
if(hardleft)
reglcgen(&nod1, l, Z);
else
nod1 = *l;
} else {
if(hardleft)
reglcgen(&nod1, l, Z);
else
nod1 = *l;
cgen(r, &nod);
}
gopcode(o, l->type, &nod, &nod1);
regfree(&nod);
if(nn != Z)
gmove(&nod1, nn);
if(hardleft)
regfree(&nod1);
break;
case OASAND:
case OASADD:
case OASSUB:
case OASXOR:
case OASOR:
asand:
if(l->op == OBIT)
goto asbitop;
if(typefd[n->type->etype]||typefd[r->type->etype])
goto asfop;
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(r->op != OCONST) {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
} else
gopcode(o, l->type, r, &nod);
} else {
regalloc(&nod1, r, nn);
cgen(r, &nod1);
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
}
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod);
break;
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(l->op == OBIT)
goto asbitop;
if(typefd[n->type->etype]||typefd[r->type->etype])
goto asfop;
if(r->op == OCONST) {
SET(v);
switch(o) {
case OASDIV:
case OASMOD:
c = r->vconst;
if(c < 0)
c = -c;
v = log2(c);
if(v < 0)
break;
/* fall thru */
case OASMUL:
case OASLMUL:
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod, l, nn);
cgen(&nod2, &nod);
switch(o) {
case OASMUL:
case OASLMUL:
mulgen(n->type, r, &nod);
break;
case OASDIV:
sdiv2(r->vconst, v, l, &nod);
break;
case OASMOD:
smod2(r->vconst, v, l, &nod);
break;
}
havev:
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod2);
regfree(&nod);
goto done;
case OASLDIV:
c = r->vconst;
if((c & 0x80000000) == 0)
break;
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
regalloc(&nod1, l, nn);
cgen(&nod2, &nod1);
regalloc(&nod, l, nn);
zeroregm(&nod);
gins(ACMPL, &nod1, nodconst(c));
gins(ASBBL, nodconst(-1), &nod);
regfree(&nod1);
goto havev;
}
}
if(o == OASMUL) {
/* should favour AX */
regalloc(&nod, l, nn);
if(r->complex >= FNX) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
r = &nod1;
}
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(r->addable < INDEXED) {
if(r->complex < FNX) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
}
gopcode(OASMUL, n->type, &nod1, &nod);
regfree(&nod1);
}
else
gopcode(OASMUL, n->type, r, &nod);
if(r == &nod1)
regfree(r);
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
regfree(&nod);
if(hardleft)
regfree(&nod2);
break;
}
/*
* get nod to be D_AX
* get nod1 to be D_DX
*/
if(nodreg(&nod, nn, D_AX)) {
regsalloc(&nod2, n);
gmove(&nod, &nod2);
v = reg[D_AX];
reg[D_AX] = 0;
if(isreg(l, D_AX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_AX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod);
reg[D_AX] = v;
break;
}
if(nodreg(&nod1, nn, D_DX)) {
regsalloc(&nod2, n);
gmove(&nod1, &nod2);
v = reg[D_DX];
reg[D_DX] = 0;
if(isreg(l, D_DX)) {
nod3 = *n;
nod3.left = &nod2;
cgen(&nod3, nn);
} else
if(isreg(r, D_DX)) {
nod3 = *n;
nod3.right = &nod2;
cgen(&nod3, nn);
} else
cgen(n, nn);
gmove(&nod2, &nod1);
reg[D_DX] = v;
break;
}
reg[D_AX]++;
reg[D_DX]++;
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(r->op == OCONST) {
switch(o) {
case OASDIV:
sdivgen(&nod2, r, &nod, &nod1);
goto divdone;
case OASLDIV:
udivgen(&nod2, r, &nod, &nod1);
divdone:
gmove(&nod1, &nod2);
if(nn != Z)
gmove(&nod1, nn);
goto freelxaxdx;
}
}
if(o == OASDIV || o == OASMOD)
gins(ACDQ, Z, Z);
if(o == OASLDIV || o == OASLMOD)
zeroregm(&nod1);
if(r->addable < INDEXED || r->op == OCONST ||
!typeil[r->type->etype]) {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
gopcode(o, l->type, &nod3, Z);
regfree(&nod3);
} else
gopcode(o, n->type, r, Z);
} else {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
if(hardleft)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
cgen(&nod2, &nod);
if(o == OASDIV || o == OASMOD)
gins(ACDQ, Z, Z);
if(o == OASLDIV || o == OASLMOD)
zeroregm(&nod1);
gopcode(o, l->type, &nod3, Z);
regfree(&nod3);
}
if(o == OASMOD || o == OASLMOD) {
gmove(&nod1, &nod2);
if(nn != Z)
gmove(&nod1, nn);
} else {
gmove(&nod, &nod2);
if(nn != Z)
gmove(&nod, nn);
}
freelxaxdx:
if(hardleft)
regfree(&nod2);
regfree(&nod);
regfree(&nod1);
break;
fop:
if(l->complex >= r->complex) {
cgen(l, &fregnode0);
if(r->addable < INDEXED) {
cgen(r, &fregnode0);
fgopcode(o, &fregnode0, &fregnode1, 1, 0);
} else
fgopcode(o, r, &fregnode0, 0, 0);
} else {
cgen(r, &fregnode0);
if(l->addable < INDEXED) {
cgen(l, &fregnode0);
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
} else
fgopcode(o, l, &fregnode0, 0, 1);
}
gmove(&fregnode0, nn);
break;
asfop:
if(l->complex >= r->complex) {
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
cgen(r, &fregnode0);
} else {
cgen(r, &fregnode0);
if(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
}
if(!typefd[l->type->etype]) {
gmove(&nod, &fregnode0);
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
} else
fgopcode(o, &nod, &fregnode0, 0, 1);
if(nn != Z)
gins(AFMOVD, &fregnode0, &fregnode0);
gmove(&fregnode0, &nod);
if(nn != Z)
gmove(&fregnode0, nn);
if(hardleft)
regfree(&nod);
break;
asbitop:
regalloc(&nod4, n, nn);
if(l->complex >= r->complex) {
bitload(l, &nod, &nod1, &nod2, &nod4);
regalloc(&nod3, r, Z);
cgen(r, &nod3);
} else {
regalloc(&nod3, r, Z);
cgen(r, &nod3);
bitload(l, &nod, &nod1, &nod2, &nod4);
}
gmove(&nod, &nod4);
if(typefd[nod3.type->etype])
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
else {
Node onod;
/* incredible grot ... */
onod = nod3;
onod.op = o;
onod.complex = 2;
onod.addable = 0;
onod.type = tfield;
onod.left = &nod4;
onod.right = &nod3;
cgen(&onod, Z);
}
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);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gmove(&nod, &nod1);
regfree(&nod);
nod = *n;
nod.left = &nod2;
nod2 = *l;
nod2.left = &nod1;
nod2.complex = 1;
cgen(&nod, nn);
return;
}
gargs(r, &nod, &nod1);
if(l->addable < INDEXED) {
reglcgen(&nod, l, nn);
nod.op = OREGISTER;
gopcode(OFUNC, n->type, Z, &nod);
regfree(&nod);
} else
gopcode(OFUNC, n->type, Z, l);
if(REGARG && reg[REGARG])
reg[REGARG]--;
if(nn != Z) {
regret(&nod, n);
gmove(&nod, nn);
regfree(&nod);
} else
if(typefd[n->type->etype])
gins(AFMOVDP, &fregnode0, &fregnode0);
break;
case OIND:
if(nn == Z) {
nullwarn(l, Z);
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);
gmove(&nod, 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;
}
if(typev[l->type->etype]) {
cgen64(n, nn);
break;
}
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, n, &nod);
gmove(&nod, &nod1);
gmove(&nod1, nn);
regfree(&nod1);
regfree(&nod);
break;
case ODOT:
sugen(l, nodrat, l->type->width);
if(nn == Z)
break;
warn(n, "non-interruptable temporary");
nod = *nodrat;
if(!r || r->op != OCONST) {
diag(n, "DOT and no offset");
break;
}
nod.xoffset += (long)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(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(typefd[n->type->etype])
goto fltinc;
gmove(&nod, nn);
gopcode(OADD, n->type, nodconst(v), &nod);
if(hardleft)
regfree(&nod);
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(hardleft)
reglcgen(&nod, l, Z);
else
nod = *l;
if(typefd[n->type->etype])
goto fltinc;
gopcode(OADD, n->type, nodconst(v), &nod);
if(nn != Z)
gmove(&nod, nn);
if(hardleft)
regfree(&nod);
break;
fltinc:
gmove(&nod, &fregnode0);
if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
gins(AFMOVD, &fregnode0, &fregnode0);
gins(AFLD1, Z, Z);
if(v < 0)
fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
else
fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
if(nn != Z && (o == OPREINC || o == OPREDEC))
gins(AFMOVD, &fregnode0, &fregnode0);
gmove(&fregnode0, &nod);
if(hardleft)
regfree(&nod);
break;
bitinc:
if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
bitload(l, &nod, &nod1, &nod2, Z);
gmove(&nod, nn);
gopcode(OADD, tfield, nodconst(v), &nod);
bitstore(l, &nod, &nod1, &nod2, Z);
break;
}
bitload(l, &nod, &nod1, &nod2, nn);
gopcode(OADD, tfield, nodconst(v), &nod);
bitstore(l, &nod, &nod1, &nod2, nn);
break;
}
done:
cursafe = curs;
}
void
reglcgen(Node *t, Node *n, Node *nn)
{
Node *r;
long 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;
}
gopcode(OADDR, n->type, n, 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;
long curs;
if(debug['g']) {
prtree(nn, "boolgen lhs");
prtree(n, "boolgen");
}
curs = cursafe;
l = n->left;
r = n->right;
switch(n->op) {
default:
if(typev[n->type->etype]) {
testv(n, true);
goto com;
}
o = ONE;
if(true)
o = OEQ;
if(typefd[n->type->etype]) {
if(n->addable < INDEXED) {
cgen(n, &fregnode0);
gins(AFLDZ, Z, Z);
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
} else {
gins(AFLDZ, Z, Z);
fgopcode(o, n, &fregnode0, 0, 1);
}
goto com;
}
/* bad, 13 is address of external that becomes constant */
if(n->addable >= INDEXED && n->addable != 13) {
gopcode(o, n->type, n, nodconst(0));
goto com;
}
regalloc(&nod, n, nn);
cgen(n, &nod);
gopcode(o, n->type, &nod, nodconst(0));
regfree(&nod);
goto com;
case OCONST:
o = vconst(n);
if(!true)
o = !o;
gbranch(OGOTO);
if(o) {
p1 = p;
gbranch(OGOTO);
patch(p1, pc);
}
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(typev[l->type->etype]) {
if(!true)
n->op = comrel[relindex(o)];
cgen64(n, Z);
goto com;
}
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
regret(&nod, r);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &nod1);
regfree(&nod);
nod = *n;
nod.right = &nod1;
boolgen(&nod, true, nn);
break;
}
if(typefd[l->type->etype]) {
if(l->complex >= r->complex) {
cgen(l, &fregnode0);
if(r->addable < INDEXED) {
cgen(r, &fregnode0);
o = invrel[relindex(o)];
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
} else
fgopcode(o, r, &fregnode0, 0, 1);
} else {
o = invrel[relindex(o)];
cgen(r, &fregnode0);
if(l->addable < INDEXED) {
cgen(l, &fregnode0);
o = invrel[relindex(o)];
fgopcode(o, &fregnode0, &fregnode1, 1, 1);
} else
fgopcode(o, l, &fregnode0, 0, 1);
}
goto com;
}
if(l->op == OCONST) {
o = invrel[relindex(o)];
/* bad, 13 is address of external that becomes constant */
if(r->addable < INDEXED || r->addable == 13) {
regalloc(&nod, r, nn);
cgen(r, &nod);
gopcode(o, l->type, &nod, l);
regfree(&nod);
} else
gopcode(o, l->type, r, l);
goto com;
}
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
if(r->addable < INDEXED) {
regalloc(&nod1, r, Z);
cgen(r, &nod1);
gopcode(o, l->type, &nod, &nod1);
regfree(&nod1);
} else
gopcode(o, l->type, &nod, r);
regfree(&nod);
goto com;
}
regalloc(&nod, r, nn);
cgen(r, &nod);
if(l->addable < INDEXED || l->addable == 13) {
regalloc(&nod1, l, Z);
cgen(l, &nod1);
if(typechlp[l->type->etype])
gopcode(o, types[TINT], &nod1, &nod);
else
gopcode(o, l->type, &nod1, &nod);
regfree(&nod1);
} else
gopcode(o, l->type, l, &nod);
regfree(&nod);
com:
if(nn != Z) {
p1 = p;
gmove(nodconst(1L), nn);
gbranch(OGOTO);
p2 = p;
patch(p1, pc);
gmove(nodconst(0L), nn);
patch(p2, pc);
}
break;
}
cursafe = curs;
}
void
sugen(Node *n, Node *nn, long w)
{
Prog *p1;
Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
Type *t;
int c, v, x;
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;
}
if(nn->op == OREGPAIR) {
loadpair(n, nn);
break;
}
else if(!vaddr(nn, 0)) {
t = nn->type;
nn->type = types[TLONG];
reglcgen(&nod1, nn, Z);
nn->type = t;
gmove(lo64(n), &nod1);
nod1.xoffset += SZ_LONG;
gmove(hi64(n), &nod1);
regfree(&nod1);
}
else {
gins(AMOVL, lo64(n), nn);
nn->xoffset += SZ_LONG;
gins(AMOVL, hi64(n), nn);
nn->xoffset -= SZ_LONG;
break;
}
break;
}
goto copy;
case ODOT:
l = n->left;
sugen(l, nodrat, l->type->width);
if(nn == Z)
break;
warn(n, "non-interruptable temporary");
nod1 = *nodrat;
r = n->right;
if(!r || r->op != OCONST) {
diag(n, "DOT and no offset");
break;
}
nod1.xoffset += (long)r->vconst;
nod1.type = n->type;
sugen(&nod1, nn, w);
break;
case OSTRUCT:
/*
* rewrite so lhs has no fn call
*/
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
regret(&nod2, &nod1);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
cgen(&nod2, &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 = nil;
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;
nod0.right = l;
/* prtree(&nod0, "hand craft"); /* */
cgen(&nod0, Z);
}
break;
case OAS:
if(nn == Z) {
if(n->addable < INDEXED)
sugen(n->right, n->left, w);
break;
}
sugen(n->right, nodrat, w);
warn(n, "non-interruptable temporary");
sugen(nodrat, n->left, w);
sugen(nodrat, nn, w);
break;
case OFUNC:
if(nn == Z) {
sugen(n, nodrat, w);
break;
}
h = nn;
if(nn->op == OREGPAIR) {
regsalloc(&nod1, nn);
nn = &nod1;
}
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);
if(h->op == OREGPAIR)
loadpair(nn->left, h);
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) {
switch(n->op) {
case OASADD:
case OASSUB:
case OASAND:
case OASOR:
case OASXOR:
case OASMUL:
case OASLMUL:
case OASASHL:
case OASASHR:
case OASLSHR:
break;
case OPOSTINC:
case OPOSTDEC:
case OPREINC:
case OPREDEC:
break;
default:
return;
}
}
if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
t = nn->type;
nn->type = types[TLONG];
regialloc(&nod1, nn, Z);
lcgen(nn, &nod1);
regsalloc(&nod2, nn);
nn->type = t;
gins(AMOVL, &nod1, &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;
}
x = 0;
v = w == 8;
if(v) {
c = cursafe;
if(n->left != Z && n->left->complex >= FNX
&& n->right != Z && n->right->complex >= FNX) {
// warn(n, "toughie");
regsalloc(&nod1, n->right);
cgen(n->right, &nod1);
nod2 = *n;
nod2.right = &nod1;
cgen(&nod2, nn);
cursafe = c;
return;
}
if(cgen64(n, nn)) {
cursafe = c;
return;
}
if(n->op == OCOM) {
n = n->left;
x = 1;
}
}
/* botch, need to save in .safe */
c = 0;
if(n->complex > nn->complex) {
t = n->type;
n->type = types[TLONG];
if(v) {
regalloc(&nod0, n, Z);
if(!vaddr(n, 0)) {
reglcgen(&nod1, n, Z);
n->type = t;
n = &nod1;
}
else
n->type = t;
}
else {
nodreg(&nod1, n, D_SI);
if(reg[D_SI]) {
gins(APUSHL, &nod1, Z);
c |= 1;
reg[D_SI]++;
}
lcgen(n, &nod1);
n->type = t;
}
t = nn->type;
nn->type = types[TLONG];
if(v) {
if(!vaddr(nn, 0)) {
reglcgen(&nod2, nn, Z);
nn->type = t;
nn = &nod2;
}
else
nn->type = t;
}
else {
nodreg(&nod2, nn, D_DI);
if(reg[D_DI]) {
gins(APUSHL, &nod2, Z);
c |= 2;
reg[D_DI]++;
}
lcgen(nn, &nod2);
nn->type = t;
}
} else {
t = nn->type;
nn->type = types[TLONG];
if(v) {
regalloc(&nod0, nn, Z);
if(!vaddr(nn, 0)) {
reglcgen(&nod2, nn, Z);
nn->type = t;
nn = &nod2;
}
else
nn->type = t;
}
else {
nodreg(&nod2, nn, D_DI);
if(reg[D_DI]) {
gins(APUSHL, &nod2, Z);
c |= 2;
reg[D_DI]++;
}
lcgen(nn, &nod2);
nn->type = t;
}
t = n->type;
n->type = types[TLONG];
if(v) {
if(!vaddr(n, 0)) {
reglcgen(&nod1, n, Z);
n->type = t;
n = &nod1;
}
else
n->type = t;
}
else {
nodreg(&nod1, n, D_SI);
if(reg[D_SI]) {
gins(APUSHL, &nod1, Z);
c |= 1;
reg[D_SI]++;
}
lcgen(n, &nod1);
n->type = t;
}
}
if(v) {
gins(AMOVL, n, &nod0);
if(x)
gins(ANOTL, Z, &nod0);
gins(AMOVL, &nod0, nn);
n->xoffset += SZ_LONG;
nn->xoffset += SZ_LONG;
gins(AMOVL, n, &nod0);
if(x)
gins(ANOTL, Z, &nod0);
gins(AMOVL, &nod0, nn);
n->xoffset -= SZ_LONG;
nn->xoffset -= SZ_LONG;
if(nn == &nod2)
regfree(&nod2);
if(n == &nod1)
regfree(&nod1);
regfree(&nod0);
return;
}
nodreg(&nod3, n, D_CX);
if(reg[D_CX]) {
gins(APUSHL, &nod3, Z);
c |= 4;
reg[D_CX]++;
}
gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
gins(ACLD, Z, Z);
gins(AREP, Z, Z);
gins(AMOVSL, Z, Z);
if(c & 4) {
gins(APOPL, Z, &nod3);
reg[D_CX]--;
}
if(c & 2) {
gins(APOPL, Z, &nod2);
reg[nod2.reg]--;
}
if(c & 1) {
gins(APOPL, Z, &nod1);
reg[nod1.reg]--;
}
}
// Inferno utils/8c/cgen64.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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 "gc.h"
void
zeroregm(Node *n)
{
gins(AMOVL, nodconst(0), n);
}
/* do we need to load the address of a vlong? */
int
vaddr(Node *n, int a)
{
switch(n->op) {
case ONAME:
if(a)
return 1;
return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
case OCONST:
case OREGISTER:
case OINDREG:
return 1;
}
return 0;
}
long
hi64v(Node *n)
{
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
return (long)(n->vconst) & ~0L;
else
return (long)((uvlong)n->vconst>>32) & ~0L;
}
long
lo64v(Node *n)
{
if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
return (long)((uvlong)n->vconst>>32) & ~0L;
else
return (long)(n->vconst) & ~0L;
}
Node *
hi64(Node *n)
{
return nodconst(hi64v(n));
}
Node *
lo64(Node *n)
{
return nodconst(lo64v(n));
}
static Node *
anonreg(void)
{
Node *n;
n = new(OREGISTER, Z, Z);
n->reg = D_NONE;
n->type = types[TLONG];
return n;
}
static Node *
regpair(Node *n, Node *t)
{
Node *r;
if(n != Z && n->op == OREGPAIR)
return n;
r = new(OREGPAIR, anonreg(), anonreg());
if(n != Z)
r->type = n->type;
else
r->type = t->type;
return r;
}
static void
evacaxdx(Node *r)
{
Node nod1, nod2;
if(r->reg == D_AX || r->reg == D_DX) {
reg[D_AX]++;
reg[D_DX]++;
/*
* this is just an optim that should
* check for spill
*/
r->type = types[TULONG];
regalloc(&nod1, r, Z);
nodreg(&nod2, Z, r->reg);
gins(AMOVL, &nod2, &nod1);
regfree(r);
r->reg = nod1.reg;
reg[D_AX]--;
reg[D_DX]--;
}
}
/* lazy instantiation of register pair */
static int
instpair(Node *n, Node *l)
{
int r;
r = 0;
if(n->left->reg == D_NONE) {
if(l != Z) {
n->left->reg = l->reg;
r = 1;
}
else
regalloc(n->left, n->left, Z);
}
if(n->right->reg == D_NONE)
regalloc(n->right, n->right, Z);
return r;
}
static void
zapreg(Node *n)
{
if(n->reg != D_NONE) {
regfree(n);
n->reg = D_NONE;
}
}
static void
freepair(Node *n)
{
regfree(n->left);
regfree(n->right);
}
/* n is not OREGPAIR, nn is */
void
loadpair(Node *n, Node *nn)
{
Node nod;
instpair(nn, Z);
if(n->op == OCONST) {
gins(AMOVL, lo64(n), nn->left);
n->xoffset += SZ_LONG;
gins(AMOVL, hi64(n), nn->right);
n->xoffset -= SZ_LONG;
return;
}
if(!vaddr(n, 0)) {
/* steal the right register for the laddr */
nod = regnode;
nod.reg = nn->right->reg;
lcgen(n, &nod);
n = &nod;
regind(n, n);
n->xoffset = 0;
}
gins(AMOVL, n, nn->left);
n->xoffset += SZ_LONG;
gins(AMOVL, n, nn->right);
n->xoffset -= SZ_LONG;
}
/* n is OREGPAIR, nn is not */
static void
storepair(Node *n, Node *nn, int f)
{
Node nod;
if(!vaddr(nn, 0)) {
reglcgen(&nod, nn, Z);
nn = &nod;
}
gins(AMOVL, n->left, nn);
nn->xoffset += SZ_LONG;
gins(AMOVL, n->right, nn);
nn->xoffset -= SZ_LONG;
if(nn == &nod)
regfree(&nod);
if(f)
freepair(n);
}
/* generate a cast t from n to tt */
static void
cast(Node *n, Type *t, Node *nn)
{
Node *r;
r = new(OCAST, n, Z);
r->type = t;
sugen(r, nn, 8);
}
static void
swapregs(Node *a, Node *b)
{
int t;
t = a->reg;
a->reg = b->reg;
b->reg = t;
}
static void
swappairs(Node *a, Node *b)
{
swapregs(a->left, b->left);
swapregs(a->right, b->right);
}
static int
saveme(Node *n)
{
int r;
r = n->reg;
return r >= D_AX && r <= D_DI;
}
static void
saveit(Node *n, Node *t, Node *r)
{
Node nod;
if(saveme(n)) {
t->reg = n->reg;
gins(AMOVL, t, r);
r->xoffset += SZ_LONG;
if(n->reg == D_AX) {
regalloc(&nod, n, Z);
regfree(n);
n->reg = nod.reg;
}
}
}
static void
restoreit(Node *n, Node *t, Node *r)
{
if(saveme(n)) {
t->reg = n->reg;
gins(AMOVL, r, t);
r->xoffset += SZ_LONG;
}
}
enum
{
/* 4 only, see WW */
WNONE = 0,
WCONST,
WADDR,
WHARD,
};
static int
whatof(Node *n, int a)
{
if(n->op == OCONST)
return WCONST;
return !vaddr(n, a) ? WHARD : WADDR;
}
/* can upgrade an extern to addr for AND */
static int
reduxv(Node *n)
{
return lo64v(n) == 0 || hi64v(n) == 0;
}
int
cond(int op)
{
switch(op) {
case OANDAND:
case OOROR:
case ONOT:
return 1;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
return 1;
}
return 0;
}
/*
* for a func operand call it and then return
* the safe node
*/
static Node *
vfunc(Node *n, Node *nn)
{
Node *t;
if(n->op != OFUNC)
return n;
t = new(0, Z, Z);
if(nn == Z || nn == nodret)
nn = n;
regsalloc(t, nn);
sugen(n, t, 8);
return t;
}
static int
forcereg(Node *d, int r, int o, Node *t)
{
int a;
if(d->reg != D_NONE)
diag(Z, "force alloc");
d->reg = r;
a = 0;
if(reg[r]) {
reg[o]++;
regalloc(t, d, Z);
a = 1;
gins(AMOVL, d, t);
reg[o]--;
}
reg[r]++;
return a;
}
/* try to steal a reg */
static int
getreg(Node **np, Node *t, int r)
{
Node *n, *p;
n = *np;
if(n->reg == r) {
p = new(0, Z, Z);
regalloc(p, n, Z);
gins(AMOVL, n, p);
*t = *n;
*np = p;
return 1;
}
return 0;
}
static Node *
snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
{
if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
if(nodreg(t, Z, r)) {
regalloc(c, d, Z);
gins(AMOVL, t, c);
reg[r]++;
return c;
}
reg[r]++;
}
return Z;
}
enum
{
Vstart = OEND,
Vgo,
Vamv,
Vmv,
Vzero,
Vop,
Vopx,
Vins,
Vins0,
Vinsl,
Vinsr,
Vinsla,
Vinsra,
Vinsx,
Vmul,
Vshll,
VT,
VF,
V_l_lo_f,
V_l_hi_f,
V_l_lo_t,
V_l_hi_t,
V_l_lo_u,
V_l_hi_u,
V_r_lo_f,
V_r_hi_f,
V_r_lo_t,
V_r_hi_t,
V_r_lo_u,
V_r_hi_u,
Vspazz,
Vend,
V_T0,
V_T1,
V_F0,
V_F1,
V_a0,
V_a1,
V_f0,
V_f1,
V_p0,
V_p1,
V_p2,
V_p3,
V_p4,
V_s0,
V_s1,
V_s2,
V_s3,
V_s4,
C00,
C01,
C31,
C32,
O_l_lo,
O_l_hi,
O_r_lo,
O_r_hi,
O_t_lo,
O_t_hi,
O_l,
O_r,
O_l_rp,
O_r_rp,
O_t_rp,
O_r0,
O_r1,
O_Zop,
O_a0,
O_a1,
V_C0,
V_C1,
V_S0,
V_S1,
VOPS = 5,
VLEN = 5,
VARGS = 2,
S00 = 0,
Sc0,
Sc1,
Sc2,
Sac3,
Sac4,
S10,
SAgen = 0,
SAclo,
SAc32,
SAchi,
SAdgen,
SAdclo,
SAdc32,
SAdchi,
B0c = 0,
Bca,
Bac,
T0i = 0,
Tii,
Bop0 = 0,
Bop1,
};
/*
* _testv:
* CMPL lo,$0
* JNE true
* CMPL hi,$0
* JNE true
* GOTO false
* false:
* GOTO code
* true:
* GOTO patchme
* code:
*/
static uchar testi[][VLEN] =
{
{Vop, ONE, O_l_lo, C00},
{V_s0, Vop, ONE, O_l_hi, C00},
{V_s1, Vgo, V_s2, Vgo, V_s3},
{VF, V_p0, V_p1, VT, V_p2},
{Vgo, V_p3},
{VT, V_p0, V_p1, VF, V_p2},
{Vend},
};
/* shift left general case */
static uchar shll00[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vinsl, ASHLL, O_r, O_l_rp},
{Vins, ASHLL, O_r, O_l_lo, Vgo},
{V_p0, V_s0},
{Vins, ASHLL, O_r, O_l_lo},
{Vins, AMOVL, O_l_lo, O_l_hi},
{Vzero, O_l_lo, V_p0, Vend},
};
/* shift left rp, const < 32 */
static uchar shllc0[][VLEN] =
{
{Vinsl, ASHLL, O_r, O_l_rp},
{Vshll, O_r, O_l_lo, Vend},
};
/* shift left rp, const == 32 */
static uchar shllc1[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_l_hi},
{Vzero, O_l_lo, Vend},
};
/* shift left rp, const > 32 */
static uchar shllc2[][VLEN] =
{
{Vshll, O_r, O_l_lo},
{Vins, AMOVL, O_l_lo, O_l_hi},
{Vzero, O_l_lo, Vend},
};
/* shift left addr, const == 32 */
static uchar shllac3[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_hi},
{Vzero, O_t_lo, Vend},
};
/* shift left addr, const > 32 */
static uchar shllac4[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_hi},
{Vshll, O_r, O_t_hi},
{Vzero, O_t_lo, Vend},
};
/* shift left of constant */
static uchar shll10[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsl, ASHLL, O_r, O_t_rp},
{Vins, ASHLL, O_r, O_t_lo, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_lo, O_t_hi},
{V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
{Vzero, O_t_lo, V_p0, Vend},
};
static uchar (*shlltab[])[VLEN] =
{
shll00,
shllc0,
shllc1,
shllc2,
shllac3,
shllac4,
shll10,
};
/* shift right general case */
static uchar shrl00[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vinsr, ASHRL, O_r, O_l_rp},
{Vins, O_a0, O_r, O_l_hi, Vgo},
{V_p0, V_s0},
{Vins, O_a0, O_r, O_l_hi},
{Vins, AMOVL, O_l_hi, O_l_lo},
{V_T1, Vzero, O_l_hi},
{V_F1, Vins, ASARL, C31, O_l_hi},
{V_p0, Vend},
};
/* shift right rp, const < 32 */
static uchar shrlc0[][VLEN] =
{
{Vinsr, ASHRL, O_r, O_l_rp},
{Vins, O_a0, O_r, O_l_hi, Vend},
};
/* shift right rp, const == 32 */
static uchar shrlc1[][VLEN] =
{
{Vins, AMOVL, O_l_hi, O_l_lo},
{V_T1, Vzero, O_l_hi},
{V_F1, Vins, ASARL, C31, O_l_hi},
{Vend},
};
/* shift right rp, const > 32 */
static uchar shrlc2[][VLEN] =
{
{Vins, O_a0, O_r, O_l_hi},
{Vins, AMOVL, O_l_hi, O_l_lo},
{V_T1, Vzero, O_l_hi},
{V_F1, Vins, ASARL, C31, O_l_hi},
{Vend},
};
/* shift right addr, const == 32 */
static uchar shrlac3[][VLEN] =
{
{Vins, AMOVL, O_l_hi, O_t_lo},
{V_T1, Vzero, O_t_hi},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{Vend},
};
/* shift right addr, const > 32 */
static uchar shrlac4[][VLEN] =
{
{Vins, AMOVL, O_l_hi, O_t_lo},
{Vins, O_a0, O_r, O_t_lo},
{V_T1, Vzero, O_t_hi},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{Vend},
};
/* shift right of constant */
static uchar shrl10[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsr, ASHRL, O_r, O_t_rp},
{Vins, O_a0, O_r, O_t_hi, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_hi, O_t_lo},
{V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
{V_l_hi_u, V_S1},
{V_T1, Vzero, O_t_hi, V_p0},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{Vend},
};
static uchar (*shrltab[])[VLEN] =
{
shrl00,
shrlc0,
shrlc1,
shrlc2,
shrlac3,
shrlac4,
shrl10,
};
/* shift asop left general case */
static uchar asshllgen[][VLEN] =
{
{V_a0, V_a1},
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_r0},
{Vins, AMOVL, O_l_hi, O_r1},
{Vinsla, ASHLL, O_r, O_r0},
{Vins, ASHLL, O_r, O_r0},
{Vins, AMOVL, O_r1, O_l_hi},
{Vins, AMOVL, O_r0, O_l_lo, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_lo, O_r0},
{Vzero, O_l_lo},
{Vins, ASHLL, O_r, O_r0},
{Vins, AMOVL, O_r0, O_l_hi, V_p0},
{V_f0, V_f1, Vend},
};
/* shift asop left, const < 32 */
static uchar asshllclo[][VLEN] =
{
{V_a0, V_a1},
{Vins, AMOVL, O_l_lo, O_r0},
{Vins, AMOVL, O_l_hi, O_r1},
{Vinsla, ASHLL, O_r, O_r0},
{Vshll, O_r, O_r0},
{Vins, AMOVL, O_r1, O_l_hi},
{Vins, AMOVL, O_r0, O_l_lo},
{V_f0, V_f1, Vend},
};
/* shift asop left, const == 32 */
static uchar asshllc32[][VLEN] =
{
{V_a0},
{Vins, AMOVL, O_l_lo, O_r0},
{Vzero, O_l_lo},
{Vins, AMOVL, O_r0, O_l_hi},
{V_f0, Vend},
};
/* shift asop left, const > 32 */
static uchar asshllchi[][VLEN] =
{
{V_a0},
{Vins, AMOVL, O_l_lo, O_r0},
{Vzero, O_l_lo},
{Vshll, O_r, O_r0},
{Vins, AMOVL, O_r0, O_l_hi},
{V_f0, Vend},
};
/* shift asop dest left general case */
static uchar asdshllgen[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsl, ASHLL, O_r, O_t_rp},
{Vins, ASHLL, O_r, O_t_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_lo, O_t_hi},
{Vzero, O_l_lo},
{Vins, ASHLL, O_r, O_t_hi},
{Vzero, O_t_lo},
{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
{Vend},
};
/* shift asop dest left, const < 32 */
static uchar asdshllclo[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsl, ASHLL, O_r, O_t_rp},
{Vshll, O_r, O_t_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vend},
};
/* shift asop dest left, const == 32 */
static uchar asdshllc32[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_hi},
{Vzero, O_t_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vend},
};
/* shift asop dest, const > 32 */
static uchar asdshllchi[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_hi},
{Vzero, O_t_lo},
{Vshll, O_r, O_t_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vend},
};
static uchar (*asshlltab[])[VLEN] =
{
asshllgen,
asshllclo,
asshllc32,
asshllchi,
asdshllgen,
asdshllclo,
asdshllc32,
asdshllchi,
};
/* shift asop right general case */
static uchar asshrlgen[][VLEN] =
{
{V_a0, V_a1},
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_r0},
{Vins, AMOVL, O_l_hi, O_r1},
{Vinsra, ASHRL, O_r, O_r0},
{Vinsx, Bop0, O_r, O_r1},
{Vins, AMOVL, O_r0, O_l_lo},
{Vins, AMOVL, O_r1, O_l_hi, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_hi, O_r0},
{Vinsx, Bop0, O_r, O_r0},
{V_T1, Vzero, O_l_hi},
{Vins, AMOVL, O_r0, O_l_lo},
{V_F1, Vins, ASARL, C31, O_r0},
{V_F1, Vins, AMOVL, O_r0, O_l_hi},
{V_p0, V_f0, V_f1, Vend},
};
/* shift asop right, const < 32 */
static uchar asshrlclo[][VLEN] =
{
{V_a0, V_a1},
{Vins, AMOVL, O_l_lo, O_r0},
{Vins, AMOVL, O_l_hi, O_r1},
{Vinsra, ASHRL, O_r, O_r0},
{Vinsx, Bop0, O_r, O_r1},
{Vins, AMOVL, O_r0, O_l_lo},
{Vins, AMOVL, O_r1, O_l_hi},
{V_f0, V_f1, Vend},
};
/* shift asop right, const == 32 */
static uchar asshrlc32[][VLEN] =
{
{V_a0},
{Vins, AMOVL, O_l_hi, O_r0},
{V_T1, Vzero, O_l_hi},
{Vins, AMOVL, O_r0, O_l_lo},
{V_F1, Vins, ASARL, C31, O_r0},
{V_F1, Vins, AMOVL, O_r0, O_l_hi},
{V_f0, Vend},
};
/* shift asop right, const > 32 */
static uchar asshrlchi[][VLEN] =
{
{V_a0},
{Vins, AMOVL, O_l_hi, O_r0},
{V_T1, Vzero, O_l_hi},
{Vinsx, Bop0, O_r, O_r0},
{Vins, AMOVL, O_r0, O_l_lo},
{V_F1, Vins, ASARL, C31, O_r0},
{V_F1, Vins, AMOVL, O_r0, O_l_hi},
{V_f0, Vend},
};
/* shift asop dest right general case */
static uchar asdshrlgen[][VLEN] =
{
{Vop, OGE, O_r, C32},
{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsr, ASHRL, O_r, O_t_rp},
{Vinsx, Bop0, O_r, O_t_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
{V_p0, V_s0},
{Vins, AMOVL, O_l_hi, O_t_lo},
{V_T1, Vzero, O_t_hi},
{Vinsx, Bop0, O_r, O_t_lo},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
{Vend},
};
/* shift asop dest right, const < 32 */
static uchar asdshrlclo[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsr, ASHRL, O_r, O_t_rp},
{Vinsx, Bop0, O_r, O_t_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vend},
};
/* shift asop dest right, const == 32 */
static uchar asdshrlc32[][VLEN] =
{
{Vins, AMOVL, O_l_hi, O_t_lo},
{V_T1, Vzero, O_t_hi},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vins, AMOVL, O_t_hi, O_l_hi},
{Vend},
};
/* shift asop dest, const > 32 */
static uchar asdshrlchi[][VLEN] =
{
{Vins, AMOVL, O_l_hi, O_t_lo},
{V_T1, Vzero, O_t_hi},
{Vinsx, Bop0, O_r, O_t_lo},
{V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
{V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
{V_F1, Vins, ASARL, C31, O_t_hi},
{V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
{V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
{Vend},
};
static uchar (*asshrltab[])[VLEN] =
{
asshrlgen,
asshrlclo,
asshrlc32,
asshrlchi,
asdshrlgen,
asdshrlclo,
asdshrlc32,
asdshrlchi,
};
static uchar shrlargs[] = { ASHRL, 1 };
static uchar sarlargs[] = { ASARL, 0 };
/* ++ -- */
static uchar incdec[][VLEN] =
{
{Vinsx, Bop0, C01, O_l_lo},
{Vinsx, Bop1, C00, O_l_hi, Vend},
};
/* ++ -- *p */
static uchar incdecpre[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsx, Bop0, C01, O_t_lo},
{Vinsx, Bop1, C00, O_t_hi},
{Vins, AMOVL, O_t_lo, O_l_lo},
{Vins, AMOVL, O_t_hi, O_l_hi, Vend},
};
/* *p ++ -- */
static uchar incdecpost[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsx, Bop0, C01, O_l_lo},
{Vinsx, Bop1, C00, O_l_hi, Vend},
};
/* binop rp, rp */
static uchar binop00[][VLEN] =
{
{Vinsx, Bop0, O_r_lo, O_l_lo},
{Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
{Vend},
};
/* binop rp, addr */
static uchar binoptmp[][VLEN] =
{
{V_a0, Vins, AMOVL, O_r_lo, O_r0},
{Vinsx, Bop0, O_r0, O_l_lo},
{Vins, AMOVL, O_r_hi, O_r0},
{Vinsx, Bop1, O_r0, O_l_hi},
{V_f0, Vend},
};
/* binop t = *a op *b */
static uchar binop11[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vinsx, Bop0, O_r_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
};
/* binop t = rp +- c */
static uchar add0c[][VLEN] =
{
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
{V_r_lo_f, Vamv, Bop0, Bop1},
{Vinsx, Bop1, O_r_hi, O_l_hi},
{Vend},
};
/* binop t = rp & c */
static uchar and0c[][VLEN] =
{
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
{V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
{V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
{Vend},
};
/* binop t = rp | c */
static uchar or0c[][VLEN] =
{
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
{Vend},
};
/* binop t = c - rp */
static uchar sub10[][VLEN] =
{
{V_a0, Vins, AMOVL, O_l_lo, O_r0},
{Vinsx, Bop0, O_r_lo, O_r0},
{Vins, AMOVL, O_l_hi, O_r_lo},
{Vinsx, Bop1, O_r_hi, O_r_lo},
{Vspazz, V_f0, Vend},
};
/* binop t = c + *b */
static uchar addca[][VLEN] =
{
{Vins, AMOVL, O_r_lo, O_t_lo},
{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
{V_l_lo_f, Vamv, Bop0, Bop1},
{Vins, AMOVL, O_r_hi, O_t_hi},
{Vinsx, Bop1, O_l_hi, O_t_hi},
{Vend},
};
/* binop t = c & *b */
static uchar andca[][VLEN] =
{
{V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
{V_l_lo_f, Vzero, O_t_lo},
{V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
{V_l_hi_f, Vzero, O_t_hi},
{Vend},
};
/* binop t = c | *b */
static uchar orca[][VLEN] =
{
{Vins, AMOVL, O_r_lo, O_t_lo},
{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
{Vins, AMOVL, O_r_hi, O_t_hi},
{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
{Vend},
};
/* binop t = c - *b */
static uchar subca[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsx, Bop0, O_r_lo, O_t_lo},
{Vinsx, Bop1, O_r_hi, O_t_hi},
{Vend},
};
/* binop t = *a +- c */
static uchar addac[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
{V_r_lo_f, Vamv, Bop0, Bop1},
{Vins, AMOVL, O_l_hi, O_t_hi},
{Vinsx, Bop1, O_r_hi, O_t_hi},
{Vend},
};
/* binop t = *a | c */
static uchar orac[][VLEN] =
{
{Vins, AMOVL, O_l_lo, O_t_lo},
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
{Vins, AMOVL, O_l_hi, O_t_hi},
{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
{Vend},
};
/* binop t = *a & c */
static uchar andac[][VLEN] =
{
{V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
{V_r_lo_f, Vzero, O_t_lo},
{V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
{V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
{V_r_hi_f, Vzero, O_t_hi},
{Vend},
};
static uchar ADDargs[] = { AADDL, AADCL };
static uchar ANDargs[] = { AANDL, AANDL };
static uchar ORargs[] = { AORL, AORL };
static uchar SUBargs[] = { ASUBL, ASBBL };
static uchar XORargs[] = { AXORL, AXORL };
static uchar (*ADDtab[])[VLEN] =
{
add0c, addca, addac,
};
static uchar (*ANDtab[])[VLEN] =
{
and0c, andca, andac,
};
static uchar (*ORtab[])[VLEN] =
{
or0c, orca, orac,
};
static uchar (*SUBtab[])[VLEN] =
{
add0c, subca, addac,
};
/* mul of const32 */
static uchar mulc32[][VLEN] =
{
{V_a0, Vop, ONE, O_l_hi, C00},
{V_s0, Vins, AMOVL, O_r_lo, O_r0},
{Vins, AMULL, O_r0, O_Zop},
{Vgo, V_p0, V_s0},
{Vins, AMOVL, O_l_hi, O_r0},
{Vmul, O_r_lo, O_r0},
{Vins, AMOVL, O_r_lo, O_l_hi},
{Vins, AMULL, O_l_hi, O_Zop},
{Vins, AADDL, O_r0, O_l_hi},
{V_f0, V_p0, Vend},
};
/* mul of const64 */
static uchar mulc64[][VLEN] =
{
{V_a0, Vins, AMOVL, O_r_hi, O_r0},
{Vop, OOR, O_l_hi, O_r0},
{Vop, ONE, O_r0, C00},
{V_s0, Vins, AMOVL, O_r_lo, O_r0},
{Vins, AMULL, O_r0, O_Zop},
{Vgo, V_p0, V_s0},
{Vmul, O_r_lo, O_l_hi},
{Vins, AMOVL, O_l_lo, O_r0},
{Vmul, O_r_hi, O_r0},
{Vins, AADDL, O_l_hi, O_r0},
{Vins, AMOVL, O_r_lo, O_l_hi},
{Vins, AMULL, O_l_hi, O_Zop},
{Vins, AADDL, O_r0, O_l_hi},
{V_f0, V_p0, Vend},
};
/* mul general */
static uchar mull[][VLEN] =
{
{V_a0, Vins, AMOVL, O_r_hi, O_r0},
{Vop, OOR, O_l_hi, O_r0},
{Vop, ONE, O_r0, C00},
{V_s0, Vins, AMOVL, O_r_lo, O_r0},
{Vins, AMULL, O_r0, O_Zop},
{Vgo, V_p0, V_s0},
{Vins, AIMULL, O_r_lo, O_l_hi},
{Vins, AMOVL, O_l_lo, O_r0},
{Vins, AIMULL, O_r_hi, O_r0},
{Vins, AADDL, O_l_hi, O_r0},
{Vins, AMOVL, O_r_lo, O_l_hi},
{Vins, AMULL, O_l_hi, O_Zop},
{Vins, AADDL, O_r0, O_l_hi},
{V_f0, V_p0, Vend},
};
/* cast rp l to rp t */
static uchar castrp[][VLEN] =
{
{Vmv, O_l, O_t_lo},
{VT, Vins, AMOVL, O_t_lo, O_t_hi},
{VT, Vins, ASARL, C31, O_t_hi},
{VF, Vzero, O_t_hi},
{Vend},
};
/* cast rp l to addr t */
static uchar castrpa[][VLEN] =
{
{VT, V_a0, Vmv, O_l, O_r0},
{VT, Vins, AMOVL, O_r0, O_t_lo},
{VT, Vins, ASARL, C31, O_r0},
{VT, Vins, AMOVL, O_r0, O_t_hi},
{VT, V_f0},
{VF, Vmv, O_l, O_t_lo},
{VF, Vzero, O_t_hi},
{Vend},
};
static uchar netab0i[][VLEN] =
{
{Vop, ONE, O_l_lo, O_r_lo},
{V_s0, Vop, ONE, O_l_hi, O_r_hi},
{V_s1, Vgo, V_s2, Vgo, V_s3},
{VF, V_p0, V_p1, VT, V_p2},
{Vgo, V_p3},
{VT, V_p0, V_p1, VF, V_p2},
{Vend},
};
static uchar netabii[][VLEN] =
{
{V_a0, Vins, AMOVL, O_l_lo, O_r0},
{Vop, ONE, O_r0, O_r_lo},
{V_s0, Vins, AMOVL, O_l_hi, O_r0},
{Vop, ONE, O_r0, O_r_hi},
{V_s1, Vgo, V_s2, Vgo, V_s3},
{VF, V_p0, V_p1, VT, V_p2},
{Vgo, V_p3},
{VT, V_p0, V_p1, VF, V_p2},
{V_f0, Vend},
};
static uchar cmptab0i[][VLEN] =
{
{Vopx, Bop0, O_l_hi, O_r_hi},
{V_s0, Vins0, AJNE},
{V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
{V_s2, Vgo, V_s3, Vgo, V_s4},
{VT, V_p1, V_p3},
{VF, V_p0, V_p2},
{Vgo, V_p4},
{VT, V_p0, V_p2},
{VF, V_p1, V_p3},
{Vend},
};
static uchar cmptabii[][VLEN] =
{
{V_a0, Vins, AMOVL, O_l_hi, O_r0},
{Vopx, Bop0, O_r0, O_r_hi},
{V_s0, Vins0, AJNE},
{V_s1, Vins, AMOVL, O_l_lo, O_r0},
{Vopx, Bop1, O_r0, O_r_lo},
{V_s2, Vgo, V_s3, Vgo, V_s4},
{VT, V_p1, V_p3},
{VF, V_p0, V_p2},
{Vgo, V_p4},
{VT, V_p0, V_p2},
{VF, V_p1, V_p3},
{V_f0, Vend},
};
static uchar (*NEtab[])[VLEN] =
{
netab0i, netabii,
};
static uchar (*cmptab[])[VLEN] =
{
cmptab0i, cmptabii,
};
static uchar GEargs[] = { OGT, OHS };
static uchar GTargs[] = { OGT, OHI };
static uchar HIargs[] = { OHI, OHI };
static uchar HSargs[] = { OHI, OHS };
/* Big Generator */
static void
biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
{
int i, j, g, oc, op, lo, ro, to, xo, *xp;
Type *lt;
Prog *pr[VOPS];
Node *ot, *tl, *tr, tmps[2];
uchar *c, (*cp)[VLEN], args[VARGS];
if(a != nil)
memmove(args, a, VARGS);
//print("biggen %d %d %d\n", args[0], args[1], args[2]);
//if(l) prtree(l, "l");
//if(r) prtree(r, "r");
//if(t) prtree(t, "t");
lo = ro = to = 0;
cp = code;
for (;;) {
c = *cp++;
g = 1;
i = 0;
//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
for(;;) {
switch(op = c[i]) {
case Vgo:
if(g)
gbranch(OGOTO);
i++;
break;
case Vamv:
i += 3;
if(i > VLEN) {
diag(l, "bad Vop");
return;
}
if(g)
args[c[i - 1]] = args[c[i - 2]];
break;
case Vzero:
i += 2;
if(i > VLEN) {
diag(l, "bad Vop");
return;
}
j = i - 1;
goto op;
case Vspazz: // nasty hack to save a reg in SUB
//print("spazz\n");
if(g) {
//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
ot = r->right;
r->right = r->left;
tl = new(0, Z, Z);
*tl = tmps[0];
r->left = tl;
tmps[0] = *ot;
//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
}
i++;
break;
case Vmv:
case Vmul:
case Vshll:
i += 3;
if(i > VLEN) {
diag(l, "bad Vop");
return;
}
j = i - 2;
goto op;
case Vins0:
i += 2;
if(i > VLEN) {
diag(l, "bad Vop");
return;
}
gins(c[i - 1], Z, Z);
break;
case Vop:
case Vopx:
case Vins:
case Vinsl:
case Vinsr:
case Vinsla:
case Vinsra:
case Vinsx:
i += 4;
if(i > VLEN) {
diag(l, "bad Vop");
return;
}
j = i - 2;
goto op;
op:
if(!g)
break;
tl = Z;
tr = Z;
for(; j < i; j++) {
switch(c[j]) {
case C00:
ot = nodconst(0);
break;
case C01:
ot = nodconst(1);
break;
case C31:
ot = nodconst(31);
break;
case C32:
ot = nodconst(32);
break;
case O_l:
case O_l_lo:
ot = l; xp = &lo; xo = 0;
goto op0;
case O_l_hi:
ot = l; xp = &lo; xo = SZ_LONG;
goto op0;
case O_r:
case O_r_lo:
ot = r; xp = &ro; xo = 0;
goto op0;
case O_r_hi:
ot = r; xp = &ro; xo = SZ_LONG;
goto op0;
case O_t_lo:
ot = t; xp = &to; xo = 0;
goto op0;
case O_t_hi:
ot = t; xp = &to; xo = SZ_LONG;
goto op0;
case O_l_rp:
ot = l;
break;
case O_r_rp:
ot = r;
break;
case O_t_rp:
ot = t;
break;
case O_r0:
case O_r1:
ot = &tmps[c[j] - O_r0];
break;
case O_Zop:
ot = Z;
break;
op0:
switch(ot->op) {
case OCONST:
if(xo)
ot = hi64(ot);
else
ot = lo64(ot);
break;
case OREGPAIR:
if(xo)
ot = ot->right;
else
ot = ot->left;
break;
case OREGISTER:
break;
default:
if(xo != *xp) {
ot->xoffset += xo - *xp;
*xp = xo;
}
}
break;
default:
diag(l, "bad V_lop");
return;
}
if(tl == nil)
tl = ot;
else
tr = ot;
}
if(op == Vzero) {
zeroregm(tl);
break;
}
oc = c[i - 3];
if(op == Vinsx || op == Vopx) {
//print("%d -> %d\n", oc, args[oc]);
oc = args[oc];
}
else {
switch(oc) {
case O_a0:
case O_a1:
oc = args[oc - O_a0];
break;
}
}
switch(op) {
case Vmul:
mulgen(tr->type, tl, tr);
break;
case Vmv:
gmove(tl, tr);
break;
case Vshll:
shiftit(tr->type, tl, tr);
break;
case Vop:
case Vopx:
gopcode(oc, types[TULONG], tl, tr);
break;
case Vins:
case Vinsx:
gins(oc, tl, tr);
break;
case Vinsl:
gins(oc, tl, tr->right);
p->from.index = tr->left->reg;
break;
case Vinsr:
gins(oc, tl, tr->left);
p->from.index = tr->right->reg;
break;
case Vinsla:
gins(oc, tl, tr + 1);
p->from.index = tr->reg;
break;
case Vinsra:
gins(oc, tl, tr);
p->from.index = (tr + 1)->reg;
break;
}
break;
case VT:
g = true;
i++;
break;
case VF:
g = !true;
i++;
break;
case V_T0: case V_T1:
g = args[op - V_T0];
i++;
break;
case V_F0: case V_F1:
g = !args[op - V_F0];
i++;
break;
case V_C0: case V_C1:
if(g)
args[op - V_C0] = 0;
i++;
break;
case V_S0: case V_S1:
if(g)
args[op - V_S0] = 1;
i++;
break;
case V_l_lo_f:
g = lo64v(l) == 0;
i++;
break;
case V_l_hi_f:
g = hi64v(l) == 0;
i++;
break;
case V_l_lo_t:
g = lo64v(l) != 0;
i++;
break;
case V_l_hi_t:
g = hi64v(l) != 0;
i++;
break;
case V_l_lo_u:
g = lo64v(l) >= 0;
i++;
break;
case V_l_hi_u:
g = hi64v(l) >= 0;
i++;
break;
case V_r_lo_f:
g = lo64v(r) == 0;
i++;
break;
case V_r_hi_f:
g = hi64v(r) == 0;
i++;
break;
case V_r_lo_t:
g = lo64v(r) != 0;
i++;
break;
case V_r_hi_t:
g = hi64v(r) != 0;
i++;
break;
case V_r_lo_u:
g = lo64v(r) >= 0;
i++;
break;
case V_r_hi_u:
g = hi64v(r) >= 0;
i++;
break;
case Vend:
goto out;
case V_a0: case V_a1:
if(g) {
lt = l->type;
l->type = types[TULONG];
regalloc(&tmps[op - V_a0], l, Z);
l->type = lt;
}
i++;
break;
case V_f0: case V_f1:
if(g)
regfree(&tmps[op - V_f0]);
i++;
break;
case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
if(g)
patch(pr[op - V_p0], pc);
i++;
break;
case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
if(g)
pr[op - V_s0] = p;
i++;
break;
default:
diag(l, "bad biggen: %d", op);
return;
}
if(i == VLEN || c[i] == 0)
break;
}
}
out:
if(lo)
l->xoffset -= lo;
if(ro)
r->xoffset -= ro;
if(to)
t->xoffset -= to;
}
int
cgen64(Node *n, Node *nn)
{
Type *dt;
uchar *args, (*cp)[VLEN], (**optab)[VLEN];
int li, ri, lri, dr, si, m, op, sh, cmp, true;
Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
if(debug['g']) {
prtree(nn, "cgen64 lhs");
prtree(n, "cgen64");
print("AX = %d\n", reg[D_AX]);
}
cmp = 0;
sh = 0;
switch(n->op) {
case ONEG:
d = regpair(nn, n);
sugen(n->left, d, 8);
gins(ANOTL, Z, d->right);
gins(ANEGL, Z, d->left);
gins(ASBBL, nodconst(-1), d->right);
break;
case OCOM:
if(!vaddr(n->left, 0) || !vaddr(nn, 0))
d = regpair(nn, n);
else
return 0;
sugen(n->left, d, 8);
gins(ANOTL, Z, d->left);
gins(ANOTL, Z, d->right);
break;
case OADD:
optab = ADDtab;
args = ADDargs;
goto twoop;
case OAND:
optab = ANDtab;
args = ANDargs;
goto twoop;
case OOR:
optab = ORtab;
args = ORargs;
goto twoop;
case OSUB:
optab = SUBtab;
args = SUBargs;
goto twoop;
case OXOR:
optab = ORtab;
args = XORargs;
goto twoop;
case OASHL:
sh = 1;
args = nil;
optab = shlltab;
goto twoop;
case OLSHR:
sh = 1;
args = shrlargs;
optab = shrltab;
goto twoop;
case OASHR:
sh = 1;
args = sarlargs;
optab = shrltab;
goto twoop;
case OEQ:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case ONE:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OLE:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OLT:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OGE:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OGT:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OHI:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OHS:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OLO:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
case OLS:
cmp = 1;
args = nil;
optab = nil;
goto twoop;
twoop:
dr = nn != Z && nn->op == OREGPAIR;
l = vfunc(n->left, nn);
if(sh)
r = n->right;
else
r = vfunc(n->right, nn);
li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
#define IMM(l, r) ((l) | ((r) << 1))
lri = IMM(li, ri);
/* find out what is so easy about some operands */
if(li)
li = whatof(l, sh | cmp);
if(ri)
ri = whatof(r, cmp);
if(sh)
goto shift;
if(cmp)
goto cmp;
/* evaluate hard subexps, stealing nn if possible. */
switch(lri) {
case IMM(0, 0):
bin00:
if(l->complex > r->complex) {
if(dr)
t = nn;
else
t = regpair(Z, n);
sugen(l, t, 8);
l = t;
t = regpair(Z, n);
sugen(r, t, 8);
r = t;
}
else {
t = regpair(Z, n);
sugen(r, t, 8);
r = t;
if(dr)
t = nn;
else
t = regpair(Z, n);
sugen(l, t, 8);
l = t;
}
break;
case IMM(0, 1):
if(dr)
t = nn;
else
t = regpair(Z, n);
sugen(l, t, 8);
l = t;
break;
case IMM(1, 0):
if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
lri = IMM(0, 0);
goto bin00;
}
if(dr)
t = nn;
else
t = regpair(Z, n);
sugen(r, t, 8);
r = t;
break;
case IMM(1, 1):
break;
}
#define WW(l, r) ((l) | ((r) << 2))
d = Z;
dt = nn->type;
nn->type = types[TLONG];
switch(lri) {
case IMM(0, 0):
biggen(l, r, Z, 0, binop00, args);
break;
case IMM(0, 1):
switch(ri) {
case WNONE:
diag(r, "bad whatof\n");
break;
case WCONST:
biggen(l, r, Z, 0, optab[B0c], args);
break;
case WHARD:
reglcgen(&nod2, r, Z);
r = &nod2;
/* fall thru */
case WADDR:
biggen(l, r, Z, 0, binoptmp, args);
if(ri == WHARD)
regfree(r);
break;
}
break;
case IMM(1, 0):
if(n->op == OSUB) {
switch(li) {
case WNONE:
diag(l, "bad whatof\n");
break;
case WHARD:
reglcgen(&nod2, l, Z);
l = &nod2;
/* fall thru */
case WADDR:
case WCONST:
biggen(l, r, Z, 0, sub10, args);
break;
}
if(li == WHARD)
regfree(l);
}
else {
switch(li) {
case WNONE:
diag(l, "bad whatof\n");
break;
case WCONST:
biggen(r, l, Z, 0, optab[B0c], args);
break;
case WHARD:
reglcgen(&nod2, l, Z);
l = &nod2;
/* fall thru */
case WADDR:
biggen(r, l, Z, 0, binoptmp, args);
if(li == WHARD)
regfree(l);
break;
}
}
break;
case IMM(1, 1):
switch(WW(li, ri)) {
case WW(WCONST, WHARD):
if(r->op == ONAME && n->op == OAND && reduxv(l))
ri = WADDR;
break;
case WW(WHARD, WCONST):
if(l->op == ONAME && n->op == OAND && reduxv(r))
li = WADDR;
break;
}
if(li == WHARD) {
reglcgen(&nod3, l, Z);
l = &nod3;
}
if(ri == WHARD) {
reglcgen(&nod2, r, Z);
r = &nod2;
}
d = regpair(nn, n);
instpair(d, Z);
switch(WW(li, ri)) {
case WW(WCONST, WADDR):
case WW(WCONST, WHARD):
biggen(l, r, d, 0, optab[Bca], args);
break;
case WW(WADDR, WCONST):
case WW(WHARD, WCONST):
biggen(l, r, d, 0, optab[Bac], args);
break;
case WW(WADDR, WADDR):
case WW(WADDR, WHARD):
case WW(WHARD, WADDR):
case WW(WHARD, WHARD):
biggen(l, r, d, 0, binop11, args);
break;
default:
diag(r, "bad whatof pair %d %d\n", li, ri);
break;
}
if(li == WHARD)
regfree(l);
if(ri == WHARD)
regfree(r);
break;
}
nn->type = dt;
if(d != Z)
goto finished;
switch(lri) {
case IMM(0, 0):
freepair(r);
/* fall thru */;
case IMM(0, 1):
if(!dr)
storepair(l, nn, 1);
break;
case IMM(1, 0):
if(!dr)
storepair(r, nn, 1);
break;
case IMM(1, 1):
break;
}
return 1;
shift:
c = Z;
/* evaluate hard subexps, stealing nn if possible. */
/* must also secure CX. not as many optims as binop. */
switch(lri) {
case IMM(0, 0):
imm00:
if(l->complex + 1 > r->complex) {
if(dr)
t = nn;
else
t = regpair(Z, l);
sugen(l, t, 8);
l = t;
t = &nod1;
c = snarfreg(l, t, D_CX, r, &nod2);
cgen(r, t);
r = t;
}
else {
t = &nod1;
c = snarfreg(nn, t, D_CX, r, &nod2);
cgen(r, t);
r = t;
if(dr)
t = nn;
else
t = regpair(Z, l);
sugen(l, t, 8);
l = t;
}
break;
case IMM(0, 1):
imm01:
if(ri != WCONST) {
lri = IMM(0, 0);
goto imm00;
}
if(dr)
t = nn;
else
t = regpair(Z, n);
sugen(l, t, 8);
l = t;
break;
case IMM(1, 0):
imm10:
if(li != WCONST) {
lri = IMM(0, 0);
goto imm00;
}
t = &nod1;
c = snarfreg(nn, t, D_CX, r, &nod2);
cgen(r, t);
r = t;
break;
case IMM(1, 1):
if(ri != WCONST) {
lri = IMM(1, 0);
goto imm10;
}
if(li == WHARD) {
lri = IMM(0, 1);
goto imm01;
}
break;
}
d = Z;
switch(lri) {
case IMM(0, 0):
biggen(l, r, Z, 0, optab[S00], args);
break;
case IMM(0, 1):
switch(ri) {
case WNONE:
case WADDR:
case WHARD:
diag(r, "bad whatof\n");
break;
case WCONST:
m = r->vconst & 63;
s = nodconst(m);
if(m < 32)
cp = optab[Sc0];
else if(m == 32)
cp = optab[Sc1];
else
cp = optab[Sc2];
biggen(l, s, Z, 0, cp, args);
break;
}
break;
case IMM(1, 0):
/* left is const */
d = regpair(nn, n);
instpair(d, Z);
biggen(l, r, d, 0, optab[S10], args);
regfree(r);
break;
case IMM(1, 1):
d = regpair(nn, n);
instpair(d, Z);
switch(WW(li, ri)) {
case WW(WADDR, WCONST):
m = r->vconst & 63;
s = nodconst(m);
if(m < 32) {
loadpair(l, d);
l = d;
cp = optab[Sc0];
}
else if(m == 32)
cp = optab[Sac3];
else
cp = optab[Sac4];
biggen(l, s, d, 0, cp, args);
break;
default:
diag(r, "bad whatof pair %d %d\n", li, ri);
break;
}
break;
}
if(c != Z) {
gins(AMOVL, c, r);
regfree(c);
}
if(d != Z)
goto finished;
switch(lri) {
case IMM(0, 0):
regfree(r);
/* fall thru */
case IMM(0, 1):
if(!dr)
storepair(l, nn, 1);
break;
case IMM(1, 0):
regfree(r);
break;
case IMM(1, 1):
break;
}
return 1;
cmp:
op = n->op;
/* evaluate hard subexps */
switch(lri) {
case IMM(0, 0):
if(l->complex > r->complex) {
t = regpair(Z, l);
sugen(l, t, 8);
l = t;
t = regpair(Z, r);
sugen(r, t, 8);
r = t;
}
else {
t = regpair(Z, r);
sugen(r, t, 8);
r = t;
t = regpair(Z, l);
sugen(l, t, 8);
l = t;
}
break;
case IMM(1, 0):
t = r;
r = l;
l = t;
ri = li;
op = invrel[relindex(op)];
/* fall thru */
case IMM(0, 1):
t = regpair(Z, l);
sugen(l, t, 8);
l = t;
break;
case IMM(1, 1):
break;
}
true = 1;
optab = cmptab;
switch(op) {
case OEQ:
optab = NEtab;
true = 0;
break;
case ONE:
optab = NEtab;
break;
case OLE:
args = GTargs;
true = 0;
break;
case OGT:
args = GTargs;
break;
case OLS:
args = HIargs;
true = 0;
break;
case OHI:
args = HIargs;
break;
case OLT:
args = GEargs;
true = 0;
break;
case OGE:
args = GEargs;
break;
case OLO:
args = HSargs;
true = 0;
break;
case OHS:
args = HSargs;
break;
default:
diag(n, "bad cmp\n");
SET(optab);
}
switch(lri) {
case IMM(0, 0):
biggen(l, r, Z, true, optab[T0i], args);
break;
case IMM(0, 1):
case IMM(1, 0):
switch(ri) {
case WNONE:
diag(l, "bad whatof\n");
break;
case WCONST:
biggen(l, r, Z, true, optab[T0i], args);
break;
case WHARD:
reglcgen(&nod2, r, Z);
r = &nod2;
/* fall thru */
case WADDR:
biggen(l, r, Z, true, optab[T0i], args);
if(ri == WHARD)
regfree(r);
break;
}
break;
case IMM(1, 1):
if(li == WHARD) {
reglcgen(&nod3, l, Z);
l = &nod3;
}
if(ri == WHARD) {
reglcgen(&nod2, r, Z);
r = &nod2;
}
biggen(l, r, Z, true, optab[Tii], args);
if(li == WHARD)
regfree(l);
if(ri == WHARD)
regfree(r);
break;
}
switch(lri) {
case IMM(0, 0):
freepair(r);
/* fall thru */;
case IMM(0, 1):
case IMM(1, 0):
freepair(l);
break;
case IMM(1, 1):
break;
}
return 1;
case OASMUL:
case OASLMUL:
m = 0;
goto mulop;
case OMUL:
case OLMUL:
m = 1;
goto mulop;
mulop:
dr = nn != Z && nn->op == OREGPAIR;
l = vfunc(n->left, nn);
r = vfunc(n->right, nn);
if(r->op != OCONST) {
if(l->complex > r->complex) {
if(m) {
t = l;
l = r;
r = t;
}
else if(!vaddr(l, 1)) {
reglcgen(&nod5, l, Z);
l = &nod5;
evacaxdx(l);
}
}
t = regpair(Z, n);
sugen(r, t, 8);
r = t;
evacaxdx(r->left);
evacaxdx(r->right);
if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
reglcgen(&nod5, l, Z);
l = &nod5;
evacaxdx(l);
}
}
if(dr)
t = nn;
else
t = regpair(Z, n);
c = Z;
d = Z;
if(!nodreg(&nod1, t->left, D_AX)) {
if(t->left->reg != D_AX){
t->left->reg = D_AX;
reg[D_AX]++;
}else if(reg[D_AX] == 0)
fatal(Z, "vlong mul AX botch");
}
if(!nodreg(&nod2, t->right, D_DX)) {
if(t->right->reg != D_DX){
t->right->reg = D_DX;
reg[D_DX]++;
}else if(reg[D_DX] == 0)
fatal(Z, "vlong mul DX botch");
}
if(m)
sugen(l, t, 8);
else
loadpair(l, t);
if(t->left->reg != D_AX) {
c = &nod3;
regsalloc(c, t->left);
gmove(&nod1, c);
gmove(t->left, &nod1);
zapreg(t->left);
}
if(t->right->reg != D_DX) {
d = &nod4;
regsalloc(d, t->right);
gmove(&nod2, d);
gmove(t->right, &nod2);
zapreg(t->right);
}
if(c != Z || d != Z) {
s = regpair(Z, n);
s->left = &nod1;
s->right = &nod2;
}
else
s = t;
if(r->op == OCONST) {
if(hi64v(r) == 0)
biggen(s, r, Z, 0, mulc32, nil);
else
biggen(s, r, Z, 0, mulc64, nil);
}
else
biggen(s, r, Z, 0, mull, nil);
instpair(t, Z);
if(c != Z) {
gmove(&nod1, t->left);
gmove(&nod3, &nod1);
}
if(d != Z) {
gmove(&nod2, t->right);
gmove(&nod4, &nod2);
}
if(r->op == OREGPAIR)
freepair(r);
if(!m)
storepair(t, l, 0);
if(l == &nod5)
regfree(l);
if(!dr) {
if(nn != Z)
storepair(t, nn, 1);
else
freepair(t);
}
return 1;
case OASADD:
args = ADDargs;
goto vasop;
case OASAND:
args = ANDargs;
goto vasop;
case OASOR:
args = ORargs;
goto vasop;
case OASSUB:
args = SUBargs;
goto vasop;
case OASXOR:
args = XORargs;
goto vasop;
vasop:
l = n->left;
r = n->right;
dr = nn != Z && nn->op == OREGPAIR;
m = 0;
if(l->complex > r->complex) {
if(!vaddr(l, 1)) {
reglcgen(&nod1, l, Z);
l = &nod1;
}
if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
if(dr)
t = nn;
else
t = regpair(Z, r);
sugen(r, t, 8);
r = t;
m = 1;
}
}
else {
if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
if(dr)
t = nn;
else
t = regpair(Z, r);
sugen(r, t, 8);
r = t;
m = 1;
}
if(!vaddr(l, 1)) {
reglcgen(&nod1, l, Z);
l = &nod1;
}
}
if(nn != Z) {
if(n->op == OASSUB)
biggen(l, r, Z, 0, sub10, args);
else
biggen(r, l, Z, 0, binoptmp, args);
storepair(r, l, 0);
}
else {
if(m)
biggen(l, r, Z, 0, binop00, args);
else
biggen(l, r, Z, 0, binoptmp, args);
}
if(l == &nod1)
regfree(&nod1);
if(m) {
if(nn == Z)
freepair(r);
else if(!dr)
storepair(r, nn, 1);
}
return 1;
case OASASHL:
args = nil;
optab = asshlltab;
goto assh;
case OASLSHR:
args = shrlargs;
optab = asshrltab;
goto assh;
case OASASHR:
args = sarlargs;
optab = asshrltab;
goto assh;
assh:
c = Z;
l = n->left;
r = n->right;
if(r->op == OCONST) {
m = r->vconst & 63;
if(m < 32)
m = SAclo;
else if(m == 32)
m = SAc32;
else
m = SAchi;
}
else
m = SAgen;
if(l->complex > r->complex) {
if(!vaddr(l, 0)) {
reglcgen(&nod1, l, Z);
l = &nod1;
}
if(m == SAgen) {
t = &nod2;
if(l->reg == D_CX) {
regalloc(t, r, Z);
gmove(l, t);
l->reg = t->reg;
t->reg = D_CX;
}
else
c = snarfreg(nn, t, D_CX, r, &nod3);
cgen(r, t);
r = t;
}
}
else {
if(m == SAgen) {
t = &nod2;
c = snarfreg(nn, t, D_CX, r, &nod3);
cgen(r, t);
r = t;
}
if(!vaddr(l, 0)) {
reglcgen(&nod1, l, Z);
l = &nod1;
}
}
if(nn != Z) {
m += SAdgen - SAgen;
d = regpair(nn, n);
instpair(d, Z);
biggen(l, r, d, 0, optab[m], args);
if(l == &nod1) {
regfree(&nod1);
l = Z;
}
if(r == &nod2 && c == Z) {
regfree(&nod2);
r = Z;
}
if(d != nn)
storepair(d, nn, 1);
}
else
biggen(l, r, Z, 0, optab[m], args);
if(c != Z) {
gins(AMOVL, c, r);
regfree(c);
}
if(l == &nod1)
regfree(&nod1);
if(r == &nod2)
regfree(&nod2);
return 1;
case OPOSTINC:
args = ADDargs;
cp = incdecpost;
goto vinc;
case OPOSTDEC:
args = SUBargs;
cp = incdecpost;
goto vinc;
case OPREINC:
args = ADDargs;
cp = incdecpre;
goto vinc;
case OPREDEC:
args = SUBargs;
cp = incdecpre;
goto vinc;
vinc:
l = n->left;
if(!vaddr(l, 1)) {
reglcgen(&nod1, l, Z);
l = &nod1;
}
if(nn != Z) {
d = regpair(nn, n);
instpair(d, Z);
biggen(l, Z, d, 0, cp, args);
if(l == &nod1) {
regfree(&nod1);
l = Z;
}
if(d != nn)
storepair(d, nn, 1);
}
else
biggen(l, Z, Z, 0, incdec, args);
if(l == &nod1)
regfree(&nod1);
return 1;
case OCAST:
l = n->left;
if(typev[l->type->etype]) {
if(!vaddr(l, 1)) {
if(l->complex + 1 > nn->complex) {
d = regpair(Z, l);
sugen(l, d, 8);
if(!vaddr(nn, 1)) {
reglcgen(&nod1, nn, Z);
r = &nod1;
}
else
r = nn;
}
else {
if(!vaddr(nn, 1)) {
reglcgen(&nod1, nn, Z);
r = &nod1;
}
else
r = nn;
d = regpair(Z, l);
sugen(l, d, 8);
}
// d->left->type = r->type;
d->left->type = types[TLONG];
gmove(d->left, r);
freepair(d);
}
else {
if(nn->op != OREGISTER && !vaddr(nn, 1)) {
reglcgen(&nod1, nn, Z);
r = &nod1;
}
else
r = nn;
// l->type = r->type;
l->type = types[TLONG];
gmove(l, r);
}
if(r != nn)
regfree(r);
}
else {
if(typeu[l->type->etype] || cond(l->op))
si = TUNSIGNED;
else
si = TSIGNED;
regalloc(&nod1, l, Z);
cgen(l, &nod1);
if(nn->op == OREGPAIR) {
m = instpair(nn, &nod1);
biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
}
else {
m = 0;
if(!vaddr(nn, si != TSIGNED)) {
dt = nn->type;
nn->type = types[TLONG];
reglcgen(&nod2, nn, Z);
nn->type = dt;
nn = &nod2;
}
dt = nn->type;
nn->type = types[TLONG];
biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
nn->type = dt;
if(nn == &nod2)
regfree(&nod2);
}
if(!m)
regfree(&nod1);
}
return 1;
default:
if(n->op == OREGPAIR) {
storepair(n, nn, 1);
return 1;
}
if(nn->op == OREGPAIR) {
loadpair(n, nn);
return 1;
}
return 0;
}
finished:
if(d != nn)
storepair(d, nn, 1);
return 1;
}
void
testv(Node *n, int true)
{
Type *t;
Node *nn, nod;
switch(n->op) {
case OINDREG:
case ONAME:
biggen(n, Z, Z, true, testi, nil);
break;
default:
n = vfunc(n, n);
if(n->addable >= INDEXED) {
t = n->type;
n->type = types[TLONG];
reglcgen(&nod, n, Z);
n->type = t;
n = &nod;
biggen(n, Z, Z, true, testi, nil);
if(n == &nod)
regfree(n);
}
else {
nn = regpair(Z, n);
sugen(n, nn, 8);
biggen(nn, Z, Z, true, testi, nil);
freepair(nn);
}
}
}
// Inferno utils/8c/div.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.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 "gc.h"
/*
* Based on: Granlund, T.; Montgomery, P.L.
* "Division by Invariant Integers using Multiplication".
* SIGPLAN Notices, Vol. 29, June 1994, page 61.
*/
#define TN(n) ((uvlong)1 << (n))
#define T31 TN(31)
#define T32 TN(32)
int
multiplier(ulong d, int p, uvlong *mp)
{
int l;
uvlong mlo, mhi, tlo, thi;
l = topbit(d - 1) + 1;
mlo = (((TN(l) - d) << 32) / d) + T32;
if(l + p == 64)
mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
else
mhi = (TN(32 + l) + TN(32 + l - p)) / d;
/*assert(mlo < mhi);*/
while(l > 0) {
tlo = mlo >> 1;
thi = mhi >> 1;
if(tlo == thi)
break;
mlo = tlo;
mhi = thi;
l--;
}
*mp = mhi;
return l;
}
int
sdiv(ulong d, ulong *mp, int *sp)
{
int s;
uvlong m;
s = multiplier(d, 32 - 1, &m);
*mp = m;
*sp = s;
if(m >= T31)
return 1;
else
return 0;
}
int
udiv(ulong d, ulong *mp, int *sp, int *pp)
{
int p, s;
uvlong m;
s = multiplier(d, 32, &m);
p = 0;
if(m >= T32) {
while((d & 1) == 0) {
d >>= 1;
p++;
}
s = multiplier(d, 32 - p, &m);
}
*mp = m;
*pp = p;
if(m >= T32) {
/*assert(p == 0);*/
*sp = s - 1;
return 1;
}
else {
*sp = s;
return 0;
}
}
void
sdivgen(Node *l, Node *r, Node *ax, Node *dx)
{
int a, s;
ulong m;
vlong c;
c = r->vconst;
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
if(a)
gins(AADDL, ax, dx);
gins(ASHRL, nodconst(31), ax);
gins(ASARL, nodconst(s), dx);
gins(AADDL, ax, dx);
if(r->vconst < 0)
gins(ANEGL, Z, dx);
}
void
udivgen(Node *l, Node *r, Node *ax, Node *dx)
{
int a, s, t;
ulong m;
Node nod;
a = udiv(r->vconst, &m, &s, &t);
//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
gins(AMOVL, nodconst(m), dx);
gins(AMULL, dx, Z);
}
else if(a) {
if(l->op != OREGISTER) {
regalloc(&nod, l, Z);
gins(AMOVL, l, &nod);
l = &nod;
}
gins(AMOVL, nodconst(m), ax);
gins(AMULL, l, Z);
gins(AADDL, l, dx);
gins(ARCRL, nodconst(1), dx);
if(l == &nod)
regfree(l);
}
else {
gins(AMOVL, nodconst(m), ax);
gins(AMULL, l, Z);
}
if(s != 0)
gins(ASHRL, nodconst(s), dx);
}
void
sext(Node *d, Node *s, Node *l)
{
if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
reg[D_DX]++;
gins(ACDQ, Z, Z);
}
else {
regalloc(d, l, Z);
gins(AMOVL, s, d);
gins(ASARL, nodconst(31), d);
}
}
void
sdiv2(long c, int v, Node *l, Node *n)
{
Node nod;
if(v > 0) {
if(v > 1) {
sext(&nod, n, l);
gins(AANDL, nodconst((1 << v) - 1), &nod);
gins(AADDL, &nod, n);
regfree(&nod);
}
else {
gins(ACMPL, n, nodconst(0x80000000));
gins(ASBBL, nodconst(-1), n);
}
gins(ASARL, nodconst(v), n);
}
if(c < 0)
gins(ANEGL, Z, n);
}
void
smod2(long c, int v, Node *l, Node *n)
{
Node nod;
if(c == 1) {
zeroregm(n);
return;
}
sext(&nod, n, l);
if(v == 0) {
zeroregm(n);
gins(AXORL, &nod, n);
gins(ASUBL, &nod, n);
}
else if(v > 1) {
gins(AANDL, nodconst((1 << v) - 1), &nod);
gins(AADDL, &nod, n);
gins(AANDL, nodconst((1 << v) - 1), n);
gins(ASUBL, &nod, n);
}
else {
gins(AANDL, nodconst(1), n);
gins(AXORL, &nod, n);
gins(ASUBL, &nod, n);
}
regfree(&nod);
}
// Inferno utils/8c/gc.h
// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "../cc/cc.h"
#include "../8c/8.out.h"
/*
* 8c/386
* Intel 386
*/
#define SZ_CHAR 1
#define SZ_SHORT 2
#define SZ_INT 4
#define SZ_LONG 4
#define SZ_IND 4
#define SZ_FLOAT 4
#define SZ_VLONG 8
#define SZ_DOUBLE 8
#define FNX 100
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Case Case;
typedef struct C1 C1;
typedef struct Var Var;
typedef struct Reg Reg;
typedef struct Rgn Rgn;
typedef struct Renv Renv;
EXTERN struct
{
Node* regtree;
Node* basetree;
short scale;
short reg;
short ptr;
} idx;
struct Adr
{
long offset;
double dval;
char sval[NSNAME];
Sym* sym;
uchar type;
uchar index;
uchar etype;
uchar scale; /* doubles as width in DATA op */
};
#define A ((Adr*)0)
#define INDEXED 9
struct Prog
{
Adr from;
Adr to;
Prog* link;
long lineno;
short as;
};
#define P ((Prog*)0)
struct Case
{
Case* link;
long val;
long label;
char def;
};
#define C ((Case*)0)
struct C1
{
long val;
long label;
};
struct Var
{
long offset;
Sym* sym;
char name;
char etype;
};
struct Reg
{
long pc;
long rpo; /* reverse post ordering */
Bits set;
Bits use1;
Bits use2;
Bits refbehind;
Bits refahead;
Bits calbehind;
Bits calahead;
Bits regdiff;
Bits act;
long regu;
long loop; /* could be shorter */
Reg* log5;
long active;
Reg* p1;
Reg* p2;
Reg* p2link;
Reg* s1;
Reg* s2;
Reg* link;
Prog* prog;
};
#define R ((Reg*)0)
struct Renv
{
int safe;
Node base;
Node* saved;
Node* scope;
};
#define NRGN 600
struct Rgn
{
Reg* enter;
short cost;
short varno;
short regno;
};
EXTERN long breakpc;
EXTERN Case* cases;
EXTERN Node constnode;
EXTERN Node fconstnode;
EXTERN long continpc;
EXTERN long curarg;
EXTERN long cursafe;
EXTERN Prog* firstp;
EXTERN Prog* lastp;
EXTERN long maxargsafe;
EXTERN int mnstring;
EXTERN int retok;
EXTERN Node* nodrat;
EXTERN Node* nodret;
EXTERN Node* nodsafe;
EXTERN long nrathole;
EXTERN long nstring;
EXTERN Prog* p;
EXTERN long pc;
EXTERN Node regnode;
EXTERN Node fregnode0;
EXTERN Node fregnode1;
EXTERN char string[NSNAME];
EXTERN Sym* symrathole;
EXTERN Node znode;
EXTERN Prog zprog;
EXTERN int reg[D_NONE];
EXTERN long exregoffset;
EXTERN long exfregoffset;
#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
#define CLOAD 5
#define CREF 5
#define CINF 1000
#define LOOP 3
EXTERN Rgn region[NRGN];
EXTERN Rgn* rgp;
EXTERN int nregion;
EXTERN int nvar;
EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
EXTERN long regbits;
EXTERN long exregbits;
EXTERN int change;
EXTERN int suppress;
EXTERN Reg* firstr;
EXTERN Reg* lastr;
EXTERN Reg zreg;
EXTERN Reg* freer;
EXTERN Var var[NVAR];
EXTERN long* idom;
EXTERN Reg** rpo2r;
EXTERN long maxnr;
extern char* anames[];
/*
* sgen.c
*/
void codgen(Node*, Node*);
void gen(Node*);
void noretval(int);
void usedset(Node*, int);
void xcom(Node*);
void indx(Node*);
int bcomplex(Node*, Node*);
/*
* cgen.c
*/
void zeroregm(Node*);
void cgen(Node*, Node*);
void reglcgen(Node*, Node*, Node*);
void lcgen(Node*, Node*);
void bcgen(Node*, int);
void boolgen(Node*, int, Node*);
void sugen(Node*, Node*, long);
int needreg(Node*, int);
/*
* cgen64.c
*/
int vaddr(Node*, int);
void loadpair(Node*, Node*);
int cgen64(Node*, Node*);
void testv(Node*, int);
/*
* txt.c
*/
void ginit(void);
void gclean(void);
void nextpc(void);
void gargs(Node*, Node*, Node*);
void garg1(Node*, Node*, Node*, int, Node**);
Node* nodconst(long);
Node* nodfconst(double);
int nodreg(Node*, Node*, int);
int isreg(Node*, int);
void regret(Node*, Node*);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
void regialloc(Node*, Node*, Node*);
void regsalloc(Node*, Node*);
void regaalloc1(Node*, Node*);
void regaalloc(Node*, Node*);
void regind(Node*, Node*);
void gprep(Node*, Node*);
void naddr(Node*, Adr*);
void gmove(Node*, Node*);
void gins(int a, Node*, Node*);
void fgopcode(int, Node*, Node*, int, int);
void gopcode(int, Type*, Node*, Node*);
int samaddr(Node*, Node*);
void gbranch(int);
void patch(Prog*, long);
int sconst(Node*);
void gpseudo(int, Sym*, Node*);
/*
* swt.c
*/
int swcmp(const void*, const void*);
void doswit(Node*);
void swit1(C1*, int, long, Node*);
void cas(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
long outstring(char*, long);
void nullwarn(Node*, Node*);
void sextern(Sym*, Node*, long, long);
void gextern(Sym*, Node*, long, long);
void outcode(void);
void ieeedtod(Ieee*, double);
/*
* list
*/
void listinit(void);
int Pconv(Fmt*);
int Aconv(Fmt*);
int Dconv(Fmt*);
int Sconv(Fmt*);
int Rconv(Fmt*);
int Xconv(Fmt*);
int Bconv(Fmt*);
/*
* reg.c
*/
Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
Bits mkvar(Reg*, Adr*);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, long);
void synch(Reg*, Bits);
ulong allreg(ulong, Rgn*);
void paint1(Reg*, int);
ulong paint2(Reg*, int);
void paint3(Reg*, int, long, int);
void addreg(Adr*, int);
/*
* peep.c
*/
void peep(void);
void excise(Reg*);
Reg* uniqp(Reg*);
Reg* uniqs(Reg*);
int regtyp(Adr*);
int anyvar(Adr*);
int subprop(Reg*);
int copyprop(Reg*);
int copy1(Adr*, Adr*, Reg*, int);
int copyu(Prog*, Adr*, Adr*);
int copyas(Adr*, Adr*);
int copyau(Adr*, Adr*);
int copysub(Adr*, Adr*, Adr*, int);
int copysub1(Prog*, Adr*, Adr*, int);
long RtoB(int);
long FtoB(int);
int BtoR(long);
int BtoF(long);
#define D_HI D_NONE
#define D_LO D_NONE
/*
* bound
*/
void comtarg(void);
/*
* com64
*/
int cond(int);
int com64(Node*);
void com64init(void);
void bool64(Node*);
long lo64v(Node*);
long hi64v(Node*);
Node* lo64(Node*);
Node* hi64(Node*);
/*
* div/mul
*/
void sdivgen(Node*, Node*, Node*, Node*);
void udivgen(Node*, Node*, Node*, Node*);
void sdiv2(long, int, Node*, Node*);
void smod2(long, int, Node*, Node*);
void mulgen(Type*, Node*, Node*);
void genmuladd(Node*, Node*, int, Node*);
void shiftit(Type*, Node*, Node*);
#pragma varargck type "A" int
#pragma varargck type "B" Bits
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
/* wrecklessly steal a field */
#define rplink label
// Inferno utils/8c/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define EXTERN
#include "gc.h"
void
listinit(void)
{
fmtinstall('A', Aconv);
fmtinstall('B', Bconv);
fmtinstall('P', Pconv);
fmtinstall('S', Sconv);
fmtinstall('D', Dconv);
fmtinstall('R', Rconv);
}
int
Bconv(Fmt *fp)
{
char str[STRINGSZ], ss[STRINGSZ], *s;
Bits bits;
int i;
str[0] = 0;
bits = va_arg(fp->args, Bits);
while(bany(&bits)) {
i = bnum(bits);
if(str[0])
strcat(str, " ");
if(var[i].sym == S) {
sprint(ss, "$%ld", var[i].offset);
s = ss;
} else
s = var[i].sym->name;
if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
break;
strcat(str, s);
bits.b[i/32] &= ~(1L << (i%32));
}
return fmtstrcpy(fp, str);
}
int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
if(p->as == ADATA)
sprint(str, " %A %D/%d,%D",
p->as, &p->from, p->from.scale, &p->to);
else if(p->as == ATEXT)
sprint(str, " %A %D,%d,%D",
p->as, &p->from, p->from.scale, &p->to);
else
sprint(str, " %A %D,%D",
p->as, &p->from, &p->to);
return fmtstrcpy(fp, str);
}
int
Aconv(Fmt *fp)
{
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
}
int
Dconv(Fmt *fp)
{
char str[40], s[20];
Adr *a;
int i;
a = va_arg(fp->args, Adr*);
i = a->type;
if(i >= D_INDIR) {
if(a->offset)
sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
else
sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
if(a->offset)
sprint(str, "$%ld,%R", a->offset, i);
else
sprint(str, "%R", i);
break;
case D_NONE:
str[0] = 0;
break;
case D_BRANCH:
sprint(str, "%ld(PC)", a->offset-pc);
break;
case D_EXTERN:
sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
break;
case D_STATIC:
sprint(str, "%s<>+%ld(SB)", a->sym->name,
a->offset);
break;
case D_AUTO:
sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
break;
case D_PARAM:
if(a->sym)
sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
else
sprint(str, "%ld(FP)", a->offset);
break;
case D_CONST:
sprint(str, "$%ld", a->offset);
break;
case D_FCONST:
sprint(str, "$(%.17e)", a->dval);
break;
case D_SCONST:
sprint(str, "$\"%S\"", a->sval);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
strcat(str, s);
}
conv:
return fmtstrcpy(fp, str);
}
char* regstr[] =
{
"AL", /*[D_AL]*/
"CL",
"DL",
"BL",
"AH",
"CH",
"DH",
"BH",
"AX", /*[D_AX]*/
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"F0", /*[D_F0]*/
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"CS", /*[D_CS]*/
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", /*[D_GDTR]*/
"IDTR", /*[D_IDTR]*/
"LDTR", /*[D_LDTR]*/
"MSW", /*[D_MSW] */
"TASK", /*[D_TASK]*/
"CR0", /*[D_CR]*/
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"DR0", /*[D_DR]*/
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", /*[D_TR]*/
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"NONE", /*[D_NONE]*/
};
int
Rconv(Fmt *fp)
{
char str[20];
int r;
r = va_arg(fp->args, int);
if(r >= D_AL && r <= D_NONE)
sprint(str, "%s", regstr[r-D_AL]);
else
sprint(str, "gok(%d)", r);
return fmtstrcpy(fp, str);
}
int
Sconv(Fmt *fp)
{
int i, c;
char str[30], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
default:
if(c < 040 || c >= 0177)
break; /* not portable */
p[-1] = c;
continue;
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}
// Inferno utils/8c/machcap.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.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 "gc.h"
int
machcap(Node *n)
{
if(n == Z)
return 1; /* test */
switch(n->op) {
case OMUL:
case OLMUL:
case OASMUL:
case OASLMUL:
if(typechl[n->type->etype])
return 1;
if(typev[n->type->etype]) {
return 1;
}
break;
case OCOM:
case ONEG:
case OADD:
case OAND:
case OOR:
case OSUB:
case OXOR:
case OASHL:
case OLSHR:
case OASHR:
if(typechlv[n->left->type->etype])
return 1;
break;
case OCAST:
if(typev[n->type->etype]) {
if(typechlp[n->left->type->etype])
return 1;
}
else if(!typefd[n->type->etype]) {
if(typev[n->left->type->etype])
return 1;
}
break;
case OCOND:
case OCOMMA:
case OLIST:
case OANDAND:
case OOROR:
case ONOT:
return 1;
case OASADD:
case OASSUB:
case OASAND:
case OASOR:
case OASXOR:
return 1;
case OASASHL:
case OASASHR:
case OASLSHR:
return 1;
case OPOSTINC:
case OPOSTDEC:
case OPREINC:
case OPREDEC:
return 1;
case OEQ:
case ONE:
case OLE:
case OGT:
case OLT:
case OGE:
case OHI:
case OHS:
case OLO:
case OLS:
return 1;
}
return 0;
}
# Inferno utils/8c/mkenam
# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam
#
# 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.
ed - ../8c/8.out.h <<'!'
v/^ A/d
,s/^ A/ "/
g/ .*$/s///
,s/,*$/",/
1i
char* anames[] =
{
.
$a
};
.
w enam.c
Q
!
// Inferno utils/8c/mul.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.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 "gc.h"
typedef struct Malg Malg;
typedef struct Mparam Mparam;
struct Malg
{
char vals[10];
};
struct Mparam
{
ulong value;
char alg;
char neg;
char shift;
char arg;
char off;
};
static Mparam multab[32];
static int mulptr;
static Malg malgs[] =
{
{0, 100},
{-1, 1, 100},
{-9, -5, -3, 3, 5, 9, 100},
{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
{-8, -4, -2, 2, 4, 8, 100},
};
/*
* return position of lowest 1
*/
int
lowbit(ulong v)
{
int s, i;
ulong m;
s = 0;
m = 0xFFFFFFFFUL;
for(i = 16; i > 0; i >>= 1) {
m >>= i;
if((v & m) == 0) {
v >>= i;
s += i;
}
}
return s;
}
void
genmuladd(Node *d, Node *s, int m, Node *a)
{
Node nod;
nod.op = OINDEX;
nod.left = a;
nod.right = s;
nod.scale = m;
nod.type = types[TIND];
nod.xoffset = 0;
xcom(&nod);
gopcode(OADDR, d->type, &nod, d);
}
void
mulparam(ulong m, Mparam *mp)
{
int c, i, j, n, o, q, s;
int bc, bi, bn, bo, bq, bs, bt;
char *p;
long u;
ulong t;
bc = bq = 10;
bi = bn = bo = bs = bt = 0;
for(i = 0; i < nelem(malgs); i++) {
for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
for(s = 0; s < 2; s++) {
c = 10;
q = 10;
u = m - o;
if(u == 0)
continue;
if(s) {
o = -o;
if(o > 0)
continue;
u = -u;
}
n = lowbit(u);
t = (ulong)u >> n;
switch(i) {
case 0:
if(t == 1) {
c = s + 1;
q = 0;
break;
}
switch(t) {
case 3:
case 5:
case 9:
c = s + 1;
if(n)
c++;
q = 0;
break;
}
if(s)
break;
switch(t) {
case 15:
case 25:
case 27:
case 45:
case 81:
c = 2;
if(n)
c++;
q = 1;
break;
}
break;
case 1:
if(t == 1) {
c = 3;
q = 3;
break;
}
switch(t) {
case 3:
case 5:
case 9:
c = 3;
q = 2;
break;
}
break;
case 2:
if(t == 1) {
c = 3;
q = 2;
break;
}
break;
case 3:
if(s)
break;
if(t == 1) {
c = 3;
q = 1;
break;
}
break;
case 4:
if(t == 1) {
c = 3;
q = 0;
break;
}
break;
}
if(c < bc || (c == bc && q > bq)) {
bc = c;
bi = i;
bn = n;
bo = o;
bq = q;
bs = s;
bt = t;
}
}
}
mp->value = m;
if(bc <= 3) {
mp->alg = bi;
mp->shift = bn;
mp->off = bo;
mp->neg = bs;
mp->arg = bt;
}
else
mp->alg = -1;
}
int
m0(int a)
{
switch(a) {
case -2:
case 2:
return 2;
case -3:
case 3:
return 2;
case -4:
case 4:
return 4;
case -5:
case 5:
return 4;
case 6:
return 2;
case -8:
case 8:
return 8;
case -9:
case 9:
return 8;
case 10:
return 4;
case 12:
return 2;
case 15:
return 2;
case 18:
return 8;
case 20:
return 4;
case 24:
return 2;
case 25:
return 4;
case 27:
return 2;
case 36:
return 8;
case 40:
return 4;
case 45:
return 4;
case 72:
return 8;
case 81:
return 8;
}
diag(Z, "bad m0");
return 0;
}
int
m1(int a)
{
switch(a) {
case 15:
return 4;
case 25:
return 4;
case 27:
return 8;
case 45:
return 8;
case 81:
return 8;
}
diag(Z, "bad m1");
return 0;
}
int
m2(int a)
{
switch(a) {
case 6:
return 2;
case 10:
return 2;
case 12:
return 4;
case 18:
return 2;
case 20:
return 4;
case 24:
return 8;
case 36:
return 4;
case 40:
return 8;
case 72:
return 8;
}
diag(Z, "bad m2");
return 0;
}
void
shiftit(Type *t, Node *s, Node *d)
{
long c;
c = (long)s->vconst & 31;
switch(c) {
case 0:
break;
case 1:
gopcode(OADD, t, d, d);
break;
default:
gopcode(OASHL, t, s, d);
}
}
static int
mulgen1(ulong v, Node *n)
{
int i, o;
Mparam *p;
Node nod, nods;
for(i = 0; i < nelem(multab); i++) {
p = &multab[i];
if(p->value == v)
goto found;
}
p = &multab[mulptr];
if(++mulptr == nelem(multab))
mulptr = 0;
mulparam(v, p);
found:
// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
nods = *nodconst(p->shift);
o = OADD;
if(p->alg > 0) {
regalloc(&nod, n, Z);
if(p->off < 0)
o = OSUB;
}
switch(p->alg) {
case 0:
switch(p->arg) {
case 1:
shiftit(n->type, &nods, n);
break;
case 15:
case 25:
case 27:
case 45:
case 81:
genmuladd(n, n, m1(p->arg), n);
/* fall thru */
case 3:
case 5:
case 9:
genmuladd(n, n, m0(p->arg), n);
shiftit(n->type, &nods, n);
break;
default:
goto bad;
}
if(p->neg == 1)
gins(ANEGL, Z, n);
break;
case 1:
switch(p->arg) {
case 1:
gmove(n, &nod);
shiftit(n->type, &nods, &nod);
break;
case 3:
case 5:
case 9:
genmuladd(&nod, n, m0(p->arg), n);
shiftit(n->type, &nods, &nod);
break;
default:
goto bad;
}
if(p->neg)
gopcode(o, n->type, &nod, n);
else {
gopcode(o, n->type, n, &nod);
gmove(&nod, n);
}
break;
case 2:
genmuladd(&nod, n, m0(p->off), n);
shiftit(n->type, &nods, n);
goto comop;
case 3:
genmuladd(&nod, n, m0(p->off), n);
shiftit(n->type, &nods, n);
genmuladd(n, &nod, m2(p->off), n);
break;
case 4:
genmuladd(&nod, n, m0(p->off), nodconst(0));
shiftit(n->type, &nods, n);
goto comop;
default:
diag(Z, "bad mul alg");
break;
comop:
if(p->neg) {
gopcode(o, n->type, n, &nod);
gmove(&nod, n);
}
else
gopcode(o, n->type, &nod, n);
}
if(p->alg > 0)
regfree(&nod);
return 1;
bad:
diag(Z, "mulgen botch");
return 1;
}
void
mulgen(Type *t, Node *r, Node *n)
{
if(!mulgen1(r->vconst, n))
gopcode(OMUL, t, r, n);
}
// Inferno utils/8c/peep.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "gc.h"
static int
needc(Prog *p)
{
while(p != P) {
switch(p->as) {
case AADCL:
case ASBBL:
case ARCRL:
return 1;
case AADDL:
case ASUBL:
case AJMP:
case ARET:
case ACALL:
return 0;
default:
if(p->to.type == D_BRANCH)
return 0;
}
p = p->link;
}
return 0;
}
void
peep(void)
{
Reg *r, *r1, *r2;
Prog *p, *p1;
int t;
/*
* complete R structure
*/
t = 0;
for(r=firstr; r!=R; r=r1) {
r1 = r->link;
if(r1 == R)
break;
p = r->prog->link;
while(p != r1->prog)
switch(p->as) {
default:
r2 = rega();
r->link = r2;
r2->link = r1;
r2->prog = p;
r2->p1 = r;
r->s1 = r2;
r2->s1 = r1;
r1->p1 = r2;
r = r2;
t++;
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
p = p->link;
}
}
pc = 0; /* speculating it won't kill */
loop1:
t = 0;
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
switch(p->as) {
case AMOVL:
if(regtyp(&p->to))
if(regtyp(&p->from)) {
if(copyprop(r)) {
excise(r);
t++;
}
if(subprop(r) && copyprop(r)) {
excise(r);
t++;
}
}
break;
case AMOVBLSX:
case AMOVBLZX:
case AMOVWLSX:
case AMOVWLZX:
if(regtyp(&p->to)) {
r1 = uniqs(r);
if(r1 != R) {
p1 = r1->prog;
if(p->as == p1->as && p->to.type == p1->from.type)
p1->as = AMOVL;
}
}
break;
case AADDL:
case AADDW:
if(p->from.type != D_CONST || needc(p->link))
break;
if(p->from.offset == -1){
if(p->as == AADDL)
p->as = ADECL;
else
p->as = ADECW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
if(p->as == AADDL)
p->as = AINCL;
else
p->as = AINCW;
p->from = zprog.from;
}
break;
case ASUBL:
case ASUBW:
if(p->from.type != D_CONST || needc(p->link))
break;
if(p->from.offset == -1) {
if(p->as == ASUBL)
p->as = AINCL;
else
p->as = AINCW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
if(p->as == ASUBL)
p->as = ADECL;
else
p->as = ADECW;
p->from = zprog.from;
}
break;
}
}
if(t)
goto loop1;
}
void
excise(Reg *r)
{
Prog *p;
p = r->prog;
p->as = ANOP;
p->from = zprog.from;
p->to = zprog.to;
}
Reg*
uniqp(Reg *r)
{
Reg *r1;
r1 = r->p1;
if(r1 == R) {
r1 = r->p2;
if(r1 == R || r1->p2link != R)
return R;
} else
if(r->p2 != R)
return R;
return r1;
}
Reg*
uniqs(Reg *r)
{
Reg *r1;
r1 = r->s1;
if(r1 == R) {
r1 = r->s2;
if(r1 == R)
return R;
} else
if(r->s2 != R)
return R;
return r1;
}
int
regtyp(Adr *a)
{
int t;
t = a->type;
if(t >= D_AX && t <= D_DI)
return 1;
return 0;
}
/*
* the idea is to substitute
* one register for another
* from one MOV to another
* MOV a, R0
* ADD b, R0 / no use of R1
* MOV R0, R1
* would be converted to
* MOV a, R1
* ADD b, R1
* MOV R1, R0
* hopefully, then the former or latter MOV
* will be eliminated by copy propagation.
*/
int
subprop(Reg *r0)
{
Prog *p;
Adr *v1, *v2;
Reg *r;
int t;
p = r0->prog;
v1 = &p->from;
if(!regtyp(v1))
return 0;
v2 = &p->to;
if(!regtyp(v2))
return 0;
for(r=uniqp(r0); r!=R; r=uniqp(r)) {
if(uniqs(r) == R)
break;
p = r->prog;
switch(p->as) {
case ACALL:
return 0;
case AIMULL:
case AIMULW:
if(p->to.type != D_NONE)
break;
case ADIVB:
case ADIVL:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULW:
case AROLB:
case AROLL:
case AROLW:
case ARORB:
case ARORL:
case ARORW:
case ASALB:
case ASALL:
case ASALW:
case ASARB:
case ASARL:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRW:
case AREP:
case AREPN:
case ACWD:
case ACDQ:
case AMOVSL:
case AFSTSW:
return 0;
case AMOVL:
if(p->to.type == v1->type)
goto gotit;
break;
}
if(copyau(&p->from, v2) ||
copyau(&p->to, v2))
break;
if(copysub(&p->from, v1, v2, 0) ||
copysub(&p->to, v1, v2, 0))
break;
}
return 0;
gotit:
copysub(&p->to, v1, v2, 1);
if(debug['P']) {
print("gotit: %D->%D\n%P", v1, v2, r->prog);
if(p->from.type == v2->type)
print(" excise");
print("\n");
}
for(r=uniqs(r); r!=r0; r=uniqs(r)) {
p = r->prog;
copysub(&p->from, v1, v2, 1);
copysub(&p->to, v1, v2, 1);
if(debug['P'])
print("%P\n", r->prog);
}
t = v1->type;
v1->type = v2->type;
v2->type = t;
if(debug['P'])
print("%P last\n", r->prog);
return 1;
}
/*
* The idea is to remove redundant copies.
* v1->v2 F=0
* (use v2 s/v2/v1/)*
* set v1 F=1
* use v2 return fail
* -----------------
* v1->v2 F=0
* (use v2 s/v2/v1/)*
* set v1 F=1
* set v2 return success
*/
int
copyprop(Reg *r0)
{
Prog *p;
Adr *v1, *v2;
Reg *r;
p = r0->prog;
v1 = &p->from;
v2 = &p->to;
if(copyas(v1, v2))
return 1;
for(r=firstr; r!=R; r=r->link)
r->active = 0;
return copy1(v1, v2, r0->s1, 0);
}
int
copy1(Adr *v1, Adr *v2, Reg *r, int f)
{
int t;
Prog *p;
if(r->active) {
if(debug['P'])
print("act set; return 1\n");
return 1;
}
r->active = 1;
if(debug['P'])
print("copy %D->%D f=%d\n", v1, v2, f);
for(; r != R; r = r->s1) {
p = r->prog;
if(debug['P'])
print("%P", p);
if(!f && uniqp(r) == R) {
f = 1;
if(debug['P'])
print("; merge; f=%d", f);
}
t = copyu(p, v2, A);
switch(t) {
case 2: /* rar, cant split */
if(debug['P'])
print("; %D rar; return 0\n", v2);
return 0;
case 3: /* set */
if(debug['P'])
print("; %D set; return 1\n", v2);
return 1;
case 1: /* used, substitute */
case 4: /* use and set */
if(f) {
if(!debug['P'])
return 0;
if(t == 4)
print("; %D used+set and f=%d; return 0\n", v2, f);
else
print("; %D used and f=%d; return 0\n", v2, f);
return 0;
}
if(copyu(p, v2, v1)) {
if(debug['P'])
print("; sub fail; return 0\n");
return 0;
}
if(debug['P'])
print("; sub %D/%D", v2, v1);
if(t == 4) {
if(debug['P'])
print("; %D used+set; return 1\n", v2);
return 1;
}
break;
}
if(!f) {
t = copyu(p, v1, A);
if(!f && (t == 2 || t == 3 || t == 4)) {
f = 1;
if(debug['P'])
print("; %D set and !f; f=%d", v1, f);
}
}
if(debug['P'])
print("\n");
if(r->s2)
if(!copy1(v1, v2, r->s2, f))
return 0;
}
return 1;
}
/*
* return
* 1 if v only used (and substitute),
* 2 if read-alter-rewrite
* 3 if set
* 4 if set and used
* 0 otherwise (not touched)
*/
int
copyu(Prog *p, Adr *v, Adr *s)
{
switch(p->as) {
default:
if(debug['P'])
print("unknown op %A\n", p->as);
return 2;
case ANEGB:
case ANEGW:
case ANEGL:
case ANOTB:
case ANOTW:
case ANOTL:
if(copyas(&p->to, v))
return 2;
break;
case ALEAL: /* lhs addr, rhs store */
if(copyas(&p->from, v))
return 2;
case ANOP: /* rhs store */
case AMOVL:
case AMOVBLSX:
case AMOVBLZX:
case AMOVWLSX:
case AMOVWLZX:
if(copyas(&p->to, v)) {
if(s != A)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
return 3;
}
goto caseread;
case AROLB:
case AROLL:
case AROLW:
case ARORB:
case ARORL:
case ARORW:
case ASALB:
case ASALL:
case ASALW:
case ASARB:
case ASARL:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRW:
if(copyas(&p->to, v))
return 2;
if(copyas(&p->from, v))
if(p->from.type == D_CX)
return 2;
goto caseread;
case AADDB: /* rhs rar */
case AADDL:
case AADDW:
case AANDB:
case AANDL:
case AANDW:
case ADECL:
case ADECW:
case AINCL:
case AINCW:
case ASUBB:
case ASUBL:
case ASUBW:
case AORB:
case AORL:
case AORW:
case AXORB:
case AXORL:
case AXORW:
case AMOVB:
case AMOVW:
case AFMOVB:
case AFMOVBP:
case AFMOVD:
case AFMOVDP:
case AFMOVF:
case AFMOVFP:
case AFMOVL:
case AFMOVLP:
case AFMOVV:
case AFMOVVP:
case AFMOVW:
case AFMOVWP:
case AFMOVX:
case AFMOVXP:
case AFADDDP:
case AFADDW:
case AFADDL:
case AFADDF:
case AFADDD:
case AFMULDP:
case AFMULW:
case AFMULL:
case AFMULF:
case AFMULD:
case AFSUBDP:
case AFSUBW:
case AFSUBL:
case AFSUBF:
case AFSUBD:
case AFSUBRDP:
case AFSUBRW:
case AFSUBRL:
case AFSUBRF:
case AFSUBRD:
case AFDIVDP:
case AFDIVW:
case AFDIVL:
case AFDIVF:
case AFDIVD:
case AFDIVRDP:
case AFDIVRW:
case AFDIVRL:
case AFDIVRF:
case AFDIVRD:
if(copyas(&p->to, v))
return 2;
goto caseread;
case ACMPL: /* read only */
case ACMPW:
case ACMPB:
case AFCOMB:
case AFCOMBP:
case AFCOMD:
case AFCOMDP:
case AFCOMDPP:
case AFCOMF:
case AFCOMFP:
case AFCOML:
case AFCOMLP:
case AFCOMW:
case AFCOMWP:
case AFUCOM:
case AFUCOMP:
case AFUCOMPP:
caseread:
if(s != A) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
}
if(copyau(&p->from, v))
return 1;
if(copyau(&p->to, v))
return 1;
break;
case AJGE: /* no reference */
case AJNE:
case AJLE:
case AJEQ:
case AJHI:
case AJLS:
case AJMI:
case AJPL:
case AJGT:
case AJLT:
case AJCC:
case AJCS:
case AADJSP:
case AFLDZ:
case AWAIT:
break;
case AIMULL:
case AIMULW:
if(p->to.type != D_NONE) {
if(copyas(&p->to, v))
return 2;
goto caseread;
}
case ADIVB:
case ADIVL:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULW:
case ACWD:
case ACDQ:
if(v->type == D_AX || v->type == D_DX)
return 2;
goto caseread;
case AMOVSL:
case AREP:
case AREPN:
if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
return 2;
goto caseread;
case AFSTSW:
if(v->type == D_AX)
return 2;
goto caseread;
case AJMP: /* funny */
if(s != A) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
}
if(copyau(&p->to, v))
return 1;
return 0;
case ARET: /* funny */
if(v->type == REGRET)
return 2;
if(s != A)
return 1;
return 3;
case ACALL: /* funny */
if(REGARG && v->type == REGARG)
return 2;
if(s != A) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
}
if(copyau(&p->to, v))
return 4;
return 3;
}
return 0;
}
/*
* direct reference,
* could be set/use depending on
* semantics
*/
int
copyas(Adr *a, Adr *v)
{
if(a->type != v->type)
return 0;
if(regtyp(v))
return 1;
if(v->type == D_AUTO || v->type == D_PARAM)
if(v->offset == a->offset)
return 1;
return 0;
}
/*
* either direct or indirect
*/
int
copyau(Adr *a, Adr *v)
{
if(copyas(a, v))
return 1;
if(regtyp(v)) {
if(a->type-D_INDIR == v->type)
return 1;
if(a->index == v->type)
return 1;
}
return 0;
}
/*
* substitute s for v in a
* return failure to substitute
*/
int
copysub(Adr *a, Adr *v, Adr *s, int f)
{
int t;
if(copyas(a, v)) {
t = s->type;
if(t >= D_AX && t <= D_DI) {
if(f)
a->type = t;
}
return 0;
}
if(regtyp(v)) {
t = v->type;
if(a->type == t+D_INDIR) {
if(s->type == D_BP && a->index != D_NONE)
return 1; /* can't use BP-base with index */
if(f)
a->type = s->type+D_INDIR;
// return 0;
}
if(a->index == t) {
if(f)
a->index = s->type;
return 0;
}
return 0;
}
return 0;
}
// Inferno utils/8c/reg.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "gc.h"
Reg*
rega(void)
{
Reg *r;
r = freer;
if(r == R) {
r = alloc(sizeof(*r));
} else
freer = r->link;
*r = zreg;
return r;
}
int
rcmp(const void *a1, const void *a2)
{
Rgn *p1, *p2;
int c1, c2;
p1 = (Rgn*)a1;
p2 = (Rgn*)a2;
c1 = p2->cost;
c2 = p1->cost;
if(c1 -= c2)
return c1;
return p2->varno - p1->varno;
}
void
regopt(Prog *p)
{
Reg *r, *r1, *r2;
Prog *p1;
int i, z;
long initpc, val, npc;
ulong vreg;
Bits bit;
struct
{
long m;
long c;
Reg* p;
} log5[6], *lp;
firstr = R;
lastr = R;
nvar = 0;
regbits = RtoB(D_SP) | RtoB(D_AX);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
params.b[z] = 0;
consts.b[z] = 0;
addrs.b[z] = 0;
}
/*
* pass 1
* build aux data structure
* allocate pcs
* find use and set of variables
*/
val = 5L * 5L * 5L * 5L * 5L;
lp = log5;
for(i=0; i<5; i++) {
lp->m = val;
lp->c = 0;
lp->p = R;
val /= 5L;
lp++;
}
val = 0;
for(; p != P; p = p->link) {
switch(p->as) {
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
continue;
}
r = rega();
if(firstr == R) {
firstr = r;
lastr = r;
} else {
lastr->link = r;
r->p1 = lastr;
lastr->s1 = r;
lastr = r;
}
r->prog = p;
r->pc = val;
val++;
lp = log5;
for(i=0; i<5; i++) {
lp->c--;
if(lp->c <= 0) {
lp->c = lp->m;
if(lp->p != R)
lp->p->log5 = r;
lp->p = r;
(lp+1)->c = 0;
break;
}
lp++;
}
r1 = r->p1;
if(r1 != R)
switch(r1->prog->as) {
case ARET:
case AJMP:
case AIRETL:
r->p1 = R;
r1->s1 = R;
}
bit = mkvar(r, &p->from);
if(bany(&bit))
switch(p->as) {
/*
* funny
*/
case ALEAL:
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
break;
/*
* left side read
*/
default:
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
break;
}
bit = mkvar(r, &p->to);
if(bany(&bit))
switch(p->as) {
default:
diag(Z, "reg: unknown op: %A", p->as);
break;
/*
* right side read
*/
case ACMPB:
case ACMPL:
case ACMPW:
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
break;
/*
* right side write
*/
case ANOP:
case AMOVL:
case AMOVB:
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
case AMOVWLSX:
case AMOVWLZX:
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
/*
* right side read+write
*/
case AADDB:
case AADDL:
case AADDW:
case AANDB:
case AANDL:
case AANDW:
case ASUBB:
case ASUBL:
case ASUBW:
case AORB:
case AORL:
case AORW:
case AXORB:
case AXORL:
case AXORW:
case ASALB:
case ASALL:
case ASALW:
case ASARB:
case ASARL:
case ASARW:
case AROLB:
case AROLL:
case AROLW:
case ARORB:
case ARORL:
case ARORW:
case ASHLB:
case ASHLL:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRW:
case AIMULL:
case AIMULW:
case ANEGL:
case ANOTL:
case AADCL:
case ASBBL:
for(z=0; z<BITS; z++) {
r->set.b[z] |= bit.b[z];
r->use2.b[z] |= bit.b[z];
}
break;
/*
* funny
*/
case AFMOVDP:
case AFMOVFP:
case AFMOVVP:
case ACALL:
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
break;
}
switch(p->as) {
case AIMULL:
case AIMULW:
if(p->to.type != D_NONE)
break;
case AIDIVB:
case AIDIVL:
case AIDIVW:
case AIMULB:
case ADIVB:
case ADIVL:
case ADIVW:
case AMULB:
case AMULL:
case AMULW:
case ACWD:
case ACDQ:
r->regu |= RtoB(D_AX) | RtoB(D_DX);
break;
case AREP:
case AREPN:
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
r->regu |= RtoB(D_CX);
break;
case AMOVSB:
case AMOVSL:
case AMOVSW:
case ACMPSB:
case ACMPSL:
case ACMPSW:
r->regu |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
case ASTOSL:
case ASTOSW:
case ASCASB:
case ASCASL:
case ASCASW:
r->regu |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
case AOUTSB:
case AOUTSL:
case AOUTSW:
r->regu |= RtoB(D_DI) | RtoB(D_DX);
break;
case AFSTSW:
case ASAHF:
r->regu |= RtoB(D_AX);
break;
}
}
if(firstr == R)
return;
initpc = pc - val;
npc = val;
/*
* pass 2
* turn branch references to pointers
* build back pointers
*/
for(r = firstr; r != R; r = r->link) {
p = r->prog;
if(p->to.type == D_BRANCH) {
val = p->to.offset - initpc;
r1 = firstr;
while(r1 != R) {
r2 = r1->log5;
if(r2 != R && val >= r2->pc) {
r1 = r2;
continue;
}
if(r1->pc == val)
break;
r1 = r1->link;
}
if(r1 == R) {
nearln = p->lineno;
diag(Z, "ref not found\n%P", p);
continue;
}
if(r1 == r) {
nearln = p->lineno;
diag(Z, "ref to self\n%P", p);
continue;
}
r->s2 = r1;
r->p2link = r1->p2;
r1->p2 = r;
}
}
if(debug['R']) {
p = firstr->prog;
print("\n%L %D\n", p->lineno, &p->from);
}
/*
* pass 2.5
* find looping structure
*/
for(r = firstr; r != R; r = r->link)
r->active = 0;
change = 0;
loopit(firstr, npc);
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
print("%ld:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] |
r->set.b[z];
if(bany(&bit)) {
print("\t");
if(bany(&r->use1))
print(" u1=%B", r->use1);
if(bany(&r->use2))
print(" u2=%B", r->use2);
if(bany(&r->set))
print(" st=%B", r->set);
}
print("\n");
}
}
/*
* pass 3
* iterate propagating usage
* back until flow graph is complete
*/
loop1:
change = 0;
for(r = firstr; r != R; r = r->link)
r->active = 0;
for(r = firstr; r != R; r = r->link)
if(r->prog->as == ARET)
prop(r, zbits, zbits);
loop11:
/* pick up unreachable code */
i = 0;
for(r = firstr; r != R; r = r1) {
r1 = r->link;
if(r1 && r1->active && !r->active) {
prop(r, zbits, zbits);
i = 1;
}
}
if(i)
goto loop11;
if(change)
goto loop1;
/*
* pass 4
* iterate propagating register/variable synchrony
* forward until graph is complete
*/
loop2:
change = 0;
for(r = firstr; r != R; r = r->link)
r->active = 0;
synch(firstr, zbits);
if(change)
goto loop2;
/*
* pass 5
* isolate regions
* calculate costs (paint1)
*/
r = firstr;
if(r) {
for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
if(bany(&bit)) {
nearln = r->prog->lineno;
warn(Z, "used and not set: %B", bit);
if(debug['R'] && !debug['w'])
print("used and not set: %B\n", bit);
}
}
if(debug['R'] && debug['v'])
print("\nprop structure:\n");
for(r = firstr; r != R; r = r->link)
r->act = zbits;
rgp = region;
nregion = 0;
for(r = firstr; r != R; r = r->link) {
if(debug['R'] && debug['v']) {
print("%P\t", r->prog);
if(bany(&r->set))
print("s:%B ", r->set);
if(bany(&r->refahead))
print("ra:%B ", r->refahead);
if(bany(&r->calahead))
print("ca:%B ", r->calahead);
print("\n");
}
for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] &
~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
if(bany(&bit)) {
nearln = r->prog->lineno;
warn(Z, "set and not used: %B", bit);
if(debug['R'])
print("set and not used: %B\n", bit);
excise(r);
}
for(z=0; z<BITS; z++)
bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
while(bany(&bit)) {
i = bnum(bit);
rgp->enter = r;
rgp->varno = i;
change = 0;
if(debug['R'] && debug['v'])
print("\n");
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
if(change <= 0) {
if(debug['R'])
print("%L$%d: %B\n",
r->prog->lineno, change, blsh(i));
continue;
}
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
goto brk;
}
rgp++;
}
}
brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
/*
* pass 6
* determine used registers (paint2)
* replace code (paint3)
*/
rgp = region;
for(i=0; i<nregion; i++) {
bit = blsh(rgp->varno);
vreg = paint2(rgp->enter, rgp->varno);
vreg = allreg(vreg, rgp);
if(debug['R']) {
print("%L$%d %R: %B\n",
rgp->enter->prog->lineno,
rgp->cost,
rgp->regno,
bit);
}
if(rgp->regno != 0)
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
rgp++;
}
/*
* pass 7
* peep-hole on basic block
*/
if(!debug['R'] || debug['P'])
peep();
/*
* pass 8
* recalculate pc
*/
val = initpc;
for(r = firstr; r != R; r = r1) {
r->pc = val;
p = r->prog;
p1 = P;
r1 = r->link;
if(r1 != R)
p1 = r1->prog;
for(; p != p1; p = p->link) {
switch(p->as) {
default:
val++;
break;
case ANOP:
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
break;
}
}
}
pc = val;
/*
* fix up branches
*/
if(debug['R'])
if(bany(&addrs))
print("addrs: %B\n", addrs);
r1 = 0; /* set */
for(r = firstr; r != R; r = r->link) {
p = r->prog;
if(p->to.type == D_BRANCH)
p->to.offset = r->s2->pc;
r1 = r;
}
/*
* last pass
* eliminate nops
* free aux structures
*/
for(p = firstr->prog; p != P; p = p->link){
while(p->link && p->link->as == ANOP)
p->link = p->link->link;
}
if(r1 != R) {
r1->link = freer;
freer = firstr;
}
}
/*
* add mov b,rn
* just after r
*/
void
addmove(Reg *r, int bn, int rn, int f)
{
Prog *p, *p1;
Adr *a;
Var *v;
p1 = alloc(sizeof(*p1));
*p1 = zprog;
p = r->prog;
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
v = var + bn;
a = &p1->to;
a->sym = v->sym;
a->offset = v->offset;
a->etype = v->etype;
a->type = v->name;
p1->as = AMOVL;
if(v->etype == TCHAR || v->etype == TUCHAR)
p1->as = AMOVB;
if(v->etype == TSHORT || v->etype == TUSHORT)
p1->as = AMOVW;
p1->from.type = rn;
if(!f) {
p1->from = *a;
*a = zprog.from;
a->type = rn;
if(v->etype == TUCHAR)
p1->as = AMOVB;
if(v->etype == TUSHORT)
p1->as = AMOVW;
}
if(debug['R'])
print("%P\t.a%P\n", p, p1);
}
ulong
doregbits(int r)
{
ulong b;
b = 0;
if(r >= D_INDIR)
r -= D_INDIR;
if(r >= D_AX && r <= D_DI)
b |= RtoB(r);
else
if(r >= D_AL && r <= D_BL)
b |= RtoB(r-D_AL+D_AX);
else
if(r >= D_AH && r <= D_BH)
b |= RtoB(r-D_AH+D_AX);
return b;
}
Bits
mkvar(Reg *r, Adr *a)
{
Var *v;
int i, t, n, et, z;
long o;
Bits bit;
Sym *s;
/*
* mark registers used
*/
t = a->type;
r->regu |= doregbits(t);
r->regu |= doregbits(a->index);
switch(t) {
default:
goto none;
case D_ADDR:
a->type = a->index;
bit = mkvar(r, a);
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
a->type = t;
goto none;
case D_EXTERN:
case D_STATIC:
case D_PARAM:
case D_AUTO:
n = t;
break;
}
s = a->sym;
if(s == S)
goto none;
if(s->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
v = var;
for(i=0; i<nvar; i++) {
if(s == v->sym)
if(n == v->name)
if(o == v->offset)
goto out;
v++;
}
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
i = nvar;
nvar++;
v = &var[i];
v->sym = s;
v->offset = o;
v->name = n;
v->etype = et;
if(debug['R'])
print("bit=%2d et=%2d %D\n", i, et, a);
out:
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
for(z=0; z<BITS; z++)
externs.b[z] |= bit.b[z];
if(n == D_PARAM)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
if(v->etype != et || !typechlpfd[et]) /* funny punning */
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
return bit;
none:
return zbits;
}
void
prop(Reg *r, Bits ref, Bits cal)
{
Reg *r1, *r2;
int z;
for(r1 = r; r1 != R; r1 = r1->p1) {
for(z=0; z<BITS; z++) {
ref.b[z] |= r1->refahead.b[z];
if(ref.b[z] != r1->refahead.b[z]) {
r1->refahead.b[z] = ref.b[z];
change++;
}
cal.b[z] |= r1->calahead.b[z];
if(cal.b[z] != r1->calahead.b[z]) {
r1->calahead.b[z] = cal.b[z];
change++;
}
}
switch(r1->prog->as) {
case ACALL:
for(z=0; z<BITS; z++) {
cal.b[z] |= ref.b[z] | externs.b[z];
ref.b[z] = 0;
}
break;
case ATEXT:
for(z=0; z<BITS; z++) {
cal.b[z] = 0;
ref.b[z] = 0;
}
break;
case ARET:
for(z=0; z<BITS; z++) {
cal.b[z] = externs.b[z];
ref.b[z] = 0;
}
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
r1->use1.b[z] | r1->use2.b[z];
cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
r1->refbehind.b[z] = ref.b[z];
r1->calbehind.b[z] = cal.b[z];
}
if(r1->active)
break;
r1->active = 1;
}
for(; r != r1; r = r->p1)
for(r2 = r->p2; r2 != R; r2 = r2->p2link)
prop(r2, r->refbehind, r->calbehind);
}
/*
* find looping structure
*
* 1) find reverse postordering
* 2) find approximate dominators,
* the actual dominators if the flow graph is reducible
* otherwise, dominators plus some other non-dominators.
* See Matthew S. Hecht and Jeffrey D. Ullman,
* "Analysis of a Simple Algorithm for Global Data Flow Problems",
* Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
* Oct. 1-3, 1973, pp. 207-217.
* 3) find all nodes with a predecessor dominated by the current node.
* such a node is a loop head.
* recursively, all preds with a greater rpo number are in the loop
*/
long
postorder(Reg *r, Reg **rpo2r, long n)
{
Reg *r1;
r->rpo = 1;
r1 = r->s1;
if(r1 && !r1->rpo)
n = postorder(r1, rpo2r, n);
r1 = r->s2;
if(r1 && !r1->rpo)
n = postorder(r1, rpo2r, n);
rpo2r[n] = r;
n++;
return n;
}
long
rpolca(long *idom, long rpo1, long rpo2)
{
long t;
if(rpo1 == -1)
return rpo2;
while(rpo1 != rpo2){
if(rpo1 > rpo2){
t = rpo2;
rpo2 = rpo1;
rpo1 = t;
}
while(rpo1 < rpo2){
t = idom[rpo2];
if(t >= rpo2)
fatal(Z, "bad idom");
rpo2 = t;
}
}
return rpo1;
}
int
doms(long *idom, long r, long s)
{
while(s > r)
s = idom[s];
return s == r;
}
int
loophead(long *idom, Reg *r)
{
long src;
src = r->rpo;
if(r->p1 != R && doms(idom, src, r->p1->rpo))
return 1;
for(r = r->p2; r != R; r = r->p2link)
if(doms(idom, src, r->rpo))
return 1;
return 0;
}
void
loopmark(Reg **rpo2r, long head, Reg *r)
{
if(r->rpo < head || r->active == head)
return;
r->active = head;
r->loop += LOOP;
if(r->p1 != R)
loopmark(rpo2r, head, r->p1);
for(r = r->p2; r != R; r = r->p2link)
loopmark(rpo2r, head, r);
}
void
loopit(Reg *r, long nr)
{
Reg *r1;
long i, d, me;
if(nr > maxnr) {
rpo2r = alloc(nr * sizeof(Reg*));
idom = alloc(nr * sizeof(long));
maxnr = nr;
}
d = postorder(r, rpo2r, 0);
if(d > nr)
fatal(Z, "too many reg nodes");
nr = d;
for(i = 0; i < nr / 2; i++){
r1 = rpo2r[i];
rpo2r[i] = rpo2r[nr - 1 - i];
rpo2r[nr - 1 - i] = r1;
}
for(i = 0; i < nr; i++)
rpo2r[i]->rpo = i;
idom[0] = 0;
for(i = 0; i < nr; i++){
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
if(r1->p1 != R && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
if(r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
for(i = 0; i < nr; i++){
r1 = rpo2r[i];
r1->loop++;
if(r1->p2 != R && loophead(idom, r1))
loopmark(rpo2r, i, r1);
}
}
void
synch(Reg *r, Bits dif)
{
Reg *r1;
int z;
for(r1 = r; r1 != R; r1 = r1->s1) {
for(z=0; z<BITS; z++) {
dif.b[z] = (dif.b[z] &
~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
r1->set.b[z] | r1->regdiff.b[z];
if(dif.b[z] != r1->regdiff.b[z]) {
r1->regdiff.b[z] = dif.b[z];
change++;
}
}
if(r1->active)
break;
r1->active = 1;
for(z=0; z<BITS; z++)
dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
if(r1->s2 != R)
synch(r1->s2, dif);
}
}
ulong
allreg(ulong b, Rgn *r)
{
Var *v;
int i;
v = var + r->varno;
r->regno = 0;
switch(v->etype) {
default:
diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
break;
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TARRAY:
i = BtoR(~b);
if(i && r->cost > 0) {
r->regno = i;
return RtoB(i);
}
break;
case TDOUBLE:
case TFLOAT:
break;
}
return 0;
}
void
paint1(Reg *r, int bn)
{
Reg *r1;
Prog *p;
int z;
ulong bb;
z = bn/32;
bb = 1L<<(bn%32);
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
r = r1;
}
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tld %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
r->act.b[z] |= bb;
p = r->prog;
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(p->as == AFMOVL)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
print("%ld%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(p->as == AFMOVL)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
print("%ld%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(p->as == AFMOVL)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
print("%ld%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
paint1(r1, bn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
paint1(r1, bn);
r = r->s1;
if(r == R)
break;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
break;
}
}
ulong
regset(Reg *r, ulong bb)
{
ulong b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = BtoR(b);
c = copyu(r->prog, &v, A);
if(c == 3)
set |= b;
bb &= ~b;
}
return set;
}
ulong
reguse(Reg *r, ulong bb)
{
ulong b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = BtoR(b);
c = copyu(r->prog, &v, A);
if(c == 1 || c == 2 || c == 4)
set |= b;
bb &= ~b;
}
return set;
}
ulong
paint2(Reg *r, int bn)
{
Reg *r1;
int z;
ulong bb, vreg, x;
z = bn/32;
bb = 1L << (bn%32);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(!(r1->act.b[z] & bb))
break;
r = r1;
}
for(;;) {
r->act.b[z] &= ~bb;
vreg |= r->regu;
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
vreg |= paint2(r1, bn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
vreg |= paint2(r1, bn);
r = r->s1;
if(r == R)
break;
if(!(r->act.b[z] & bb))
break;
if(!(r->refbehind.b[z] & bb))
break;
}
bb = vreg;
for(; r; r=r->s1) {
x = r->regu & ~bb;
if(x) {
vreg |= reguse(r, x);
bb |= regset(r, x);
}
}
return vreg;
}
void
paint3(Reg *r, int bn, long rb, int rn)
{
Reg *r1;
Prog *p;
int z;
ulong bb;
z = bn/32;
bb = 1L << (bn%32);
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
r = r1;
}
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
addmove(r, bn, rn, 0);
for(;;) {
r->act.b[z] |= bb;
p = r->prog;
if(r->use1.b[z] & bb) {
if(debug['R'])
print("%P", p);
addreg(&p->from, rn);
if(debug['R'])
print("\t.c%P\n", p);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
if(debug['R'])
print("%P", p);
addreg(&p->to, rn);
if(debug['R'])
print("\t.c%P\n", p);
}
if(STORE(r) & r->regdiff.b[z] & bb)
addmove(r, bn, rn, 1);
r->regu |= rb;
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
paint3(r1, bn, rb, rn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
paint3(r1, bn, rb, rn);
r = r->s1;
if(r == R)
break;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
break;
}
}
void
addreg(Adr *a, int rn)
{
a->sym = 0;
a->offset = 0;
a->type = rn;
}
long
RtoB(int r)
{
if(r < D_AX || r > D_DI)
return 0;
return 1L << (r-D_AX);
}
int
BtoR(long b)
{
b &= 0xffL;
if(b == 0)
return 0;
return bitno(b) + D_AX;
}
// Inferno utils/8c/sgen.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.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 "gc.h"
void
codgen(Node *n, Node *nn)
{
Prog *sp;
Node *n1, nod, nod1;
cursafe = 0;
curarg = 0;
maxargsafe = 0;
/*
* isolate name
*/
for(n1 = nn;; n1 = n1->left) {
if(n1 == Z) {
diag(nn, "cant find function name");
return;
}
if(n1->op == ONAME)
break;
}
nearln = nn->lineno;
gpseudo(ATEXT, n1->sym, nodconst(stkoff));
/*
* isolate first argument
*/
if(REGARG) {
if(typesuv[thisfn->link->etype]) {
nod1 = *nodret->left;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
} else
if(firstarg && typechlp[firstargtype->etype]) {
nod1 = *nodret->left;
nod1.sym = firstarg;
nod1.type = firstargtype;
nod1.xoffset = align(0, firstargtype, Aarg1);
nod1.etype = firstargtype->etype;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
}
}
sp = p;
retok = 0;
gen(n);
if(!retok)
if(thisfn->link->etype != TVOID)
warn(Z, "no return at end of function: %s", n1->sym->name);
noretval(3);
if(thisfn && thisfn->link && typefd[thisfn->link->etype])
gins(AFLDZ, Z, Z);
gbranch(ORETURN);
if(!debug['N'] || debug['R'] || debug['P'])
regopt(sp);
sp->to.offset += maxargsafe;
}
void
supgen(Node *n)
{
long spc;
Prog *sp;
if(n == Z)
return;
suppress++;
spc = pc;
sp = lastp;
gen(n);
lastp = sp;
pc = spc;
sp->link = nil;
suppress--;
}
void
gen(Node *n)
{
Node *l, nod;
Prog *sp, *spc, *spb;
Case *cn;
long sbc, scc;
int f, o;
loop:
if(n == Z)
return;
nearln = n->lineno;
o = n->op;
if(debug['G'])
if(o != OLIST)
print("%L %O\n", nearln, o);
retok = 0;
switch(o) {
default:
complex(n);
cgen(n, Z);
break;
case OLIST:
gen(n->left);
rloop:
n = n->right;
goto loop;
case ORETURN:
retok = 1;
complex(n);
if(n->type == T)
break;
l = n->left;
if(l == Z) {
noretval(3);
if(typefd[n->type->etype])
gins(AFLDZ, Z, Z);
gbranch(ORETURN);
break;
}
if(typesuv[n->type->etype]) {
sugen(l, nodret, n->type->width);
noretval(3);
gbranch(ORETURN);
break;
}
regret(&nod, n);
cgen(l, &nod);
regfree(&nod);
if(typefd[n->type->etype])
noretval(1);
else
noretval(2);
gbranch(ORETURN);
break;
case OLABEL:
l = n->left;
if(l) {
l->xoffset = pc;
if(l->label)
patch(l->label, pc);
}
gbranch(OGOTO); /* prevent self reference in reg */
patch(p, pc);
goto rloop;
case OGOTO:
retok = 1;
n = n->left;
if(n == Z)
return;
if(n->complex == 0) {
diag(Z, "label undefined: %s", n->sym->name);
return;
}
if(suppress)
return;
gbranch(OGOTO);
if(n->xoffset) {
patch(p, n->xoffset);
return;
}
if(n->label)
patch(n->label, pc-1);
n->label = p;
return;
case OCASE:
l = n->left;
if(cases == C)
diag(n, "case/default outside a switch");
if(l == Z) {
cas();
cases->val = 0;
cases->def = 1;
cases->label = pc;
goto rloop;
}
complex(l);
if(l->type == T)
goto rloop;
if(l->op == OCONST)
if(typechl[l->type->etype]) {
cas();
cases->val = l->vconst;
cases->def = 0;
cases->label = pc;
goto rloop;
}
diag(n, "case expression must be integer constant");
goto rloop;
case OSWITCH:
l = n->left;
complex(l);
if(l->type == T)
break;
if(!typechl[l->type->etype]) {
diag(n, "switch expression must be integer");
break;
}
gbranch(OGOTO); /* entry */
sp = p;
cn = cases;
cases = C;
cas();
sbc = breakpc;
breakpc = pc;
gbranch(OGOTO);
spb = p;
gen(n->right);
gbranch(OGOTO);
patch(p, breakpc);
patch(sp, pc);
regalloc(&nod, l, Z);
nod.type = types[TLONG];
cgen(l, &nod);
doswit(&nod);
regfree(&nod);
patch(spb, pc);
cases = cn;
breakpc = sbc;
break;
case OWHILE:
case ODWHILE:
l = n->left;
gbranch(OGOTO); /* entry */
sp = p;
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
if(n->op == OWHILE)
patch(sp, pc);
bcomplex(l, Z); /* test */
patch(p, breakpc);
if(n->op == ODWHILE)
patch(sp, pc);
gen(n->right); /* body */
gbranch(OGOTO);
patch(p, continpc);
patch(spb, pc);
continpc = scc;
breakpc = sbc;
break;
case OFOR:
l = n->left;
gen(l->right->left); /* init */
gbranch(OGOTO); /* entry */
sp = p;
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
gen(l->right->right); /* inc */
patch(sp, pc);
if(l->left != Z) { /* test */
bcomplex(l->left, Z);
patch(p, breakpc);
}
gen(n->right); /* body */
gbranch(OGOTO);
patch(p, continpc);
patch(spb, pc);
continpc = scc;
breakpc = sbc;
break;
case OCONTINUE:
if(continpc < 0) {
diag(n, "continue not in a loop");
break;
}
gbranch(OGOTO);
patch(p, continpc);
break;
case OBREAK:
if(breakpc < 0) {
diag(n, "break not in a loop");
break;
}
gbranch(OGOTO);
patch(p, breakpc);
break;
case OIF:
l = n->left;
if(bcomplex(l, n->right)) {
if(typefd[l->type->etype])
f = !l->fconst;
else
f = !l->vconst;
if(debug['c'])
print("%L const if %s\n", nearln, f ? "false" : "true");
if(f) {
supgen(n->right->left);
gen(n->right->right);
}
else {
gen(n->right->left);
supgen(n->right->right);
}
}
else {
sp = p;
if(n->right->left != Z)
gen(n->right->left);
if(n->right->right != Z) {
gbranch(OGOTO);
patch(sp, pc);
sp = p;
gen(n->right->right);
}
patch(sp, pc);
}
break;
case OSET:
case OUSED:
usedset(n->left, o);
break;
}
}
void
usedset(Node *n, int o)
{
if(n->op == OLIST) {
usedset(n->left, o);
usedset(n->right, o);
return;
}
complex(n);
switch(n->op) {
case OADDR: /* volatile */
gins(ANOP, n, Z);
break;
case ONAME:
if(o == OSET)
gins(ANOP, Z, n);
else
gins(ANOP, n, Z);
break;
}
}
void
noretval(int n)
{
if(n & 1) {
gins(ANOP, Z, Z);
p->to.type = REGRET;
}
if(n & 2) {
gins(ANOP, Z, Z);
p->to.type = FREGRET;
}
}
/* welcome to commute */
static void
commute(Node *n)
{
Node *l, *r;
l = n->left;
r = n->right;
if(r->complex > l->complex) {
n->left = r;
n->right = l;
}
}
void
indexshift(Node *n)
{
int g;
if(!typechlp[n->type->etype])
return;
simplifyshift(n);
if(n->op == OASHL && n->right->op == OCONST){
g = vconst(n->right);
if(g >= 0 && g < 4)
n->addable = 7;
}
}
/*
* calculate addressability as follows
* NAME ==> 10/11 name+value(SB/SP)
* REGISTER ==> 12 register
* CONST ==> 20 $value
* *(20) ==> 21 value
* &(10) ==> 13 $name+value(SB)
* &(11) ==> 1 $name+value(SP)
* (13) + (20) ==> 13 fold constants
* (1) + (20) ==> 1 fold constants
* *(13) ==> 10 back to name
* *(1) ==> 11 back to name
*
* (20) * (X) ==> 7 multiplier in indexing
* (X,7) + (13,1) ==> 8 adder in indexing (addresses)
* (8) ==> &9(OINDEX) index, almost addressable
*
* calculate complexity (number of registers)
*/
void
xcom(Node *n)
{
Node *l, *r;
int g;
if(n == Z)
return;
l = n->left;
r = n->right;
n->complex = 0;
n->addable = 0;
switch(n->op) {
case OCONST:
n->addable = 20;
break;
case ONAME:
n->addable = 10;
if(n->class == CPARAM || n->class == CAUTO)
n->addable = 11;
break;
case OREGISTER:
n->addable = 12;
break;
case OINDREG:
n->addable = 12;
break;
case OADDR:
xcom(l);
if(l->addable == 10)
n->addable = 13;
else
if(l->addable == 11)
n->addable = 1;
break;
case OADD:
xcom(l);
xcom(r);
if(n->type->etype != TIND)
break;
switch(r->addable) {
case 20:
switch(l->addable) {
case 1:
case 13:
commadd:
l->type = n->type;
*n = *l;
l = new(0, Z, Z);
*l = *(n->left);
l->xoffset += r->vconst;
n->left = l;
r = n->right;
goto brk;
}
break;
case 1:
case 13:
case 10:
case 11:
/* l is the base, r is the index */
if(l->addable != 20)
n->addable = 8;
break;
}
switch(l->addable) {
case 20:
switch(r->addable) {
case 13:
case 1:
r = n->left;
l = n->right;
n->left = l;
n->right = r;
goto commadd;
}
break;
case 13:
case 1:
case 10:
case 11:
/* r is the base, l is the index */
if(r->addable != 20)
n->addable = 8;
break;
}
if(n->addable == 8 && !side(n)) {
indx(n);
l = new1(OINDEX, idx.basetree, idx.regtree);
l->scale = idx.scale;
l->addable = 9;
l->complex = l->right->complex;
l->type = l->left->type;
n->op = OADDR;
n->left = l;
n->right = Z;
n->addable = 8;
break;
}
break;
case OINDEX:
xcom(l);
xcom(r);
n->addable = 9;
break;
case OIND:
xcom(l);
if(l->op == OADDR) {
l = l->left;
l->type = n->type;
*n = *l;
return;
}
switch(l->addable) {
case 20:
n->addable = 21;
break;
case 1:
n->addable = 11;
break;
case 13:
n->addable = 10;
break;
}
break;
case OASHL:
xcom(l);
xcom(r);
indexshift(n);
break;
case OMUL:
case OLMUL:
xcom(l);
xcom(r);
g = vlog(l);
if(g >= 0) {
n->left = r;
n->right = l;
l = r;
r = n->right;
}
g = vlog(r);
if(g >= 0) {
n->op = OASHL;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
commute(n);
break;
case OASLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASLSHR;
r->vconst = g;
r->type = types[TINT];
}
break;
case OLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OLSHR;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
break;
case OASLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASAND;
r->vconst--;
}
break;
case OLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OAND;
r->vconst--;
}
break;
case OASMUL:
case OASLMUL:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASASHL;
r->vconst = g;
}
break;
case OLSHR:
case OASHR:
xcom(l);
xcom(r);
indexshift(n);
break;
default:
if(l != Z)
xcom(l);
if(r != Z)
xcom(r);
break;
}
brk:
if(n->addable >= 10)
return;
if(l != Z)
n->complex = l->complex;
if(r != Z) {
if(r->complex == n->complex)
n->complex = r->complex+1;
else
if(r->complex > n->complex)
n->complex = r->complex;
}
if(n->complex == 0)
n->complex++;
if(com64(n))
return;
switch(n->op) {
case OFUNC:
n->complex = FNX;
break;
case OLMOD:
case OMOD:
case OLMUL:
case OLDIV:
case OMUL:
case ODIV:
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(r->complex >= l->complex) {
n->complex = l->complex + 3;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 3;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OLSHR:
case OASHL:
case OASHR:
case OASLSHR:
case OASASHL:
case OASASHR:
if(r->complex >= l->complex) {
n->complex = l->complex + 2;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 2;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OADD:
case OXOR:
case OAND:
case OOR:
/*
* immediate operators, make const on right
*/
if(l->op == OCONST) {
n->left = r;
n->right = l;
}
break;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
/*
* compare operators, make const on left
*/
if(r->op == OCONST) {
n->left = r;
n->right = l;
n->op = invrel[relindex(n->op)];
}
break;
}
}
void
indx(Node *n)
{
Node *l, *r;
if(debug['x'])
prtree(n, "indx");
l = n->left;
r = n->right;
if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
n->right = l;
n->left = r;
l = r;
r = n->right;
}
if(l->addable != 7) {
idx.regtree = l;
idx.scale = 1;
} else
if(l->right->addable == 20) {
idx.regtree = l->left;
idx.scale = 1 << l->right->vconst;
} else
if(l->left->addable == 20) {
idx.regtree = l->right;
idx.scale = 1 << l->left->vconst;
} else
diag(n, "bad index");
idx.basetree = r;
if(debug['x']) {
print("scale = %d\n", idx.scale);
prtree(idx.regtree, "index");
prtree(idx.basetree, "base");
}
}
int
bcomplex(Node *n, Node *c)
{
Node *b, nod;
complex(n);
if(n->type != T)
if(tcompat(n, T, n->type, tnot))
n->type = T;
if(n->type != T) {
if(c != Z && n->op == OCONST && deadheads(c))
return 1;
if(typev[n->type->etype] && machcap(Z)) {
b = &nod;
b->op = ONE;
b->left = n;
b->right = new(0, Z, Z);
*b->right = *nodconst(0);
b->right->type = n->type;
b->type = types[TLONG];
cgen64(b, Z);
return 0;
}
bool64(n);
boolgen(n, 1, Z);
} else
gbranch(OGOTO);
return 0;
}
// Inferno utils/8c/swt.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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 "gc.h"
int
swcmp(const void *a1, const void *a2)
{
C1 *p1, *p2;
p1 = (C1*)a1;
p2 = (C1*)a2;
if(p1->val < p2->val)
return -1;
return p1->val > p2->val;
}
void
doswit(Node *n)
{
Case *c;
C1 *q, *iq;
long def, nc, i;
def = 0;
nc = 0;
for(c = cases; c->link != C; c = c->link) {
if(c->def) {
if(def)
diag(n, "more than one default in switch");
def = c->label;
continue;
}
nc++;
}
iq = alloc(nc*sizeof(C1));
q = iq;
for(c = cases; c->link != C; c = c->link) {
if(c->def)
continue;
q->label = c->label;
q->val = c->val;
q++;
}
qsort(iq, nc, sizeof(C1), swcmp);
if(debug['W'])
for(i=0; i<nc; i++)
print("case %2ld: = %.8lux\n", i, iq[i].val);
if(def == 0)
def = breakpc;
for(i=0; i<nc-1; i++)
if(iq[i].val == iq[i+1].val)
diag(n, "duplicate cases in switch %ld", iq[i].val);
swit1(iq, nc, def, n);
}
void
swit1(C1 *q, int nc, long def, Node *n)
{
C1 *r;
int i;
Prog *sp;
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
print("case = %.8lux\n", q->val);
gopcode(OEQ, n->type, n, nodconst(q->val));
patch(p, q->label);
q++;
}
gbranch(OGOTO);
patch(p, def);
return;
}
i = nc / 2;
r = q+i;
if(debug['W'])
print("case > %.8lux\n", r->val);
gopcode(OGT, n->type, n, nodconst(r->val));
sp = p;
gbranch(OGOTO);
p->as = AJEQ;
patch(p, r->label);
swit1(q, i, def, n);
if(debug['W'])
print("case < %.8lux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
}
void
cas(void)
{
Case *c;
c = alloc(sizeof(*c));
c->link = cases;
cases = c;
}
void
bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
{
int sh;
long v;
Node *l;
/*
* n1 gets adjusted/masked value
* n2 gets address of cell
* n3 gets contents of cell
*/
l = b->left;
if(n2 != Z) {
regalloc(n1, l, nn);
reglcgen(n2, l, Z);
regalloc(n3, l, Z);
gmove(n2, n3);
gmove(n3, n1);
} else {
regalloc(n1, l, nn);
cgen(l, n1);
}
if(b->type->shift == 0 && typeu[b->type->etype]) {
v = ~0 + (1L << b->type->nbits);
gopcode(OAND, types[TLONG], nodconst(v), n1);
} else {
sh = 32 - b->type->shift - b->type->nbits;
if(sh > 0)
gopcode(OASHL, types[TLONG], nodconst(sh), n1);
sh += b->type->shift;
if(sh > 0)
if(typeu[b->type->etype])
gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
else
gopcode(OASHR, types[TLONG], nodconst(sh), n1);
}
}
void
bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
{
long v;
Node nod;
int sh;
regalloc(&nod, b->left, Z);
v = ~0 + (1L << b->type->nbits);
gopcode(OAND, types[TLONG], nodconst(v), n1);
gmove(n1, &nod);
if(nn != Z)
gmove(n1, nn);
sh = b->type->shift;
if(sh > 0)
gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
v <<= sh;
gopcode(OAND, types[TLONG], nodconst(~v), n3);
gopcode(OOR, types[TLONG], n3, &nod);
gmove(&nod, n2);
regfree(&nod);
regfree(n1);
regfree(n2);
regfree(n3);
}
long
outstring(char *s, long n)
{
long r;
if(suppress)
return nstring;
r = nstring;
while(n) {
string[mnstring] = *s++;
mnstring++;
nstring++;
if(mnstring >= NSNAME) {
gpseudo(ADATA, symstring, nodconst(0L));
p->from.offset += nstring - NSNAME;
p->from.scale = NSNAME;
p->to.type = D_SCONST;
memmove(p->to.sval, string, NSNAME);
mnstring = 0;
}
n--;
}
return r;
}
long
outlstring(ushort *s, long n)
{
char buf[2];
int c;
long r;
if(suppress)
return nstring;
while(nstring & 1)
outstring("", 1);
r = nstring;
while(n > 0) {
c = *s++;
if(align(0, types[TCHAR], Aarg1)) {
buf[0] = c>>8;
buf[1] = c;
} else {
buf[0] = c;
buf[1] = c>>8;
}
outstring(buf, 2);
n -= sizeof(ushort);
}
return r;
}
void
nullwarn(Node *l, Node *r)
{
warn(Z, "result of operation not used");
if(l != Z)
cgen(l, Z);
if(r != Z)
cgen(r, Z);
}
void
sextern(Sym *s, Node *a, long o, long w)
{
long e, lw;
for(e=0; e<w; e+=NSNAME) {
lw = NSNAME;
if(w-e < lw)
lw = w-e;
gpseudo(ADATA, s, nodconst(0L));
p->from.offset += o+e;
p->from.scale = lw;
p->to.type = D_SCONST;
memmove(p->to.sval, a->cstring+e, lw);
}
}
void
gextern(Sym *s, Node *a, long o, long w)
{
if(a->op == OCONST && typev[a->type->etype]) {
gpseudo(ADATA, s, lo64(a));
p->from.offset += o;
p->from.scale = 4;
gpseudo(ADATA, s, hi64(a));
p->from.offset += o + 4;
p->from.scale = 4;
return;
}
gpseudo(ADATA, s, a);
p->from.offset += o;
p->from.scale = w;
switch(p->to.type) {
default:
p->to.index = p->to.type;
p->to.type = D_ADDR;
case D_CONST:
case D_FCONST:
case D_ADDR:
break;
}
}
void zname(Biobuf*, Sym*, int);
void zaddr(Biobuf*, Adr*, int);
void outhist(Biobuf*);
void
outcode(void)
{
struct { Sym *sym; short type; } h[NSYM];
Prog *p;
Sym *s;
int f, sf, st, t, sym;
Biobuf b;
if(debug['S']) {
for(p = firstp; p != P; p = p->link)
if(p->as != ADATA && p->as != AGLOBL)
pc--;
for(p = firstp; p != P; p = p->link) {
print("%P\n", p);
if(p->as != ADATA && p->as != AGLOBL)
pc++;
}
}
f = open(outfile, OWRITE);
if(f < 0) {
diag(Z, "cannot open %s", outfile);
return;
}
Binit(&b, f, OWRITE);
Bseek(&b, 0L, 2);
outhist(&b);
for(sym=0; sym<NSYM; sym++) {
h[sym].sym = S;
h[sym].type = 0;
}
sym = 1;
for(p = firstp; p != P; p = p->link) {
jackpot:
sf = 0;
s = p->from.sym;
while(s != S) {
sf = s->sym;
if(sf < 0 || sf >= NSYM)
sf = 0;
t = p->from.type;
if(t == D_ADDR)
t = p->from.index;
if(h[sf].type == t)
if(h[sf].sym == s)
break;
s->sym = sym;
zname(&b, s, t);
h[sym].sym = s;
h[sym].type = t;
sf = sym;
sym++;
if(sym >= NSYM)
sym = 1;
break;
}
st = 0;
s = p->to.sym;
while(s != S) {
st = s->sym;
if(st < 0 || st >= NSYM)
st = 0;
t = p->to.type;
if(t == D_ADDR)
t = p->to.index;
if(h[st].type == t)
if(h[st].sym == s)
break;
s->sym = sym;
zname(&b, s, t);
h[sym].sym = s;
h[sym].type = t;
st = sym;
sym++;
if(sym >= NSYM)
sym = 1;
if(st == sf)
goto jackpot;
break;
}
Bputc(&b, p->as);
Bputc(&b, p->as>>8);
Bputc(&b, p->lineno);
Bputc(&b, p->lineno>>8);
Bputc(&b, p->lineno>>16);
Bputc(&b, p->lineno>>24);
zaddr(&b, &p->from, sf);
zaddr(&b, &p->to, st);
}
Bflush(&b);
close(f);
firstp = P;
lastp = P;
}
void
outhist(Biobuf *b)
{
Hist *h;
char *p, *q, *op, c;
Prog pg;
int n;
pg = zprog;
pg.as = AHISTORY;
c = pathchar();
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
p += 2;
c = *p;
}
if(p && p[0] != c && h->offset == 0 && pathname){
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
p = pathname+2;
c = *p;
} else if(pathname[0] == c){
op = p;
p = pathname;
}
}
while(p) {
q = utfrune(p, c);
if(q) {
n = q-p;
if(n == 0){
n = 1; /* leading "/" */
*p = '/'; /* don't emit "\" on windows */
}
q++;
} else {
n = strlen(p);
q = 0;
}
if(n) {
Bputc(b, ANAME);
Bputc(b, ANAME>>8);
Bputc(b, D_FILE);
Bputc(b, 1);
Bputc(b, '<');
Bwrite(b, p, n);
Bputc(b, 0);
}
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
pg.lineno = h->line;
pg.to.type = zprog.to.type;
pg.to.offset = h->offset;
if(h->offset)
pg.to.type = D_CONST;
Bputc(b, pg.as);
Bputc(b, pg.as>>8);
Bputc(b, pg.lineno);
Bputc(b, pg.lineno>>8);
Bputc(b, pg.lineno>>16);
Bputc(b, pg.lineno>>24);
zaddr(b, &pg.from, 0);
zaddr(b, &pg.to, 0);
}
}
void
zname(Biobuf *b, Sym *s, int t)
{
char *n;
ulong sig;
if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
sig = sign(s);
Bputc(b, ASIGNAME);
Bputc(b, ASIGNAME>>8);
Bputc(b, sig);
Bputc(b, sig>>8);
Bputc(b, sig>>16);
Bputc(b, sig>>24);
s->sig = SIGDONE;
}
else{
Bputc(b, ANAME); /* as */
Bputc(b, ANAME>>8); /* as */
}
Bputc(b, t); /* type */
Bputc(b, s->sym); /* sym */
n = s->name;
while(*n) {
Bputc(b, *n);
n++;
}
Bputc(b, 0);
}
void
zaddr(Biobuf *b, Adr *a, int s)
{
long l;
int i, t;
char *n;
Ieee e;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
switch(a->type) {
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0)
t |= T_OFFSET;
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
Bputc(b, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(b, a->index);
Bputc(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
}
if(t & T_SYM) /* implies sym */
Bputc(b, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e.l;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
l = e.h;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(b, a->type);
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (long)(fr*f);
}
long
align(long i, Type *t, int op)
{
long o;
Type *v;
int w;
o = i;
w = 1;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
break;
case Asu2: /* padding at end of a struct */
w = SZ_LONG;
if(packflg)
w = packflg;
break;
case Ael1: /* initial allign of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
w = ewidth[v->etype];
if(w <= 0 || w >= SZ_LONG)
w = SZ_LONG;
if(packflg)
w = packflg;
break;
case Ael2: /* width of a struct element */
o += t->width;
break;
case Aarg0: /* initial passbyptr argument in arg list */
if(typesuv[t->etype]) {
o = align(o, types[TIND], Aarg1);
o = align(o, types[TIND], Aarg2);
}
break;
case Aarg1: /* initial allign of parameter */
w = ewidth[t->etype];
if(w <= 0 || w >= SZ_LONG) {
w = SZ_LONG;
break;
}
w = 1; /* little endian no adjustment */
break;
case Aarg2: /* width of a parameter */
o += t->width;
w = SZ_LONG;
break;
case Aaut3: /* total allign of automatic */
o = align(o, t, Ael1);
o = align(o, t, Ael2);
break;
}
o = round(o, w);
if(debug['A'])
print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
return o;
}
long
maxround(long max, long v)
{
v += SZ_LONG-1;
if(v > max)
max = round(v, SZ_LONG);
return max;
}
// Inferno utils/8c/txt.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "gc.h"
void
ginit(void)
{
int i;
Type *t;
thechar = '8';
thestring = "386";
exregoffset = 0;
exfregoffset = 0;
listinit();
nstring = 0;
mnstring = 0;
nrathole = 0;
pc = 0;
breakpc = -1;
continpc = -1;
cases = C;
firstp = P;
lastp = P;
tfield = types[TLONG];
zprog.link = P;
zprog.as = AGOK;
zprog.from.type = D_NONE;
zprog.from.index = D_NONE;
zprog.from.scale = 0;
zprog.to = zprog.from;
regnode.op = OREGISTER;
regnode.class = CEXREG;
regnode.reg = REGTMP;
regnode.complex = 0;
regnode.addable = 11;
regnode.type = types[TLONG];
fregnode0 = regnode;
fregnode0.reg = D_F0;
fregnode0.type = types[TDOUBLE];
fregnode1 = fregnode0;
fregnode1.reg = D_F0+1;
constnode.op = OCONST;
constnode.class = CXXX;
constnode.complex = 0;
constnode.addable = 20;
constnode.type = types[TLONG];
fconstnode.op = OCONST;
fconstnode.class = CXXX;
fconstnode.complex = 0;
fconstnode.addable = 20;
fconstnode.type = types[TDOUBLE];
nodsafe = new(ONAME, Z, Z);
nodsafe->sym = slookup(".safe");
nodsafe->type = types[TINT];
nodsafe->etype = types[TINT]->etype;
nodsafe->class = CAUTO;
complex(nodsafe);
t = typ(TARRAY, types[TCHAR]);
symrathole = slookup(".rathole");
symrathole->class = CGLOBL;
symrathole->type = t;
nodrat = new(ONAME, Z, Z);
nodrat->sym = symrathole;
nodrat->type = types[TIND];
nodrat->etype = TVOID;
nodrat->class = CGLOBL;
complex(nodrat);
nodrat->type = t;
nodret = new(ONAME, Z, Z);
nodret->sym = slookup(".ret");
nodret->type = types[TIND];
nodret->etype = TIND;
nodret->class = CPARAM;
nodret = new(OIND, nodret, Z);
complex(nodret);
com64init();
for(i=0; i<nelem(reg); i++) {
reg[i] = 1;
if(i >= D_AX && i <= D_DI && i != D_SP)
reg[i] = 0;
}
}
void
gclean(void)
{
int i;
Sym *s;
reg[D_SP]--;
for(i=D_AX; i<=D_DI; i++)
if(reg[i])
diag(Z, "reg %R left allocated", i);
while(mnstring)
outstring("", 1L);
symstring->type->width = nstring;
symrathole->type->width = nrathole;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type == T)
continue;
if(s->type->width == 0)
continue;
if(s->class != CGLOBL && s->class != CSTATIC)
continue;
if(s->type == types[TENUM])
continue;
gpseudo(AGLOBL, s, nodconst(s->type->width));
}
nextpc();
p->as = AEND;
outcode();
}
void
nextpc(void)
{
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
pc++;
if(firstp == P) {
firstp = p;
lastp = p;
return;
}
lastp->link = p;
lastp = p;
}
void
gargs(Node *n, Node *tn1, Node *tn2)
{
long regs;
Node fnxargs[20], *fnxp;
regs = cursafe;
fnxp = fnxargs;
garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
curarg = 0;
fnxp = fnxargs;
garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
cursafe = regs;
}
int nareg(void)
{
int i, n;
n = 0;
for(i=D_AX; i<=D_DI; i++)
if(reg[i] == 0)
n++;
return n;
}
void
garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
{
Node nod;
if(n == Z)
return;
if(n->op == OLIST) {
garg1(n->left, tn1, tn2, f, fnxp);
garg1(n->right, tn1, tn2, f, fnxp);
return;
}
if(f == 0) {
if(n->complex >= FNX) {
regsalloc(*fnxp, n);
nod = znode;
nod.op = OAS;
nod.left = *fnxp;
nod.right = n;
nod.type = n->type;
cgen(&nod, Z);
(*fnxp)++;
}
return;
}
if(typesu[n->type->etype] || typev[n->type->etype]) {
regaalloc(tn2, n);
if(n->complex >= FNX) {
sugen(*fnxp, tn2, n->type->width);
(*fnxp)++;
} else
sugen(n, tn2, n->type->width);
return;
}
if(REGARG && curarg == 0 && typeilp[n->type->etype]) {
regaalloc1(tn1, n);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
return;
}
if(vconst(n) == 0) {
regaalloc(tn2, n);
gmove(n, tn2);
return;
}
regalloc(tn1, n, Z);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
regaalloc(tn2, n);
gmove(tn1, tn2);
regfree(tn1);
}
Node*
nodconst(long v)
{
constnode.vconst = v;
return &constnode;
}
Node*
nodfconst(double d)
{
fconstnode.fconst = d;
return &fconstnode;
}
int
isreg(Node *n, int r)
{
if(n->op == OREGISTER)
if(n->reg == r)
return 1;
return 0;
}
int
nodreg(Node *n, Node *nn, int r)
{
*n = regnode;
n->reg = r;
if(reg[r] == 0)
return 0;
if(nn != Z) {
n->type = nn->type;
n->lineno = nn->lineno;
if(nn->op == OREGISTER)
if(nn->reg == r)
return 0;
}
return 1;
}
void
regret(Node *n, Node *nn)
{
int r;
r = REGRET;
if(typefd[nn->type->etype])
r = FREGRET;
nodreg(n, nn, r);
reg[r]++;
}
void
regalloc(Node *n, Node *tn, Node *o)
{
int i;
switch(tn->type->etype) {
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= D_AX && i <= D_DI)
goto out;
}
for(i=D_AX; i<=D_DI; i++)
if(reg[i] == 0)
goto out;
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
case TVLONG:
i = D_F0;
goto out;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
i = 0;
out:
if(i)
reg[i]++;
nodreg(n, tn, i);
}
void
regialloc(Node *n, Node *tn, Node *o)
{
Node nod;
nod = *tn;
nod.type = types[TIND];
regalloc(n, &nod, o);
}
void
regfree(Node *n)
{
int i;
i = 0;
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
i = n->reg;
if(i < 0 || i >= sizeof(reg))
goto err;
if(reg[i] <= 0)
goto err;
reg[i]--;
return;
err:
diag(n, "error in regfree: %R", i);
}
void
regsalloc(Node *n, Node *nn)
{
cursafe = align(cursafe, nn->type, Aaut3);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
n->type = nn->type;
n->etype = nn->type->etype;
n->lineno = nn->lineno;
}
void
regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
curarg = align(curarg, nn->type, Aarg1);
curarg = align(curarg, nn->type, Aarg2);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
curarg = align(curarg, nn->type, Aarg1);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
curarg = align(curarg, nn->type, Aarg2);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regind(Node *n, Node *nn)
{
if(n->op != OREGISTER) {
diag(n, "regind not OREGISTER");
return;
}
n->op = OINDREG;
n->type = nn->type;
}
void
naddr(Node *n, Adr *a)
{
long v;
a->type = D_NONE;
if(n == Z)
return;
switch(n->op) {
default:
bad:
diag(n, "bad in naddr: %O %D", n->op, a);
break;
case OREGISTER:
a->type = n->reg;
a->sym = S;
break;
case OIND:
naddr(n->left, a);
if(a->type >= D_AX && a->type <= D_DI)
a->type += D_INDIR;
else
if(a->type == D_CONST)
a->type = D_NONE+D_INDIR;
else
if(a->type == D_ADDR) {
a->type = a->index;
a->index = D_NONE;
} else
goto bad;
break;
case OINDEX:
a->type = idx.ptr;
if(n->left->op == OADDR || n->left->op == OCONST)
naddr(n->left, a);
if(a->type >= D_AX && a->type <= D_DI)
a->type += D_INDIR;
else
if(a->type == D_CONST)
a->type = D_NONE+D_INDIR;
else
if(a->type == D_ADDR) {
a->type = a->index;
a->index = D_NONE;
} else
goto bad;
a->index = idx.reg;
a->scale = n->scale;
a->offset += n->xoffset;
break;
case OINDREG:
a->type = n->reg+D_INDIR;
a->sym = S;
a->offset = n->xoffset;
break;
case ONAME:
a->etype = n->etype;
a->type = D_STATIC;
a->sym = n->sym;
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
if(n->class == CEXTERN || n->class == CGLOBL) {
a->type = D_EXTERN;
break;
}
if(n->class == CAUTO) {
a->type = D_AUTO;
break;
}
if(n->class == CPARAM) {
a->type = D_PARAM;
break;
}
goto bad;
case OCONST:
if(typefd[n->type->etype]) {
a->type = D_FCONST;
a->dval = n->fconst;
break;
}
a->sym = S;
a->type = D_CONST;
a->offset = n->vconst;
break;
case OADDR:
naddr(n->left, a);
if(a->type >= D_INDIR) {
a->type -= D_INDIR;
break;
}
if(a->type == D_EXTERN || a->type == D_STATIC ||
a->type == D_AUTO || a->type == D_PARAM)
if(a->index == D_NONE) {
a->index = a->type;
a->type = D_ADDR;
break;
}
goto bad;
case OADD:
if(n->right->op == OCONST) {
v = n->right->vconst;
naddr(n->left, a);
} else
if(n->left->op == OCONST) {
v = n->left->vconst;
naddr(n->right, a);
} else
goto bad;
a->offset += v;
break;
}
}
#define CASE(a,b) ((a<<8)|(b<<0))
void
gmove(Node *f, Node *t)
{
int ft, tt, a;
Node nod, nod1;
Prog *p1;
ft = f->type->etype;
tt = t->type->etype;
if(debug['M'])
print("gop: %O %O[%s],%O[%s]\n", OAS,
f->op, tnames[ft], t->op, tnames[tt]);
if(typefd[ft] && f->op == OCONST) {
if(f->fconst == 0)
gins(AFLDZ, Z, Z);
else
if(f->fconst == 1)
gins(AFLD1, Z, Z);
else
gins(AFMOVD, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
/*
* load
*/
if(f->op == ONAME || f->op == OINDREG ||
f->op == OIND || f->op == OINDEX)
switch(ft) {
case TCHAR:
a = AMOVBLSX;
goto ld;
case TUCHAR:
a = AMOVBLZX;
goto ld;
case TSHORT:
if(typefd[tt]) {
gins(AFMOVW, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
a = AMOVWLSX;
goto ld;
case TUSHORT:
a = AMOVWLZX;
goto ld;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
if(typefd[tt]) {
gins(AFMOVL, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
a = AMOVL;
ld:
regalloc(&nod, f, t);
nod.type = types[TLONG];
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case TFLOAT:
gins(AFMOVF, f, t);
return;
case TDOUBLE:
gins(AFMOVD, f, t);
return;
case TVLONG:
gins(AFMOVV, f, t);
return;
}
/*
* store
*/
if(t->op == ONAME || t->op == OINDREG ||
t->op == OIND || t->op == OINDEX)
switch(tt) {
case TCHAR:
case TUCHAR:
a = AMOVB; goto st;
case TSHORT:
case TUSHORT:
a = AMOVW; goto st;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVL; goto st;
st:
if(f->op == OCONST) {
gins(a, f, t);
return;
}
regalloc(&nod, t, f);
gmove(f, &nod);
gins(a, &nod, t);
regfree(&nod);
return;
case TFLOAT:
gins(AFMOVFP, f, t);
return;
case TDOUBLE:
gins(AFMOVDP, f, t);
return;
case TVLONG:
gins(AFMOVVP, f, t);
return;
}
/*
* convert
*/
switch(CASE(ft,tt)) {
default:
/*
* integer to integer
********
a = AGOK; break;
case CASE( TCHAR, TCHAR):
case CASE( TUCHAR, TCHAR):
case CASE( TSHORT, TCHAR):
case CASE( TUSHORT,TCHAR):
case CASE( TINT, TCHAR):
case CASE( TUINT, TCHAR):
case CASE( TLONG, TCHAR):
case CASE( TULONG, TCHAR):
case CASE( TIND, TCHAR):
case CASE( TCHAR, TUCHAR):
case CASE( TUCHAR, TUCHAR):
case CASE( TSHORT, TUCHAR):
case CASE( TUSHORT,TUCHAR):
case CASE( TINT, TUCHAR):
case CASE( TUINT, TUCHAR):
case CASE( TLONG, TUCHAR):
case CASE( TULONG, TUCHAR):
case CASE( TIND, TUCHAR):
case CASE( TSHORT, TSHORT):
case CASE( TUSHORT,TSHORT):
case CASE( TINT, TSHORT):
case CASE( TUINT, TSHORT):
case CASE( TLONG, TSHORT):
case CASE( TULONG, TSHORT):
case CASE( TIND, TSHORT):
case CASE( TSHORT, TUSHORT):
case CASE( TUSHORT,TUSHORT):
case CASE( TINT, TUSHORT):
case CASE( TUINT, TUSHORT):
case CASE( TLONG, TUSHORT):
case CASE( TULONG, TUSHORT):
case CASE( TIND, TUSHORT):
case CASE( TINT, TINT):
case CASE( TUINT, TINT):
case CASE( TLONG, TINT):
case CASE( TULONG, TINT):
case CASE( TIND, TINT):
case CASE( TINT, TUINT):
case CASE( TUINT, TUINT):
case CASE( TLONG, TUINT):
case CASE( TULONG, TUINT):
case CASE( TIND, TUINT):
case CASE( TINT, TLONG):
case CASE( TUINT, TLONG):
case CASE( TLONG, TLONG):
case CASE( TULONG, TLONG):
case CASE( TIND, TLONG):
case CASE( TINT, TULONG):
case CASE( TUINT, TULONG):
case CASE( TLONG, TULONG):
case CASE( TULONG, TULONG):
case CASE( TIND, TULONG):
case CASE( TINT, TIND):
case CASE( TUINT, TIND):
case CASE( TLONG, TIND):
case CASE( TULONG, TIND):
case CASE( TIND, TIND):
*****/
a = AMOVL;
break;
case CASE( TSHORT, TINT):
case CASE( TSHORT, TUINT):
case CASE( TSHORT, TLONG):
case CASE( TSHORT, TULONG):
case CASE( TSHORT, TIND):
a = AMOVWLSX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
if(f->vconst & 0x8000)
f->vconst |= 0xffff0000;
a = AMOVL;
}
break;
case CASE( TUSHORT,TINT):
case CASE( TUSHORT,TUINT):
case CASE( TUSHORT,TLONG):
case CASE( TUSHORT,TULONG):
case CASE( TUSHORT,TIND):
a = AMOVWLZX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
a = AMOVL;
}
break;
case CASE( TCHAR, TSHORT):
case CASE( TCHAR, TUSHORT):
case CASE( TCHAR, TINT):
case CASE( TCHAR, TUINT):
case CASE( TCHAR, TLONG):
case CASE( TCHAR, TULONG):
case CASE( TCHAR, TIND):
a = AMOVBLSX;
if(f->op == OCONST) {
f->vconst &= 0xff;
if(f->vconst & 0x80)
f->vconst |= 0xffffff00;
a = AMOVL;
}
break;
case CASE( TUCHAR, TSHORT):
case CASE( TUCHAR, TUSHORT):
case CASE( TUCHAR, TINT):
case CASE( TUCHAR, TUINT):
case CASE( TUCHAR, TLONG):
case CASE( TUCHAR, TULONG):
case CASE( TUCHAR, TIND):
a = AMOVBLZX;
if(f->op == OCONST) {
f->vconst &= 0xff;
a = AMOVL;
}
break;
/*
* float to fix
*/
case CASE( TFLOAT, TCHAR):
case CASE( TFLOAT, TUCHAR):
case CASE( TFLOAT, TSHORT):
case CASE( TFLOAT, TUSHORT):
case CASE( TFLOAT, TINT):
case CASE( TFLOAT, TUINT):
case CASE( TFLOAT, TLONG):
case CASE( TFLOAT, TULONG):
case CASE( TFLOAT, TIND):
case CASE( TDOUBLE,TCHAR):
case CASE( TDOUBLE,TUCHAR):
case CASE( TDOUBLE,TSHORT):
case CASE( TDOUBLE,TUSHORT):
case CASE( TDOUBLE,TINT):
case CASE( TDOUBLE,TUINT):
case CASE( TDOUBLE,TLONG):
case CASE( TDOUBLE,TULONG):
case CASE( TDOUBLE,TIND):
case CASE( TVLONG, TCHAR):
case CASE( TVLONG, TUCHAR):
case CASE( TVLONG, TSHORT):
case CASE( TVLONG, TUSHORT):
case CASE( TVLONG, TINT):
case CASE( TVLONG, TUINT):
case CASE( TVLONG, TLONG):
case CASE( TVLONG, TULONG):
case CASE( TVLONG, TIND):
if(fproundflg) {
regsalloc(&nod, &regnode);
gins(AFMOVLP, f, &nod);
gmove(&nod, t);
return;
}
regsalloc(&nod, &regnode);
regsalloc(&nod1, &regnode);
gins(AFSTCW, Z, &nod1);
nod1.xoffset += 2;
gins(AMOVW, nodconst(0xf7f), &nod1);
gins(AFLDCW, &nod1, Z);
gins(AFMOVLP, f, &nod);
nod1.xoffset -= 2;
gins(AFLDCW, &nod1, Z);
gmove(&nod, t);
return;
/*
* ulong to float
*/
case CASE( TULONG, TDOUBLE):
case CASE( TULONG, TVLONG):
case CASE( TULONG, TFLOAT):
case CASE( TUINT, TDOUBLE):
case CASE( TUINT, TVLONG):
case CASE( TUINT, TFLOAT):
regalloc(&nod, f, f);
gmove(f, &nod);
regsalloc(&nod1, &regnode);
gmove(&nod, &nod1);
gins(AFMOVL, &nod1, &fregnode0);
gins(ACMPL, &nod, nodconst(0));
gins(AJGE, Z, Z);
p1 = p;
gins(AFADDD, nodfconst(4294967296.), &fregnode0);
patch(p1, pc);
regfree(&nod);
return;
/*
* fix to float
*/
case CASE( TCHAR, TFLOAT):
case CASE( TUCHAR, TFLOAT):
case CASE( TSHORT, TFLOAT):
case CASE( TUSHORT,TFLOAT):
case CASE( TINT, TFLOAT):
case CASE( TLONG, TFLOAT):
case CASE( TIND, TFLOAT):
case CASE( TCHAR, TDOUBLE):
case CASE( TUCHAR, TDOUBLE):
case CASE( TSHORT, TDOUBLE):
case CASE( TUSHORT,TDOUBLE):
case CASE( TINT, TDOUBLE):
case CASE( TLONG, TDOUBLE):
case CASE( TIND, TDOUBLE):
case CASE( TCHAR, TVLONG):
case CASE( TUCHAR, TVLONG):
case CASE( TSHORT, TVLONG):
case CASE( TUSHORT,TVLONG):
case CASE( TINT, TVLONG):
case CASE( TLONG, TVLONG):
case CASE( TIND, TVLONG):
regsalloc(&nod, &regnode);
gmove(f, &nod);
gins(AFMOVL, &nod, &fregnode0);
return;
/*
* float to float
*/
case CASE( TFLOAT, TFLOAT):
case CASE( TDOUBLE,TFLOAT):
case CASE( TVLONG, TFLOAT):
case CASE( TFLOAT, TDOUBLE):
case CASE( TDOUBLE,TDOUBLE):
case CASE( TVLONG, TDOUBLE):
case CASE( TFLOAT, TVLONG):
case CASE( TDOUBLE,TVLONG):
case CASE( TVLONG, TVLONG):
a = AFMOVD; break;
}
if(a == AMOVL || a == AFMOVD)
if(samaddr(f, t))
return;
gins(a, f, t);
}
void
doindex(Node *n)
{
Node nod, nod1;
long v;
if(debug['Y'])
prtree(n, "index");
if(n->left->complex >= FNX)
print("botch in doindex\n");
regalloc(&nod, &regnode, Z);
v = constnode.vconst;
cgen(n->right, &nod);
idx.ptr = D_NONE;
if(n->left->op == OCONST)
idx.ptr = D_CONST;
else if(n->left->op == OREGISTER)
idx.ptr = n->left->reg;
else if(n->left->op != OADDR) {
reg[D_BP]++; // cant be used as a base
regalloc(&nod1, &regnode, Z);
cgen(n->left, &nod1);
idx.ptr = nod1.reg;
regfree(&nod1);
reg[D_BP]--;
}
idx.reg = nod.reg;
regfree(&nod);
constnode.vconst = v;
}
void
gins(int a, Node *f, Node *t)
{
if(f != Z && f->op == OINDEX)
doindex(f);
if(t != Z && t->op == OINDEX)
doindex(t);
nextpc();
p->as = a;
if(f != Z)
naddr(f, &p->from);
if(t != Z)
naddr(t, &p->to);
if(debug['g'])
print("%P\n", p);
}
void
fgopcode(int o, Node *f, Node *t, int pop, int rev)
{
int a, et;
Node nod;
et = TLONG;
if(f != Z && f->type != T)
et = f->type->etype;
if(!typefd[et]) {
diag(f, "fop: integer %O", o);
return;
}
if(debug['M']) {
if(t != Z && t->type != T)
print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
else
print("gop: %O %O-%s %O-%s\n", o,
f->op, tnames[et], t->op, tnames[t->type->etype]);
}
a = AGOK;
switch(o) {
case OASADD:
case OADD:
if(et == TFLOAT)
a = AFADDF;
else
if(et == TDOUBLE || et == TVLONG) {
a = AFADDD;
if(pop)
a = AFADDDP;
}
break;
case OASSUB:
case OSUB:
if(et == TFLOAT) {
a = AFSUBF;
if(rev)
a = AFSUBRF;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFSUBD;
if(pop)
a = AFSUBDP;
if(rev) {
a = AFSUBRD;
if(pop)
a = AFSUBRDP;
}
}
break;
case OASMUL:
case OMUL:
if(et == TFLOAT)
a = AFMULF;
else
if(et == TDOUBLE || et == TVLONG) {
a = AFMULD;
if(pop)
a = AFMULDP;
}
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
if(et == TFLOAT) {
a = AFDIVF;
if(rev)
a = AFDIVRF;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFDIVD;
if(pop)
a = AFDIVDP;
if(rev) {
a = AFDIVRD;
if(pop)
a = AFDIVRDP;
}
}
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
pop += rev;
if(et == TFLOAT) {
a = AFCOMF;
if(pop) {
a = AFCOMFP;
if(pop > 1)
a = AGOK;
}
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFCOMF;
if(pop) {
a = AFCOMDP;
if(pop > 1)
a = AFCOMDPP;
}
}
gins(a, f, t);
regalloc(&nod, &regnode, Z);
if(nod.reg != D_AX) {
regfree(&nod);
nod.reg = D_AX;
gins(APUSHL, &nod, Z);
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
gins(APOPL, Z, &nod);
} else {
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
regfree(&nod);
}
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJCS; break;
case OLE: a = AJLS; break;
case OGE: a = AJCC; break;
case OGT: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}
void
gopcode(int o, Type *ty, Node *f, Node *t)
{
int a, et;
et = TLONG;
if(ty != T)
et = ty->etype;
if(typefd[et] && o != OADDR && o != OFUNC) {
diag(f, "gop: float %O", o);
return;
}
if(debug['M']) {
if(f != Z && f->type != T)
print("gop: %O %O[%s],", o, f->op, tnames[et]);
else
print("gop: %O Z,", o);
if(t != Z && t->type != T)
print("%O[%s]\n", t->op, tnames[t->type->etype]);
else
print("Z\n");
}
a = AGOK;
switch(o) {
case OCOM:
a = ANOTL;
if(et == TCHAR || et == TUCHAR)
a = ANOTB;
if(et == TSHORT || et == TUSHORT)
a = ANOTW;
break;
case ONEG:
a = ANEGL;
if(et == TCHAR || et == TUCHAR)
a = ANEGB;
if(et == TSHORT || et == TUSHORT)
a = ANEGW;
break;
case OADDR:
a = ALEAL;
break;
case OASADD:
case OADD:
a = AADDL;
if(et == TCHAR || et == TUCHAR)
a = AADDB;
if(et == TSHORT || et == TUSHORT)
a = AADDW;
break;
case OASSUB:
case OSUB:
a = ASUBL;
if(et == TCHAR || et == TUCHAR)
a = ASUBB;
if(et == TSHORT || et == TUSHORT)
a = ASUBW;
break;
case OASOR:
case OOR:
a = AORL;
if(et == TCHAR || et == TUCHAR)
a = AORB;
if(et == TSHORT || et == TUSHORT)
a = AORW;
break;
case OASAND:
case OAND:
a = AANDL;
if(et == TCHAR || et == TUCHAR)
a = AANDB;
if(et == TSHORT || et == TUSHORT)
a = AANDW;
break;
case OASXOR:
case OXOR:
a = AXORL;
if(et == TCHAR || et == TUCHAR)
a = AXORB;
if(et == TSHORT || et == TUSHORT)
a = AXORW;
break;
case OASLSHR:
case OLSHR:
a = ASHRL;
if(et == TCHAR || et == TUCHAR)
a = ASHRB;
if(et == TSHORT || et == TUSHORT)
a = ASHRW;
break;
case OASASHR:
case OASHR:
a = ASARL;
if(et == TCHAR || et == TUCHAR)
a = ASARB;
if(et == TSHORT || et == TUSHORT)
a = ASARW;
break;
case OASASHL:
case OASHL:
a = ASALL;
if(et == TCHAR || et == TUCHAR)
a = ASALB;
if(et == TSHORT || et == TUSHORT)
a = ASALW;
break;
case OFUNC:
a = ACALL;
break;
case OASMUL:
case OMUL:
if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
t = Z;
a = AIMULL;
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
a = AIDIVL;
break;
case OASLMUL:
case OLMUL:
a = AMULL;
break;
case OASLMOD:
case OLMOD:
case OASLDIV:
case OLDIV:
a = ADIVL;
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OLO:
case OLS:
case OHS:
case OHI:
a = ACMPL;
if(et == TCHAR || et == TUCHAR)
a = ACMPB;
if(et == TSHORT || et == TUSHORT)
a = ACMPW;
gins(a, f, t);
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJLT; break;
case OLE: a = AJLE; break;
case OGE: a = AJGE; break;
case OGT: a = AJGT; break;
case OLO: a = AJCS; break;
case OLS: a = AJLS; break;
case OHS: a = AJCC; break;
case OHI: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}
int
samaddr(Node *f, Node *t)
{
if(f->op != t->op)
return 0;
switch(f->op) {
case OREGISTER:
if(f->reg != t->reg)
break;
return 1;
}
return 0;
}
void
gbranch(int o)
{
int a;
a = AGOK;
switch(o) {
case ORETURN:
a = ARET;
break;
case OGOTO:
a = AJMP;
break;
}
nextpc();
if(a == AGOK) {
diag(Z, "bad in gbranch %O", o);
nextpc();
}
p->as = a;
}
void
patch(Prog *op, long pc)
{
op->to.offset = pc;
op->to.type = D_BRANCH;
}
void
gpseudo(int a, Sym *s, Node *n)
{
nextpc();
p->as = a;
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.scale = (profileflg ? 0 : NOPROF);
if(s->class == CSTATIC)
p->from.type = D_STATIC;
naddr(n, &p->to);
if(a == ADATA || a == AGLOBL)
pc--;
}
int
sconst(Node *n)
{
long v;
if(n->op == OCONST && !typefd[n->type->etype]) {
v = n->vconst;
if(v >= -32766L && v < 32766L)
return 1;
}
return 0;
}
long
exreg(Type *t)
{
USED(t);
return 0;
}
schar ewidth[NTYPE] =
{
-1, /*[TXXX]*/
SZ_CHAR, /*[TCHAR]*/
SZ_CHAR, /*[TUCHAR]*/
SZ_SHORT, /*[TSHORT]*/
SZ_SHORT, /*[TUSHORT]*/
SZ_INT, /*[TINT]*/
SZ_INT, /*[TUINT]*/
SZ_LONG, /*[TLONG]*/
SZ_LONG, /*[TULONG]*/
SZ_VLONG, /*[TVLONG]*/
SZ_VLONG, /*[TUVLONG]*/
SZ_FLOAT, /*[TFLOAT]*/
SZ_DOUBLE, /*[TDOUBLE]*/
SZ_IND, /*[TIND]*/
0, /*[TFUNC]*/
-1, /*[TARRAY]*/
0, /*[TVOID]*/
-1, /*[TSTRUCT]*/
-1, /*[TUNION]*/
SZ_INT, /*[TENUM]*/
};
long ncast[NTYPE] =
{
0, /*[TXXX]*/
BCHAR|BUCHAR, /*[TCHAR]*/
BCHAR|BUCHAR, /*[TUCHAR]*/
BSHORT|BUSHORT, /*[TSHORT]*/
BSHORT|BUSHORT, /*[TUSHORT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
BVLONG|BUVLONG, /*[TVLONG]*/
BVLONG|BUVLONG, /*[TUVLONG]*/
BFLOAT, /*[TFLOAT]*/
BDOUBLE, /*[TDOUBLE]*/
BLONG|BULONG|BIND, /*[TIND]*/
0, /*[TFUNC]*/
0, /*[TARRAY]*/
0, /*[TVOID]*/
BSTRUCT, /*[TSTRUCT]*/
BUNION, /*[TUNION]*/
0, /*[TENUM]*/
};
// Inferno utils/8l/asm.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "l.h"
#define Dbufslop 100
long
entryvalue(void)
{
char *a;
Sym *s;
a = INITENTRY;
if(*a >= '0' && *a <= '9')
return atolwhex(a);
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
switch(s->type) {
case STEXT:
break;
case SDATA:
if(dlm)
return s->value+INITDAT;
default:
diag("entry not text: %s", s->name);
}
return s->value;
}
void
wput(ushort w)
{
cput(w);
cput(w>>8);
}
void
wputb(ushort w)
{
cput(w>>8);
cput(w);
}
void
asmb(void)
{
Prog *p;
long v, magic;
int a;
uchar *op1;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
seek(cout, HEADR, 0);
pc = INITTEXT;
curp = firstp;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->pc != pc) {
if(!debug['a'])
print("%P\n", curp);
diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
pc = p->pc;
}
curp = p;
asmins(p);
if(cbc < sizeof(and))
cflush();
a = (andptr - and);
if(debug['a']) {
Bprint(&bso, pcstr, pc);
for(op1 = and; op1 < andptr; op1++)
Bprint(&bso, "%.2ux", *op1 & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
if(dlm) {
if(p->as == ATEXT)
reloca = nil;
else if(reloca != nil)
diag("reloc failure: %P", curp);
}
memmove(cbp, and, a);
cbp += a;
pc += a;
cbc -= a;
}
cflush();
switch(HEADTYPE) {
default:
diag("unknown header type %d", HEADTYPE);
case 0:
seek(cout, rnd(HEADR+textsize, 8192), 0);
break;
case 1:
textsize = rnd(HEADR+textsize, 4096)-HEADR;
seek(cout, textsize+HEADR, 0);
break;
case 2:
seek(cout, HEADR+textsize, 0);
break;
case 3:
case 4:
seek(cout, HEADR+rnd(textsize, INITRND), 0);
break;
}
if(debug['v'])
Bprint(&bso, "%5.2f datblk\n", cputime());
Bflush(&bso);
if(dlm){
char buf[8];
write(cout, buf, INITDAT-textsize);
textsize = INITDAT;
}
for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
if(datsize-v > sizeof(buf)-Dbufslop)
datblk(v, sizeof(buf)-Dbufslop);
else
datblk(v, datsize-v);
}
symsize = 0;
spsize = 0;
lcsize = 0;
if(!debug['s']) {
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
switch(HEADTYPE) {
default:
case 0:
seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
break;
case 1:
seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
break;
case 2:
seek(cout, HEADR+textsize+datsize, 0);
break;
case 3:
case 4:
debug['s'] = 1;
break;
}
if(!debug['s'])
asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f sp\n", cputime());
Bflush(&bso);
if(debug['v'])
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
asmlc();
if(dlm)
asmdyn();
cflush();
}
else if(dlm){
seek(cout, HEADR+textsize+datsize, 0);
asmdyn();
cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f headr\n", cputime());
Bflush(&bso);
seek(cout, 0L, 0);
switch(HEADTYPE) {
default:
case 0: /* garbage */
lput(0x160L<<16); /* magic and sections */
lput(0L); /* time and date */
lput(rnd(HEADR+textsize, 4096)+datsize);
lput(symsize); /* nsyms */
lput((0x38L<<16)|7L); /* size of optional hdr and flags */
lput((0413<<16)|0437L); /* magic and version */
lput(rnd(HEADR+textsize, 4096)); /* sizes */
lput(datsize);
lput(bsssize);
lput(entryvalue()); /* va of entry */
lput(INITTEXT-HEADR); /* va of base of text */
lput(INITDAT); /* va of base of data */
lput(INITDAT+datsize); /* va of base of bss */
lput(~0L); /* gp reg mask */
lput(0L);
lput(0L);
lput(0L);
lput(0L);
lput(~0L); /* gp value ?? */
break;
lputl(0); /* x */
case 1: /* unix coff */
/*
* file header
*/
lputl(0x0004014c); /* 4 sections, magic */
lputl(0); /* unix time stamp */
lputl(0); /* symbol table */
lputl(0); /* nsyms */
lputl(0x0003001c); /* flags, sizeof a.out header */
/*
* a.out header
*/
lputl(0x10b); /* magic, version stamp */
lputl(rnd(textsize, INITRND)); /* text sizes */
lputl(datsize); /* data sizes */
lputl(bsssize); /* bss sizes */
lput(entryvalue()); /* va of entry */
lputl(INITTEXT); /* text start */
lputl(INITDAT); /* data start */
/*
* text section header
*/
s8put(".text");
lputl(HEADR); /* pa */
lputl(HEADR); /* va */
lputl(textsize); /* text size */
lputl(HEADR); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x20); /* flags text only */
/*
* data section header
*/
s8put(".data");
lputl(INITDAT); /* pa */
lputl(INITDAT); /* va */
lputl(datsize); /* data size */
lputl(HEADR+textsize); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x40); /* flags data only */
/*
* bss section header
*/
s8put(".bss");
lputl(INITDAT+datsize); /* pa */
lputl(INITDAT+datsize); /* va */
lputl(bsssize); /* bss size */
lputl(0); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x80); /* flags bss only */
/*
* comment section header
*/
s8put(".comment");
lputl(0); /* pa */
lputl(0); /* va */
lputl(symsize+lcsize); /* comment size */
lputl(HEADR+textsize+datsize); /* file offset */
lputl(HEADR+textsize+datsize); /* offset of syms */
lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x200); /* flags comment only */
break;
case 2: /* plan9 */
magic = 4*11*11+7;
if(dlm)
magic |= 0x80000000;
lput(magic); /* magic */
lput(textsize); /* sizes */
lput(datsize);
lput(bsssize);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(spsize); /* sp offsets */
lput(lcsize); /* line offsets */
break;
case 3:
/* MS-DOS .COM */
break;
case 4:
/* fake MS-DOS .EXE */
v = rnd(HEADR+textsize, INITRND)+datsize;
wput(0x5A4D); /* 'MZ' */
wput(v % 512); /* bytes in last page */
wput(rnd(v, 512)/512); /* total number of pages */
wput(0x0000); /* number of reloc items */
v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
wput(v/16); /* size of header */
wput(0x0000); /* minimum allocation */
wput(0xFFFF); /* maximum allocation */
wput(0x0000); /* initial ss value */
wput(0x0100); /* initial sp value */
wput(0x0000); /* complemented checksum */
v = entryvalue();
wput(v); /* initial ip value (!) */
wput(0x0000); /* initial cs value */
wput(0x0000);
wput(0x0000);
wput(0x003E); /* reloc table offset */
wput(0x0000); /* overlay number */
break;
}
cflush();
}
void
lput(long l)
{
cput(l>>24);
cput(l>>16);
cput(l>>8);
cput(l);
}
void
lputl(long l)
{
cput(l);
cput(l>>8);
cput(l>>16);
cput(l>>24);
}
void
s8put(char *n)
{
char name[8];
int i;
strncpy(name, n, sizeof(name));
for(i=0; i<sizeof(name); i++)
cput(name[i]);
}
void
cflush(void)
{
int n;
n = sizeof(buf.cbuf) - cbc;
if(n)
write(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
void
datblk(long s, long n)
{
Prog *p;
char *cast;
long l, fl, j;
int i, c;
memset(buf.dbuf, 0, n+Dbufslop);
for(p = datap; p != P; p = p->link) {
curp = p;
l = p->from.sym->value + p->from.offset - s;
c = p->from.scale;
i = 0;
if(l < 0) {
if(l+c <= 0)
continue;
while(l < 0) {
l++;
i++;
}
}
if(l >= n)
continue;
if(p->as != AINIT && p->as != ADYNT) {
for(j=l+(c-i)-1; j>=l; j--)
if(buf.dbuf[j]) {
print("%P\n", p);
diag("multiple initialization");
break;
}
}
switch(p->to.type) {
case D_FCONST:
switch(c) {
default:
case 4:
fl = ieeedtof(&p->to.ieee);
cast = (char*)&fl;
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi4[i]];
l++;
}
break;
case 8:
cast = (char*)&p->to.ieee;
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi8[i]];
l++;
}
break;
}
break;
case D_SCONST:
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = p->to.scon[i];
l++;
}
break;
default:
fl = p->to.offset;
if(p->to.type == D_ADDR) {
if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
diag("DADDR type%P", p);
if(p->to.sym) {
if(p->to.sym->type == SUNDEF)
ckoff(p->to.sym, fl);
fl += p->to.sym->value;
if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
fl += INITDAT;
if(dlm)
dynreloc(p->to.sym, l+s+INITDAT, 1);
}
}
cast = (char*)&fl;
switch(c) {
default:
diag("bad nuxi %d %d\n%P", c, i, curp);
break;
case 1:
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi1[i]];
l++;
}
break;
case 2:
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi2[i]];
l++;
}
break;
case 4:
if(debug['a'] && i == 0) {
Bprint(&bso, pcstr, l+s+INITDAT);
for(j=0; j<c; j++)
Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
Bprint(&bso, "\t%P\n", curp);
}
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi4[i]];
l++;
}
break;
}
break;
}
}
write(cout, buf.dbuf, n);
}
long
rnd(long v, long r)
{
long c;
if(r <= 0)
return v;
v += r - 1;
c = v % r;
if(c < 0)
c += r;
v -= c;
return v;
}
// Inferno utils/8l/l.h
// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <lib9.h>
#include <bio.h>
#include "../8c/8.out.h"
#ifndef EXTERN
#define EXTERN extern
#endif
#define P ((Prog*)0)
#define S ((Sym*)0)
#define TNAME (curtext?curtext->from.sym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
cflush(); }
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
struct Adr
{
union
{
long u0offset;
char u0scon[8];
Prog *u0cond; /* not used, but should be D_BRANCH */
Ieee u0ieee;
} u0;
union
{
Auto* u1autom;
Sym* u1sym;
} u1;
short type;
char index;
char scale;
};
#define offset u0.u0offset
#define scon u0.u0scon
#define cond u0.u0cond
#define ieee u0.u0ieee
#define autom u1.u1autom
#define sym u1.u1sym
struct Prog
{
Adr from;
Adr to;
Prog *forwd;
Prog* link;
Prog* pcond; /* work on this */
long pc;
long line;
uchar mark; /* work on these */
uchar back;
short as;
char width; /* fake for DATA */
};
struct Auto
{
Sym* asym;
Auto* link;
long aoffset;
short type;
};
struct Sym
{
char *name;
short type;
short version;
short become;
short frame;
uchar subtype;
ushort file;
long value;
long sig;
Sym* link;
};
struct Optab
{
short as;
uchar* ytab;
uchar prefix;
uchar op[10];
};
enum
{
STEXT = 1,
SDATA,
SBSS,
SDATA1,
SXREF,
SFILE,
SCONST,
SUNDEF,
SIMPORT,
SEXPORT,
NHASH = 10007,
NHUNK = 100000,
MINSIZ = 4,
STRINGSZ = 200,
MINLC = 1,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
Yi0,
Yi1,
Yi8,
Yi32,
Yiauto,
Yal,
Ycl,
Yax,
Ycx,
Yrb,
Yrl,
Yrf,
Yf0,
Yrx,
Ymb,
Yml,
Ym,
Ybr,
Ycol,
Ycs, Yss, Yds, Yes, Yfs, Ygs,
Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
Ymax,
Zxxx = 0,
Zlit,
Z_rp,
Zbr,
Zcall,
Zib_,
Zib_rp,
Zibo_m,
Zil_,
Zil_rp,
Zilo_m,
Zjmp,
Zloop,
Zm_o,
Zm_r,
Zaut_r,
Zo_m,
Zpseudo,
Zr_m,
Zrp_,
Z_ib,
Z_il,
Zm_ibo,
Zm_ilo,
Zib_rr,
Zil_rr,
Zclr,
Zbyte,
Zmov,
Zmax,
Px = 0,
Pe = 0x66, /* operand escape */
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
Roffset = 22, /* no. bits for offset in relocation address */
Rindex = 10, /* no. bits for index in relocation address */
};
EXTERN union
{
struct
{
char obuf[MAXIO]; /* output buffer */
uchar ibuf[MAXIO]; /* input buffer */
} u;
char dbuf[1];
} buf;
#define cbuf u.obuf
#define xbuf u.ibuf
#pragma varargck type "A" uint
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
EXTERN long HEADR;
EXTERN long HEADTYPE;
EXTERN long INITDAT;
EXTERN long INITRND;
EXTERN long INITTEXT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
EXTERN long bsssize;
EXTERN long casepc;
EXTERN int cbc;
EXTERN char* cbp;
EXTERN char* pcstr;
EXTERN int cout;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Prog* curtext;
EXTERN Prog* datap;
EXTERN Prog* edatap;
EXTERN long datsize;
EXTERN char debug[128];
EXTERN char literal[32];
EXTERN Prog* etextp;
EXTERN Prog* firstp;
EXTERN char fnuxi8[8];
EXTERN char fnuxi4[4];
EXTERN Sym* hash[NHASH];
EXTERN Sym* histfrog[MAXHIST];
EXTERN int histfrogp;
EXTERN int histgen;
EXTERN char* library[50];
EXTERN char* libraryobj[50];
EXTERN int libraryp;
EXTERN int xrefresolv;
EXTERN char* hunk;
EXTERN char inuxi1[1];
EXTERN char inuxi2[2];
EXTERN char inuxi4[4];
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar and[30];
EXTERN char reg[D_NONE];
EXTERN Prog* lastp;
EXTERN long lcsize;
EXTERN int maxop;
EXTERN int nerrors;
EXTERN long nhunk;
EXTERN long nsymbol;
EXTERN char* noname;
EXTERN char* outfile;
EXTERN long pc;
EXTERN long spsize;
EXTERN Sym* symlist;
EXTERN long symsize;
EXTERN Prog* textp;
EXTERN long textsize;
EXTERN long thunk;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN Adr* reloca;
EXTERN int doexp, dlm;
EXTERN int imports, nimports;
EXTERN int exports, nexports;
EXTERN char* EXPTAB;
EXTERN Prog undefp;
#define UP (&undefp)
extern Optab optab[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(long, int);
Prog* appendp(Prog*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
void asmlc(void);
void asmsp(void);
void asmsym(void);
long atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void cflush(void);
void ckoff(Sym*, long);
Prog* copyp(Prog*);
double cputime(void);
void datblk(long, long);
void diag(char*, ...);
void dodata(void);
void doinit(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
void dynreloc(Sym*, ulong, int);
long entryvalue(void);
void errorexit(void);
void export(void);
int find1(long, int);
int find2(long, int);
void follow(void);
void gethunk(void);
void histtoauto(void);
double ieeedtod(Ieee*);
long ieeedtof(Ieee*);
void import(void);
void ldobj(int, long, char*);
void loadlib(void);
void listinit(void);
Sym* lookup(char*, int);
void lput(long);
void lputl(long);
void main(int, char*[]);
void mkfwd(void);
void* mysbrk(ulong);
void nuxiinit(void);
void objfile(char*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
void readundefs(char*, int);
int relinv(int);
long reuse(Prog*, Sym*);
long rnd(long, long);
void s8put(char*);
void span(void);
void undef(void);
void undefsym(Sym*);
long vaddr(Adr*);
void wputb(ushort);
void xdefine(char*, int, long);
void xfol(Prog*);
int zaddr(uchar*, Adr*, Sym*[]);
void zerosig(char*);
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "A" int
// Inferno utils/8l/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.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 "l.h"
void
listinit(void)
{
fmtinstall('R', Rconv);
fmtinstall('A', Aconv);
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
}
static Prog *bigP;
int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
bigP = p;
switch(p->as) {
case ATEXT:
if(p->from.scale) {
sprint(str, "(%ld) %A %D,%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
sprint(str, "(%ld) %A %D,%D",
p->line, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT:
case ADYNT:
sprint(str, "(%ld) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
return fmtstrcpy(fp, str);
}
int
Aconv(Fmt *fp)
{
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
}
int
Dconv(Fmt *fp)
{
char str[40], s[20];
Adr *a;
int i;
a = va_arg(fp->args, Adr*);
i = a->type;
if(i >= D_INDIR) {
if(a->offset)
sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
else
sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
sprint(str, "%R", i);
break;
case D_NONE:
str[0] = 0;
break;
case D_BRANCH:
if(bigP != P && bigP->pcond != P)
if(a->sym != S)
sprint(str, "%lux+%s", bigP->pcond->pc,
a->sym->name);
else
sprint(str, "%lux", bigP->pcond->pc);
else
sprint(str, "%ld(PC)", a->offset);
break;
case D_EXTERN:
sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
break;
case D_STATIC:
sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
a->sym->version, a->offset);
break;
case D_AUTO:
sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
break;
case D_PARAM:
if(a->sym)
sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
else
sprint(str, "%ld(FP)", a->offset);
break;
case D_CONST:
sprint(str, "$%ld", a->offset);
break;
case D_FCONST:
sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
sprint(str, "$\"%S\"", a->scon);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
sprint(s, "(%R*%d)", a->index, a->scale);
strcat(str, s);
}
conv:
return fmtstrcpy(fp, str);
}
char* regstr[] =
{
"AL", /* [D_AL] */
"CL",
"DL",
"BL",
"AH",
"CH",
"DH",
"BH",
"AX", /* [D_AX] */
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"F0", /* [D_F0] */
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", /* [D_GDTR] */
"IDTR", /* [D_IDTR] */
"LDTR", /* [D_LDTR] */
"MSW", /* [D_MSW] */
"TASK", /* [D_TASK] */
"CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"NONE", /* [D_NONE] */
};
int
Rconv(Fmt *fp)
{
char str[20];
int r;
r = va_arg(fp->args, int);
if(r >= D_AL && r <= D_NONE)
sprint(str, "%s", regstr[r-D_AL]);
else
sprint(str, "gok(%d)", r);
return fmtstrcpy(fp, str);
}
int
Sconv(Fmt *fp)
{
int i, c;
char str[30], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
default:
if(c < 040 || c >= 0177)
break; /* not portable */
p[-1] = c;
continue;
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}
void
diag(char *fmt, ...)
{
char buf[STRINGSZ], *tn;
va_list arg;
tn = "??none??";
if(curtext != P && curtext->from.sym != S)
tn = curtext->from.sym->name;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
print("%s: %s\n", tn, buf);
nerrors++;
if(nerrors > 20) {
print("too many errors\n");
errorexit();
}
}
// Inferno utils/8l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define EXTERN
#include "l.h"
#include <ar.h>
#ifndef DEFAULT
#define DEFAULT '9'
#endif
char *noname = "<none>";
char symname[] = SYMDEF;
char thechar = '8';
char *thestring = "386";
/*
* -H0 -T0x40004C -D0x10000000 is garbage unix
* -H1 -T0xd0 -R4 is unix coff
* -H2 -T4128 -R4096 is plan9 format
* -H3 -Tx -Rx is MS-DOS .COM
* -H4 -Tx -Rx is fake MS-DOS .EXE
*/
static int
isobjfile(char *f)
{
int n, v;
Biobuf *b;
char buf1[5], buf2[SARMAG];
b = Bopen(f, OREAD);
if(b == nil)
return 0;
n = Bread(b, buf1, 5);
if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
v = 1; /* good enough for our purposes */
else{
Bseek(b, 0, 0);
n = Bread(b, buf2, SARMAG);
v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
}
Bterm(b);
return v;
}
void
main(int argc, char *argv[])
{
int i, c;
char *a;
Binit(&bso, 1, OWRITE);
cout = -1;
listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = "8.out";
HEADTYPE = -1;
INITTEXT = -1;
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
ARGBEGIN {
default:
c = ARGC();
if(c >= 0 && c < sizeof(debug))
debug[c]++;
break;
case 'o': /* output to (next arg) */
outfile = ARGF();
break;
case 'E':
a = ARGF();
if(a)
INITENTRY = a;
break;
case 'H':
a = ARGF();
if(a)
HEADTYPE = atolwhex(a);
break;
case 'T':
a = ARGF();
if(a)
INITTEXT = atolwhex(a);
break;
case 'D':
a = ARGF();
if(a)
INITDAT = atolwhex(a);
break;
case 'R':
a = ARGF();
if(a)
INITRND = atolwhex(a);
break;
case 'x': /* produce export table */
doexp = 1;
if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
readundefs(ARGF(), SEXPORT);
break;
case 'u': /* produce dynamically loadable module */
dlm = 1;
debug['l']++;
if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
readundefs(ARGF(), SIMPORT);
break;
} ARGEND
USED(argc);
if(*argv == 0) {
diag("usage: 8l [-options] objects");
errorexit();
}
if(!debug['9'] && !debug['U'] && !debug['B'])
debug[DEFAULT] = 1;
if(HEADTYPE == -1) {
if(debug['U'])
HEADTYPE = 1;
if(debug['B'])
HEADTYPE = 2;
if(debug['9'])
HEADTYPE = 2;
}
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
case 0: /* this is garbage */
HEADR = 20L+56L;
if(INITTEXT == -1)
INITTEXT = 0x40004CL;
if(INITDAT == -1)
INITDAT = 0x10000000L;
if(INITRND == -1)
INITRND = 0;
break;
case 1: /* is unix coff */
HEADR = 0xd0L;
if(INITTEXT == -1)
INITTEXT = 0xd0;
if(INITDAT == -1)
INITDAT = 0x400000;
if(INITRND == -1)
INITRND = 0;
break;
case 2: /* plan 9 */
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+32;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4096;
break;
case 3: /* MS-DOS .COM */
HEADR = 0;
if(INITTEXT == -1)
INITTEXT = 0x0100;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4;
break;
case 4: /* fake MS-DOS .EXE */
HEADR = 0x200;
if(INITTEXT == -1)
INITTEXT = 0x0100;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4;
HEADR += (INITTEXT & 0xFFFF);
if(debug['v'])
Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
break;
}
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%lux is ignored because of -R0x%lux\n",
INITDAT, INITRND);
if(debug['v'])
Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
for(i=1; optab[i].as; i++)
if(i != optab[i].as) {
diag("phase error in optab: %d", i);
errorexit();
}
maxop = i;
for(i=0; i<Ymax; i++)
ycover[i*Ymax + i] = 1;
ycover[Yi0*Ymax + Yi8] = 1;
ycover[Yi1*Ymax + Yi8] = 1;
ycover[Yi0*Ymax + Yi32] = 1;
ycover[Yi1*Ymax + Yi32] = 1;
ycover[Yi8*Ymax + Yi32] = 1;
ycover[Yal*Ymax + Yrb] = 1;
ycover[Ycl*Ymax + Yrb] = 1;
ycover[Yax*Ymax + Yrb] = 1;
ycover[Ycx*Ymax + Yrb] = 1;
ycover[Yrx*Ymax + Yrb] = 1;
ycover[Yax*Ymax + Yrx] = 1;
ycover[Ycx*Ymax + Yrx] = 1;
ycover[Yax*Ymax + Yrl] = 1;
ycover[Ycx*Ymax + Yrl] = 1;
ycover[Yrx*Ymax + Yrl] = 1;
ycover[Yf0*Ymax + Yrf] = 1;
ycover[Yal*Ymax + Ymb] = 1;
ycover[Ycl*Ymax + Ymb] = 1;
ycover[Yax*Ymax + Ymb] = 1;
ycover[Ycx*Ymax + Ymb] = 1;
ycover[Yrx*Ymax + Ymb] = 1;
ycover[Yrb*Ymax + Ymb] = 1;
ycover[Ym*Ymax + Ymb] = 1;
ycover[Yax*Ymax + Yml] = 1;
ycover[Ycx*Ymax + Yml] = 1;
ycover[Yrx*Ymax + Yml] = 1;
ycover[Yrl*Ymax + Yml] = 1;
ycover[Ym*Ymax + Yml] = 1;
for(i=0; i<D_NONE; i++) {
reg[i] = -1;
if(i >= D_AL && i <= D_BH)
reg[i] = (i-D_AL) & 7;
if(i >= D_AX && i <= D_DI)
reg[i] = (i-D_AX) & 7;
if(i >= D_F0 && i <= D_F0+7)
reg[i] = (i-D_F0) & 7;
}
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
zprg.as = AGOK;
zprg.from.type = D_NONE;
zprg.from.index = D_NONE;
zprg.from.scale = 1;
zprg.to = zprg.from;
pcstr = "%.6lux ";
nuxiinit();
histgen = 0;
textp = P;
datap = P;
edatap = P;
pc = 0;
dtype = 4;
cout = create(outfile, 1, 0775);
if(cout < 0) {
diag("cannot create %s", outfile);
errorexit();
}
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
firstp = prg();
lastp = firstp;
if(INITENTRY == 0) {
INITENTRY = "_main";
if(debug['p'])
INITENTRY = "_mainp";
if(!debug['l'])
lookup(INITENTRY, 0)->type = SXREF;
} else
lookup(INITENTRY, 0)->type = SXREF;
while(*argv)
objfile(*argv++);
if(!debug['l'])
loadlib();
firstp = firstp->link;
if(firstp == P)
errorexit();
if(doexp || dlm){
EXPTAB = "_exporttab";
zerosig(EXPTAB);
zerosig("etext");
zerosig("edata");
zerosig("end");
if(dlm){
import();
HEADTYPE = 2;
INITTEXT = INITDAT = 0;
INITRND = 8;
INITENTRY = EXPTAB;
}
export();
}
patch();
follow();
dodata();
dostkoff();
if(debug['p'])
if(debug['1'])
doprof1();
else
doprof2();
span();
doinit();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%ld symbols\n", nsymbol);
Bprint(&bso, "%ld memory used\n", thunk);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
Bflush(&bso);
errorexit();
}
void
loadlib(void)
{
int i;
long h;
Sym *s;
loop:
xrefresolv = 0;
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
objfile(library[i]);
}
if(xrefresolv)
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->type == SXREF)
goto loop;
}
void
errorexit(void)
{
if(nerrors) {
if(cout >= 0)
remove(outfile);
exits("error");
}
exits(0);
}
void
objfile(char *file)
{
long off, esym, cnt, l;
int f, work;
Sym *s;
char magbuf[SARMAG];
char name[100], pname[150];
struct ar_hdr arhdr;
char *e, *start, *stop;
if(file[0] == '-' && file[1] == 'l') {
if(debug['9'])
sprint(name, "/%s/lib/lib", thestring);
else
sprint(name, "/usr/%clib/lib", thechar);
strcat(name, file+2);
strcat(name, ".a");
file = name;
}
if(debug['v'])
Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
Bflush(&bso);
f = open(file, 0);
if(f < 0) {
diag("cannot open file: %s", file);
errorexit();
}
l = read(f, magbuf, SARMAG);
if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
/* load it as a regular file */
l = seek(f, 0L, 2);
seek(f, 0L, 0);
ldobj(f, l, file);
close(f);
return;
}
l = read(f, &arhdr, SAR_HDR);
if(l != SAR_HDR) {
diag("%s: short read on archive file symbol header", file);
goto out;
}
if(strncmp(arhdr.name, symname, strlen(symname))) {
diag("%s: first entry not symbol header", file);
goto out;
}
esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
off = SARMAG + SAR_HDR;
/*
* just bang the whole symbol file into memory
*/
seek(f, off, 0);
cnt = esym - off;
start = malloc(cnt + 10);
cnt = read(f, start, cnt);
if(cnt <= 0){
close(f);
return;
}
stop = &start[cnt];
memset(stop, 0, 10);
work = 1;
while(work) {
if(debug['v'])
Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
Bflush(&bso);
work = 0;
for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
s = lookup(e+5, 0);
if(s->type != SXREF)
continue;
sprint(pname, "%s(%s)", file, s->name);
if(debug['v'])
Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
Bflush(&bso);
l = e[1] & 0xff;
l |= (e[2] & 0xff) << 8;
l |= (e[3] & 0xff) << 16;
l |= (e[4] & 0xff) << 24;
seek(f, l, 0);
l = read(f, &arhdr, SAR_HDR);
if(l != SAR_HDR)
goto bad;
if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
goto bad;
l = atolwhex(arhdr.size);
ldobj(f, l, pname);
if(s->type == SXREF) {
diag("%s: failed to load: %s", file, s->name);
errorexit();
}
work = 1;
xrefresolv = 1;
}
}
return;
bad:
diag("%s: bad or out of date archive", file);
out:
close(f);
}
int
zaddr(uchar *p, Adr *a, Sym *h[])
{
int c, t, i;
long l;
Sym *s;
Auto *u;
t = p[0];
c = 1;
if(t & T_INDEX) {
a->index = p[c];
a->scale = p[c+1];
c += 2;
} else {
a->index = D_NONE;
a->scale = 0;
}
a->offset = 0;
if(t & T_OFFSET) {
a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
c += 4;
}
a->sym = S;
if(t & T_SYM) {
a->sym = h[p[c]];
c++;
}
a->type = D_NONE;
if(t & T_FCONST) {
a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
c += 8;
a->type = D_FCONST;
} else
if(t & T_SCONST) {
for(i=0; i<NSNAME; i++)
a->scon[i] = p[c+i];
c += NSNAME;
a->type = D_SCONST;
}
if(t & T_TYPE) {
a->type = p[c];
c++;
}
s = a->sym;
if(s == S)
return c;
t = a->type;
if(t != D_AUTO && t != D_PARAM)
return c;
l = a->offset;
for(u=curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
return c;
}
}
while(nhunk < sizeof(Auto))
gethunk();
u = (Auto*)hunk;
nhunk -= sizeof(Auto);
hunk += sizeof(Auto);
u->link = curauto;
curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
return c;
}
void
addlib(char *obj)
{
char name[1024], comp[256], *p;
int i;
if(histfrogp <= 0)
return;
if(histfrog[0]->name[1] == '/') {
sprint(name, "");
i = 1;
} else
if(histfrog[0]->name[1] == '.') {
sprint(name, ".");
i = 0;
} else {
if(debug['9'])
sprint(name, "/%s/lib", thestring);
else
sprint(name, "/usr/%clib", thechar);
i = 0;
}
for(; i<histfrogp; i++) {
snprint(comp, sizeof comp, histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
break;
memmove(p+1, p+2, strlen(p+2)+1);
p[0] = thechar;
}
for(;;) {
p = strstr(comp, "$M");
if(p == 0)
break;
if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
diag("library component too long");
return;
}
memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
memmove(p, thestring, strlen(thestring));
}
if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
diag("library component too long");
return;
}
strcat(name, "/");
strcat(name, comp);
}
for(i=0; i<libraryp; i++)
if(strcmp(name, library[i]) == 0)
return;
if(libraryp == nelem(library)){
diag("too many autolibs; skipping %s", name);
return;
}
p = malloc(strlen(name) + 1);
strcpy(p, name);
library[libraryp] = p;
p = malloc(strlen(obj) + 1);
strcpy(p, obj);
libraryobj[libraryp] = p;
libraryp++;
}
void
addhist(long line, int type)
{
Auto *u;
Sym *s;
int i, j, k;
u = malloc(sizeof(Auto));
s = malloc(sizeof(Sym));
s->name = malloc(2*(histfrogp+1) + 1);
u->asym = s;
u->type = type;
u->aoffset = line;
u->link = curhist;
curhist = u;
j = 1;
for(i=0; i<histfrogp; i++) {
k = histfrog[i]->value;
s->name[j+0] = k>>8;
s->name[j+1] = k;
j += 2;
}
}
void
histtoauto(void)
{
Auto *l;
while(l = curhist) {
curhist = l->link;
l->link = curauto;
curauto = l;
}
}
void
collapsefrog(Sym *s)
{
int i;
/*
* bad encoding of path components only allows
* MAXHIST components. if there is an overflow,
* first try to collapse xxx/..
*/
for(i=1; i<histfrogp; i++)
if(strcmp(histfrog[i]->name+1, "..") == 0) {
memmove(histfrog+i-1, histfrog+i+1,
(histfrogp-i-1)*sizeof(histfrog[0]));
histfrogp--;
goto out;
}
/*
* next try to collapse .
*/
for(i=0; i<histfrogp; i++)
if(strcmp(histfrog[i]->name+1, ".") == 0) {
memmove(histfrog+i, histfrog+i+1,
(histfrogp-i-1)*sizeof(histfrog[0]));
goto out;
}
/*
* last chance, just truncate from front
*/
memmove(histfrog+0, histfrog+1,
(histfrogp-1)*sizeof(histfrog[0]));
out:
histfrog[histfrogp-1] = s;
}
void
nopout(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
uchar*
readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
{
int n;
n = stop - good;
memmove(buf, good, stop - good);
stop = buf + n;
n = MAXIO - n;
if(n > max)
n = max;
n = read(f, stop, n);
if(n <= 0)
return 0;
return stop + n;
}
void
ldobj(int f, long c, char *pn)
{
long ipc;
Prog *p, *t;
uchar *bloc, *bsize, *stop;
int v, o, r, skip;
Sym *h[NSYM], *s, *di;
ulong sig;
static int files;
static char **filen;
char **nfilen;
if((files&15) == 0){
nfilen = malloc((files+16)*sizeof(char*));
memmove(nfilen, filen, files*sizeof(char*));
free(filen);
filen = nfilen;
}
filen[files++] = strdup(pn);
bsize = buf.xbuf;
bloc = buf.xbuf;
di = S;
newloop:
memset(h, 0, sizeof(h));
version++;
histfrogp = 0;
ipc = pc;
skip = 0;
loop:
if(c <= 0)
goto eof;
r = bsize - bloc;
if(r < 100 && r < c) { /* enough for largest prog */
bsize = readsome(f, buf.xbuf, bloc, bsize, c);
if(bsize == 0)
goto eof;
bloc = buf.xbuf;
goto loop;
}
o = bloc[0] | (bloc[1] << 8);
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
diag("%s: opcode out of range %d", pn, o);
print(" probably not a .8 file\n");
errorexit();
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME) {
sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
bloc += 4;
c -= 4;
}
stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
if(stop == 0){
bsize = readsome(f, buf.xbuf, bloc, bsize, c);
if(bsize == 0)
goto eof;
bloc = buf.xbuf;
stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
if(stop == 0){
fprint(2, "%s: name too long\n", pn);
errorexit();
}
}
v = bloc[2]; /* type */
o = bloc[3]; /* sym */
bloc += 4;
c -= 4;
r = 0;
if(v == D_STATIC)
r = version;
s = lookup((char*)bloc, r);
c -= &stop[1] - bloc;
bloc = stop + 1;
if(debug['S'] && r == 0)
sig = 1729;
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
s->sig = sig;
s->file = files-1;
}
if(debug['W'])
print(" ANAME %s\n", s->name);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
histgen++;
s->type = SFILE;
s->value = histgen;
}
if(histfrogp < MAXHIST) {
histfrog[histfrogp] = s;
histfrogp++;
} else
collapsefrog(s);
}
goto loop;
}
while(nhunk < sizeof(Prog))
gethunk();
p = (Prog*)hunk;
nhunk -= sizeof(Prog);
hunk += sizeof(Prog);
p->as = o;
p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
p->back = 2;
r = zaddr(bloc+6, &p->from, h) + 6;
r += zaddr(bloc+r, &p->to, h);
bloc += r;
c -= r;
if(debug['W'])
print("%P\n", p);
switch(p->as) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(pn);
histfrogp = 0;
goto loop;
}
addhist(p->line, D_FILE); /* 'z' */
if(p->to.offset)
addhist(p->to.offset, D_FILE1); /* 'Z' */
histfrogp = 0;
goto loop;
case AEND:
histtoauto();
if(curtext != P)
curtext->to.autom = curauto;
curauto = 0;
curtext = P;
if(c)
goto newloop;
return;
case AGLOBL:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->value = 0;
}
if(s->type != SBSS) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
s->value = 0;
}
if(p->to.offset > s->value)
s->value = p->to.offset;
goto loop;
case ADYNT:
if(p->to.sym == S) {
diag("DYNT without a sym\n%P", p);
break;
}
di = p->to.sym;
p->from.scale = 4;
if(di->type == SXREF) {
if(debug['z'])
Bprint(&bso, "%P set to %d\n", p, dtype);
di->type = SCONST;
di->value = dtype;
dtype += 4;
}
if(p->from.sym == S)
break;
p->from.offset = di->value;
p->from.sym->type = SDATA;
if(curtext == P) {
diag("DYNT not in text: %P", p);
break;
}
p->to.sym = curtext->from.sym;
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
goto data;
case AINIT:
if(p->from.sym == S) {
diag("INIT without a sym\n%P", p);
break;
}
if(di == S) {
diag("INIT without previous DYNT\n%P", p);
break;
}
p->from.offset = di->value;
p->from.sym->type = SDATA;
goto data;
case ADATA:
data:
if(edatap == P)
datap = p;
else
edatap->link = p;
edatap = p;
p->link = P;
goto loop;
case AGOK:
diag("%s: GOK opcode in %s", pn, TNAME);
pc++;
goto loop;
case ATEXT:
if(curtext != P) {
histtoauto();
curtext->to.autom = curauto;
curauto = 0;
}
skip = 0;
curtext = p;
s = p->from.sym;
if(s == S) {
diag("%s: no TEXT symbol: %P", pn, p);
errorexit();
}
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
s->type = STEXT;
s->value = pc;
lastp->link = p;
lastp = p;
p->pc = pc;
pc++;
if(textp == P) {
textp = p;
etextp = p;
goto loop;
}
etextp->pcond = p;
etextp = p;
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
s->value = 4;
t = prg();
t->as = ADATA;
t->line = p->line;
t->from.type = D_EXTERN;
t->from.sym = s;
t->from.scale = 4;
t->to = p->from;
if(edatap == P)
datap = t;
else
edatap->link = t;
edatap = t;
t->link = P;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
sprint(literal, "$%lux.%lux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
s->value = 8;
t = prg();
t->as = ADATA;
t->line = p->line;
t->from.type = D_EXTERN;
t->from.sym = s;
t->from.scale = 8;
t->to = p->from;
if(edatap == P)
datap = t;
else
edatap->link = t;
edatap = t;
t->link = P;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
if(skip)
nopout(p);
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
lastp->link = p;
lastp = p;
p->pc = pc;
pc++;
goto loop;
}
goto loop;
eof:
diag("truncated object file: %s", pn);
}
Sym*
lookup(char *symb, int v)
{
Sym *s;
char *p;
long h;
int l, c;
h = v;
for(p=symb; c = *p; p++)
h = h+h+h + c;
l = (p - symb) + 1;
if(h < 0)
h = ~h;
h %= NHASH;
for(s = hash[h]; s != S; s = s->link)
if(s->version == v)
if(memcmp(s->name, symb, l) == 0)
return s;
while(nhunk < sizeof(Sym))
gethunk();
s = (Sym*)hunk;
nhunk -= sizeof(Sym);
hunk += sizeof(Sym);
s->name = malloc(l + 1);
memmove(s->name, symb, l);
s->link = hash[h];
s->type = 0;
s->version = v;
s->value = 0;
s->sig = 0;
hash[h] = s;
nsymbol++;
return s;
}
Prog*
prg(void)
{
Prog *p;
while(nhunk < sizeof(Prog))
gethunk();
p = (Prog*)hunk;
nhunk -= sizeof(Prog);
hunk += sizeof(Prog);
*p = zprg;
return p;
}
Prog*
copyp(Prog *q)
{
Prog *p;
p = prg();
*p = *q;
return p;
}
Prog*
appendp(Prog *q)
{
Prog *p;
p = prg();
p->link = q->link;
q->link = p;
p->line = q->line;
return p;
}
void
gethunk(void)
{
char *h;
long nh;
nh = NHUNK;
if(thunk >= 5L*NHUNK) {
nh = 5L*NHUNK;
if(thunk >= 25L*NHUNK)
nh = 25L*NHUNK;
}
h = mysbrk(nh);
if(h == (char*)-1) {
diag("out of memory");
errorexit();
}
hunk = h;
nhunk = nh;
thunk += nh;
}
void
doprof1(void)
{
Sym *s;
long n;
Prog *p, *q;
if(debug['v'])
Bprint(&bso, "%5.2f profile 1\n", cputime());
Bflush(&bso);
s = lookup("__mcount", 0);
n = 1;
for(p = firstp->link; p != P; p = p->link) {
if(p->as == ATEXT) {
q = prg();
q->line = p->line;
q->link = datap;
datap = q;
q->as = ADATA;
q->from.type = D_EXTERN;
q->from.offset = n*4;
q->from.sym = s;
q->from.scale = 4;
q->to = p->from;
q->to.type = D_CONST;
q = prg();
q->line = p->line;
q->pc = p->pc;
q->link = p->link;
p->link = q;
p = q;
p->as = AADDL;
p->from.type = D_CONST;
p->from.offset = 1;
p->to.type = D_EXTERN;
p->to.sym = s;
p->to.offset = n*4 + 4;
n += 2;
continue;
}
}
q = prg();
q->line = 0;
q->link = datap;
datap = q;
q->as = ADATA;
q->from.type = D_EXTERN;
q->from.sym = s;
q->from.scale = 4;
q->to.type = D_CONST;
q->to.offset = n;
s->type = SBSS;
s->value = n*4;
}
void
doprof2(void)
{
Sym *s2, *s4;
Prog *p, *q, *ps2, *ps4;
if(debug['v'])
Bprint(&bso, "%5.2f profile 2\n", cputime());
Bflush(&bso);
s2 = lookup("_profin", 0);
s4 = lookup("_profout", 0);
if(s2->type != STEXT || s4->type != STEXT) {
diag("_profin/_profout not defined");
return;
}
ps2 = P;
ps4 = P;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
if(p->from.sym == s2) {
p->from.scale = 1;
ps2 = p;
}
if(p->from.sym == s4) {
p->from.scale = 1;
ps4 = p;
}
}
}
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
curtext = p;
if(p->from.scale & NOPROF) { /* dont profile */
for(;;) {
q = p->link;
if(q == P)
break;
if(q->as == ATEXT)
break;
p = q;
}
continue;
}
/*
* JMPL profin
*/
q = prg();
q->line = p->line;
q->pc = p->pc;
q->link = p->link;
p->link = q;
p = q;
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = ps2;
p->to.sym = s2;
continue;
}
if(p->as == ARET) {
/*
* RET
*/
q = prg();
q->as = ARET;
q->from = p->from;
q->to = p->to;
q->link = p->link;
p->link = q;
/*
* JAL profout
*/
p->as = ACALL;
p->from = zprg.from;
p->to = zprg.to;
p->to.type = D_BRANCH;
p->pcond = ps4;
p->to.sym = s4;
p = q;
continue;
}
}
}
void
nuxiinit(void)
{
int i, c;
for(i=0; i<4; i++) {
c = find1(0x04030201L, i+1);
if(i < 2)
inuxi2[i] = c;
if(i < 1)
inuxi1[i] = c;
inuxi4[i] = c;
fnuxi4[i] = c;
fnuxi8[i] = c;
fnuxi8[i+4] = c+4;
}
if(debug['v']) {
Bprint(&bso, "inuxi = ");
for(i=0; i<1; i++)
Bprint(&bso, "%d", inuxi1[i]);
Bprint(&bso, " ");
for(i=0; i<2; i++)
Bprint(&bso, "%d", inuxi2[i]);
Bprint(&bso, " ");
for(i=0; i<4; i++)
Bprint(&bso, "%d", inuxi4[i]);
Bprint(&bso, "\nfnuxi = ");
for(i=0; i<4; i++)
Bprint(&bso, "%d", fnuxi4[i]);
Bprint(&bso, " ");
for(i=0; i<8; i++)
Bprint(&bso, "%d", fnuxi8[i]);
Bprint(&bso, "\n");
}
Bflush(&bso);
}
int
find1(long l, int c)
{
char *p;
int i;
p = (char*)&l;
for(i=0; i<4; i++)
if(*p++ == c)
return i;
return 0;
}
int
find2(long l, int c)
{
short *p;
int i;
p = (short*)&l;
for(i=0; i<4; i+=2) {
if(((*p >> 8) & 0xff) == c)
return i;
if((*p++ & 0xff) == c)
return i+1;
}
return 0;
}
long
ieeedtof(Ieee *e)
{
int exp;
long v;
if(e->h == 0)
return 0;
exp = (e->h>>20) & ((1L<<11)-1L);
exp -= (1L<<10) - 2L;
v = (e->h & 0xfffffL) << 3;
v |= (e->l >> 29) & 0x7L;
if((e->l >> 28) & 1) {
v++;
if(v & 0x800000L) {
v = (v & 0x7fffffL) >> 1;
exp++;
}
}
if(exp <= -126 || exp >= 130)
diag("double fp to single fp overflow");
v |= ((exp + 126) & 0xffL) << 23;
v |= e->h & 0x80000000L;
return v;
}
double
ieeedtod(Ieee *ieeep)
{
Ieee e;
double fr;
int exp;
if(ieeep->h & (1L<<31)) {
e.h = ieeep->h & ~(1L<<31);
e.l = ieeep->l;
return -ieeedtod(&e);
}
if(ieeep->l == 0 && ieeep->h == 0)
return 0;
fr = ieeep->l & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (ieeep->l>>16) & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
fr /= 1L<<21;
exp = (ieeep->h>>20) & ((1L<<11)-1L);
exp -= (1L<<10) - 2L;
return ldexp(fr, exp);
}
void
undefsym(Sym *s)
{
int n;
n = imports;
if(s->value != 0)
diag("value != 0 on SXREF");
if(n >= 1<<Rindex)
diag("import index %d out of range", n);
s->value = n<<Roffset;
s->type = SUNDEF;
imports++;
}
void
zerosig(char *sp)
{
Sym *s;
s = lookup(sp, 0);
s->sig = 0;
}
void
readundefs(char *f, int t)
{
int i, n;
Sym *s;
Biobuf *b;
char *l, buf[256], *fields[64];
if(f == nil)
return;
b = Bopen(f, OREAD);
if(b == nil){
diag("could not open %s: %r", f);
errorexit();
}
while((l = Brdline(b, '\n')) != nil){
n = Blinelen(b);
if(n >= sizeof(buf)){
diag("%s: line too long", f);
errorexit();
}
memmove(buf, l, n);
buf[n-1] = '\0';
n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
if(n == nelem(fields)){
diag("%s: bad format", f);
errorexit();
}
for(i = 0; i < n; i++){
s = lookup(fields[i], 0);
s->type = SXREF;
s->subtype = t;
if(t == SIMPORT)
nimports++;
else
nexports++;
}
}
Bterm(b);
}
// Inferno utils/8l/optab.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.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 "l.h"
uchar ynone[] =
{
Ynone, Ynone, Zlit, 1,
0
};
uchar ytext[] =
{
Ymb, Yi32, Zpseudo,1,
0
};
uchar ynop[] =
{
Ynone, Ynone, Zpseudo,1,
Ynone, Yml, Zpseudo,1,
Ynone, Yrf, Zpseudo,1,
Yml, Ynone, Zpseudo,1,
Yrf, Ynone, Zpseudo,1,
0
};
uchar yxorb[] =
{
Yi32, Yal, Zib_, 1,
Yi32, Ymb, Zibo_m, 2,
Yrb, Ymb, Zr_m, 1,
Ymb, Yrb, Zm_r, 1,
0
};
uchar yxorl[] =
{
Yi8, Yml, Zibo_m, 2,
Yi32, Yax, Zil_, 1,
Yi32, Yml, Zilo_m, 2,
Yrl, Yml, Zr_m, 1,
Yml, Yrl, Zm_r, 1,
0
};
uchar yaddl[] =
{
Yi8, Yml, Zibo_m, 2,
Yi32, Yax, Zil_, 1,
Yi32, Yml, Zilo_m, 2,
Yrl, Yml, Zr_m, 1,
Yml, Yrl, Zm_r, 1,
0
};
uchar yincb[] =
{
Ynone, Ymb, Zo_m, 2,
0
};
uchar yincl[] =
{
Ynone, Yrl, Z_rp, 1,
Ynone, Yml, Zo_m, 2,
0
};
uchar ycmpb[] =
{
Yal, Yi32, Z_ib, 1,
Ymb, Yi32, Zm_ibo, 2,
Ymb, Yrb, Zm_r, 1,
Yrb, Ymb, Zr_m, 1,
0
};
uchar ycmpl[] =
{
Yml, Yi8, Zm_ibo, 2,
Yax, Yi32, Z_il, 1,
Yml, Yi32, Zm_ilo, 2,
Yml, Yrl, Zm_r, 1,
Yrl, Yml, Zr_m, 1,
0
};
uchar yshb[] =
{
Yi1, Ymb, Zo_m, 2,
Yi32, Ymb, Zibo_m, 2,
Ycx, Ymb, Zo_m, 2,
0
};
uchar yshl[] =
{
Yi1, Yml, Zo_m, 2,
Yi32, Yml, Zibo_m, 2,
Ycl, Yml, Zo_m, 2,
Ycx, Yml, Zo_m, 2,
0
};
uchar ytestb[] =
{
Yi32, Yal, Zib_, 1,
Yi32, Ymb, Zibo_m, 2,
Yrb, Ymb, Zr_m, 1,
Ymb, Yrb, Zm_r, 1,
0
};
uchar ytestl[] =
{
Yi32, Yax, Zil_, 1,
Yi32, Yml, Zilo_m, 2,
Yrl, Yml, Zr_m, 1,
Yml, Yrl, Zm_r, 1,
0
};
uchar ymovb[] =
{
Yrb, Ymb, Zr_m, 1,
Ymb, Yrb, Zm_r, 1,
Yi32, Yrb, Zib_rp, 1,
Yi32, Ymb, Zibo_m, 2,
0
};
uchar ymovl[] =
{
Yrl, Yml, Zr_m, 1,
Yml, Yrl, Zm_r, 1,
Yi0, Yrl, Zclr, 1+2,
// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
Yi32, Yrl, Zil_rp, 1,
Yi32, Yml, Zilo_m, 2,
Yiauto, Yrl, Zaut_r, 2,
0
};
uchar ym_rl[] =
{
Ym, Yrl, Zm_r, 1,
0
};
uchar yrl_m[] =
{
Yrl, Ym, Zr_m, 1,
0
};
uchar ymb_rl[] =
{
Ymb, Yrl, Zm_r, 1,
0
};
uchar yml_rl[] =
{
Yml, Yrl, Zm_r, 1,
0
};
uchar yrl_ml[] =
{
Yrl, Yml, Zr_m, 1,
0
};
uchar yml_mb[] =
{
Yrb, Ymb, Zr_m, 1,
Ymb, Yrb, Zm_r, 1,
0
};
uchar yml_ml[] =
{
Yrl, Yml, Zr_m, 1,
Yml, Yrl, Zm_r, 1,
0
};
uchar ydivl[] =
{
Yml, Ynone, Zm_o, 2,
0
};
uchar ydivb[] =
{
Ymb, Ynone, Zm_o, 2,
0
};
uchar yimul[] =
{
Yml, Ynone, Zm_o, 2,
Yi8, Yrl, Zib_rr, 1,
Yi32, Yrl, Zil_rr, 1,
0
};
uchar ybyte[] =
{
Yi32, Ynone, Zbyte, 1,
0
};
uchar yin[] =
{
Yi32, Ynone, Zib_, 1,
Ynone, Ynone, Zlit, 1,
0
};
uchar yint[] =
{
Yi32, Ynone, Zib_, 1,
0
};
uchar ypushl[] =
{
Yrl, Ynone, Zrp_, 1,
Ym, Ynone, Zm_o, 2,
Yi8, Ynone, Zib_, 1,
Yi32, Ynone, Zil_, 1,
0
};
uchar ypopl[] =
{
Ynone, Yrl, Z_rp, 1,
Ynone, Ym, Zo_m, 2,
0
};
uchar yscond[] =
{
Ynone, Ymb, Zo_m, 2,
0
};
uchar yjcond[] =
{
Ynone, Ybr, Zbr, 1,
0
};
uchar yloop[] =
{
Ynone, Ybr, Zloop, 1,
0
};
uchar ycall[] =
{
Ynone, Yml, Zo_m, 2,
Ynone, Ybr, Zcall, 1,
0
};
uchar yjmp[] =
{
Ynone, Yml, Zo_m, 2,
Ynone, Ybr, Zjmp, 1,
0
};
uchar yfmvd[] =
{
Ym, Yf0, Zm_o, 2,
Yf0, Ym, Zo_m, 2,
Yrf, Yf0, Zm_o, 2,
Yf0, Yrf, Zo_m, 2,
0
};
uchar yfmvdp[] =
{
Yf0, Ym, Zo_m, 2,
Yf0, Yrf, Zo_m, 2,
0
};
uchar yfmvf[] =
{
Ym, Yf0, Zm_o, 2,
Yf0, Ym, Zo_m, 2,
0
};
uchar yfmvx[] =
{
Ym, Yf0, Zm_o, 2,
0
};
uchar yfmvp[] =
{
Yf0, Ym, Zo_m, 2,
0
};
uchar yfadd[] =
{
Ym, Yf0, Zm_o, 2,
Yrf, Yf0, Zm_o, 2,
Yf0, Yrf, Zo_m, 2,
0
};
uchar yfaddp[] =
{
Yf0, Yrf, Zo_m, 2,
0
};
uchar yfxch[] =
{
Yf0, Yrf, Zo_m, 2,
Yrf, Yf0, Zm_o, 2,
0
};
uchar ycompp[] =
{
Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
0
};
uchar ystsw[] =
{
Ynone, Ym, Zo_m, 2,
Ynone, Yax, Zlit, 1,
0
};
uchar ystcw[] =
{
Ynone, Ym, Zo_m, 2,
Ym, Ynone, Zm_o, 2,
0
};
uchar ysvrs[] =
{
Ynone, Ym, Zo_m, 2,
Ym, Ynone, Zm_o, 2,
0
};
Optab optab[] =
/* as, ytab, andproto, opcode */
{
{ AXXX },
{ AAAA, ynone, Px, 0x37 },
{ AAAD, ynone, Px, 0xd5,0x0a },
{ AAAM, ynone, Px, 0xd4,0x0a },
{ AAAS, ynone, Px, 0x3f },
{ AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
{ AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
{ AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
{ AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
{ AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
{ AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
{ AADJSP },
{ AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
{ AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
{ AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
{ AARPL, yrl_ml, Px, 0x63 },
{ ABOUNDL, yrl_m, Px, 0x62 },
{ ABOUNDW, yrl_m, Pe, 0x62 },
{ ABSFL, yml_rl, Pm, 0xbc },
{ ABSFW, yml_rl, Pq, 0xbc },
{ ABSRL, yml_rl, Pm, 0xbd },
{ ABSRW, yml_rl, Pq, 0xbd },
{ ABTL, yml_rl, Pm, 0xa3 },
{ ABTW, yml_rl, Pq, 0xa3 },
{ ABTCL, yml_rl, Pm, 0xbb },
{ ABTCW, yml_rl, Pq, 0xbb },
{ ABTRL, yml_rl, Pm, 0xb3 },
{ ABTRW, yml_rl, Pq, 0xb3 },
{ ABTSL, yml_rl, Pm, 0xab },
{ ABTSW, yml_rl, Pq, 0xab },
{ ABYTE, ybyte, Px, 1 },
{ ACALL, ycall, Px, 0xff,(02),0xe8 },
{ ACLC, ynone, Px, 0xf8 },
{ ACLD, ynone, Px, 0xfc },
{ ACLI, ynone, Px, 0xfa },
{ ACLTS, ynone, Pm, 0x06 },
{ ACMC, ynone, Px, 0xf5 },
{ ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
{ ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
{ ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
{ ACMPSB, ynone, Pb, 0xa6 },
{ ACMPSL, ynone, Px, 0xa7 },
{ ACMPSW, ynone, Pe, 0xa7 },
{ ADAA, ynone, Px, 0x27 },
{ ADAS, ynone, Px, 0x2f },
{ ADATA },
{ ADECB, yincb, Pb, 0xfe,(01) },
{ ADECL, yincl, Px, 0x48,0xff,(01) },
{ ADECW, yincl, Pe, 0x48,0xff,(01) },
{ ADIVB, ydivb, Pb, 0xf6,(06) },
{ ADIVL, ydivl, Px, 0xf7,(06) },
{ ADIVW, ydivl, Pe, 0xf7,(06) },
{ AENTER }, /* botch */
{ AGLOBL },
{ AGOK },
{ AHISTORY },
{ AHLT, ynone, Px, 0xf4 },
{ AIDIVB, ydivb, Pb, 0xf6,(07) },
{ AIDIVL, ydivl, Px, 0xf7,(07) },
{ AIDIVW, ydivl, Pe, 0xf7,(07) },
{ AIMULB, ydivb, Pb, 0xf6,(05) },
{ AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
{ AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
{ AINB, yin, Pb, 0xe4,0xec },
{ AINL, yin, Px, 0xe5,0xed },
{ AINW, yin, Pe, 0xe5,0xed },
{ AINCB, yincb, Pb, 0xfe,(00) },
{ AINCL, yincl, Px, 0x40,0xff,(00) },
{ AINCW, yincl, Pe, 0x40,0xff,(00) },
{ AINSB, ynone, Pb, 0x6c },
{ AINSL, ynone, Px, 0x6d },
{ AINSW, ynone, Pe, 0x6d },
{ AINT, yint, Px, 0xcd },
{ AINTO, ynone, Px, 0xce },
{ AIRETL, ynone, Px, 0xcf },
{ AIRETW, ynone, Pe, 0xcf },
{ AJCC, yjcond, Px, 0x73,0x83,(00) },
{ AJCS, yjcond, Px, 0x72,0x82 },
{ AJCXZ, yloop, Px, 0xe3 },
{ AJEQ, yjcond, Px, 0x74,0x84 },
{ AJGE, yjcond, Px, 0x7d,0x8d },
{ AJGT, yjcond, Px, 0x7f,0x8f },
{ AJHI, yjcond, Px, 0x77,0x87 },
{ AJLE, yjcond, Px, 0x7e,0x8e },
{ AJLS, yjcond, Px, 0x76,0x86 },
{ AJLT, yjcond, Px, 0x7c,0x8c },
{ AJMI, yjcond, Px, 0x78,0x88 },
{ AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
{ AJNE, yjcond, Px, 0x75,0x85 },
{ AJOC, yjcond, Px, 0x71,0x81,(00) },
{ AJOS, yjcond, Px, 0x70,0x80,(00) },
{ AJPC, yjcond, Px, 0x7b,0x8b },
{ AJPL, yjcond, Px, 0x79,0x89 },
{ AJPS, yjcond, Px, 0x7a,0x8a },
{ ALAHF, ynone, Px, 0x9f },
{ ALARL, yml_rl, Pm, 0x02 },
{ ALARW, yml_rl, Pq, 0x02 },
{ ALEAL, ym_rl, Px, 0x8d },
{ ALEAW, ym_rl, Pe, 0x8d },
{ ALEAVEL, ynone, Px, 0xc9 },
{ ALEAVEW, ynone, Pe, 0xc9 },
{ ALOCK, ynone, Px, 0xf0 },
{ ALODSB, ynone, Pb, 0xac },
{ ALODSL, ynone, Px, 0xad },
{ ALODSW, ynone, Pe, 0xad },
{ ALONG, ybyte, Px, 4 },
{ ALOOP, yloop, Px, 0xe2 },
{ ALOOPEQ, yloop, Px, 0xe1 },
{ ALOOPNE, yloop, Px, 0xe0 },
{ ALSLL, yml_rl, Pm, 0x03 },
{ ALSLW, yml_rl, Pq, 0x03 },
{ AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
{ AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
{ AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
{ AMOVBLSX, ymb_rl, Pm, 0xbe },
{ AMOVBLZX, ymb_rl, Pm, 0xb6 },
{ AMOVBWSX, ymb_rl, Pq, 0xbe },
{ AMOVBWZX, ymb_rl, Pq, 0xb6 },
{ AMOVWLSX, yml_rl, Pm, 0xbf },
{ AMOVWLZX, yml_rl, Pm, 0xb7 },
{ AMOVSB, ynone, Pb, 0xa4 },
{ AMOVSL, ynone, Px, 0xa5 },
{ AMOVSW, ynone, Pe, 0xa5 },
{ AMULB, ydivb, Pb, 0xf6,(04) },
{ AMULL, ydivl, Px, 0xf7,(04) },
{ AMULW, ydivl, Pe, 0xf7,(04) },
{ ANAME },
{ ANEGB, yscond, Px, 0xf6,(03) },
{ ANEGL, yscond, Px, 0xf7,(03) },
{ ANEGW, yscond, Pe, 0xf7,(03) },
{ ANOP, ynop, Px,0,0 },
{ ANOTB, yscond, Px, 0xf6,(02) },
{ ANOTL, yscond, Px, 0xf7,(02) },
{ ANOTW, yscond, Pe, 0xf7,(02) },
{ AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
{ AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
{ AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
{ AOUTB, yin, Pb, 0xe6,0xee },
{ AOUTL, yin, Px, 0xe7,0xef },
{ AOUTW, yin, Pe, 0xe7,0xef },
{ AOUTSB, ynone, Pb, 0x6e },
{ AOUTSL, ynone, Px, 0x6f },
{ AOUTSW, ynone, Pe, 0x6f },
{ APOPAL, ynone, Px, 0x61 },
{ APOPAW, ynone, Pe, 0x61 },
{ APOPFL, ynone, Px, 0x9d },
{ APOPFW, ynone, Pe, 0x9d },
{ APOPL, ypopl, Px, 0x58,0x8f,(00) },
{ APOPW, ypopl, Pe, 0x58,0x8f,(00) },
{ APUSHAL, ynone, Px, 0x60 },
{ APUSHAW, ynone, Pe, 0x60 },
{ APUSHFL, ynone, Px, 0x9c },
{ APUSHFW, ynone, Pe, 0x9c },
{ APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
{ APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
{ ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
{ ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
{ ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
{ ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
{ ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
{ ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
{ AREP, ynone, Px, 0xf3 },
{ AREPN, ynone, Px, 0xf2 },
{ ARET, ynone, Px, 0xc3 },
{ AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
{ AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
{ AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
{ ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
{ ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
{ ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
{ ASAHF, ynone, Px, 0x9e },
{ ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
{ ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
{ ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
{ ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
{ ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
{ ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
{ ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
{ ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
{ ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
{ ASCASB, ynone, Pb, 0xae },
{ ASCASL, ynone, Px, 0xaf },
{ ASCASW, ynone, Pe, 0xaf },
{ ASETCC, yscond, Pm, 0x93,(00) },
{ ASETCS, yscond, Pm, 0x92,(00) },
{ ASETEQ, yscond, Pm, 0x94,(00) },
{ ASETGE, yscond, Pm, 0x9d,(00) },
{ ASETGT, yscond, Pm, 0x9f,(00) },
{ ASETHI, yscond, Pm, 0x97,(00) },
{ ASETLE, yscond, Pm, 0x9e,(00) },
{ ASETLS, yscond, Pm, 0x96,(00) },
{ ASETLT, yscond, Pm, 0x9c,(00) },
{ ASETMI, yscond, Pm, 0x98,(00) },
{ ASETNE, yscond, Pm, 0x95,(00) },
{ ASETOC, yscond, Pm, 0x91,(00) },
{ ASETOS, yscond, Pm, 0x90,(00) },
{ ASETPC, yscond, Pm, 0x96,(00) },
{ ASETPL, yscond, Pm, 0x99,(00) },
{ ASETPS, yscond, Pm, 0x9a,(00) },
{ ACDQ, ynone, Px, 0x99 },
{ ACWD, ynone, Pe, 0x99 },
{ ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
{ ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
{ ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
{ ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
{ ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
{ ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
{ ASTC, ynone, Px, 0xf9 },
{ ASTD, ynone, Px, 0xfd },
{ ASTI, ynone, Px, 0xfb },
{ ASTOSB, ynone, Pb, 0xaa },
{ ASTOSL, ynone, Px, 0xab },
{ ASTOSW, ynone, Pe, 0xab },
{ ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
{ ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
{ ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
{ ASYSCALL, ynone, Px, 0xcd,100 },
{ ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
{ ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
{ ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
{ ATEXT, ytext, Px },
{ AVERR, ydivl, Pm, 0x00,(04) },
{ AVERW, ydivl, Pm, 0x00,(05) },
{ AWAIT, ynone, Px, 0x9b },
{ AWORD, ybyte, Px, 2 },
{ AXCHGB, yml_mb, Pb, 0x86,0x86 },
{ AXCHGL, yml_ml, Px, 0x87,0x87 },
{ AXCHGW, yml_ml, Pe, 0x87,0x87 },
{ AXLAT, ynone, Px, 0xd7 },
{ AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
{ AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
{ AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
{ AFMOVB, yfmvx, Px, 0xdf,(04) },
{ AFMOVBP, yfmvp, Px, 0xdf,(06) },
{ AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
{ AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
{ AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
{ AFMOVFP, yfmvp, Px, 0xd9,(03) },
{ AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
{ AFMOVLP, yfmvp, Px, 0xdb,(03) },
{ AFMOVV, yfmvx, Px, 0xdf,(05) },
{ AFMOVVP, yfmvp, Px, 0xdf,(07) },
{ AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
{ AFMOVWP, yfmvp, Px, 0xdf,(03) },
{ AFMOVX, yfmvx, Px, 0xdb,(05) },
{ AFMOVXP, yfmvp, Px, 0xdb,(07) },
{ AFCOMB },
{ AFCOMBP },
{ AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
{ AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
{ AFCOMDPP, ycompp, Px, 0xde,(03) },
{ AFCOMF, yfmvx, Px, 0xd8,(02) },
{ AFCOMFP, yfmvx, Px, 0xd8,(03) },
{ AFCOML, yfmvx, Px, 0xda,(02) },
{ AFCOMLP, yfmvx, Px, 0xda,(03) },
{ AFCOMW, yfmvx, Px, 0xde,(02) },
{ AFCOMWP, yfmvx, Px, 0xde,(03) },
{ AFUCOM, ycompp, Px, 0xdd,(04) },
{ AFUCOMP, ycompp, Px, 0xdd,(05) },
{ AFUCOMPP, ycompp, Px, 0xda,(13) },
{ AFADDDP, yfaddp, Px, 0xde,(00) },
{ AFADDW, yfmvx, Px, 0xde,(00) },
{ AFADDL, yfmvx, Px, 0xda,(00) },
{ AFADDF, yfmvx, Px, 0xd8,(00) },
{ AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
{ AFMULDP, yfaddp, Px, 0xde,(01) },
{ AFMULW, yfmvx, Px, 0xde,(01) },
{ AFMULL, yfmvx, Px, 0xda,(01) },
{ AFMULF, yfmvx, Px, 0xd8,(01) },
{ AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
{ AFSUBDP, yfaddp, Px, 0xde,(05) },
{ AFSUBW, yfmvx, Px, 0xde,(04) },
{ AFSUBL, yfmvx, Px, 0xda,(04) },
{ AFSUBF, yfmvx, Px, 0xd8,(04) },
{ AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
{ AFSUBRDP, yfaddp, Px, 0xde,(04) },
{ AFSUBRW, yfmvx, Px, 0xde,(05) },
{ AFSUBRL, yfmvx, Px, 0xda,(05) },
{ AFSUBRF, yfmvx, Px, 0xd8,(05) },
{ AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
{ AFDIVDP, yfaddp, Px, 0xde,(07) },
{ AFDIVW, yfmvx, Px, 0xde,(06) },
{ AFDIVL, yfmvx, Px, 0xda,(06) },
{ AFDIVF, yfmvx, Px, 0xd8,(06) },
{ AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
{ AFDIVRDP, yfaddp, Px, 0xde,(06) },
{ AFDIVRW, yfmvx, Px, 0xde,(07) },
{ AFDIVRL, yfmvx, Px, 0xda,(07) },
{ AFDIVRF, yfmvx, Px, 0xd8,(07) },
{ AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
{ AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
{ AFFREE },
{ AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
{ AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
{ AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
{ AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
{ AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
{ AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
{ AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
{ AF2XM1, ynone, Px, 0xd9, 0xf0 },
{ AFABS, ynone, Px, 0xd9, 0xe1 },
{ AFCHS, ynone, Px, 0xd9, 0xe0 },
{ AFCLEX, ynone, Px, 0xdb, 0xe2 },
{ AFCOS, ynone, Px, 0xd9, 0xff },
{ AFDECSTP, ynone, Px, 0xd9, 0xf6 },
{ AFINCSTP, ynone, Px, 0xd9, 0xf7 },
{ AFINIT, ynone, Px, 0xdb, 0xe3 },
{ AFLD1, ynone, Px, 0xd9, 0xe8 },
{ AFLDL2E, ynone, Px, 0xd9, 0xea },
{ AFLDL2T, ynone, Px, 0xd9, 0xe9 },
{ AFLDLG2, ynone, Px, 0xd9, 0xec },
{ AFLDLN2, ynone, Px, 0xd9, 0xed },
{ AFLDPI, ynone, Px, 0xd9, 0xeb },
{ AFLDZ, ynone, Px, 0xd9, 0xee },
{ AFNOP, ynone, Px, 0xd9, 0xd0 },
{ AFPATAN, ynone, Px, 0xd9, 0xf3 },
{ AFPREM, ynone, Px, 0xd9, 0xf8 },
{ AFPREM1, ynone, Px, 0xd9, 0xf5 },
{ AFPTAN, ynone, Px, 0xd9, 0xf2 },
{ AFRNDINT, ynone, Px, 0xd9, 0xfc },
{ AFSCALE, ynone, Px, 0xd9, 0xfd },
{ AFSIN, ynone, Px, 0xd9, 0xfe },
{ AFSINCOS, ynone, Px, 0xd9, 0xfb },
{ AFSQRT, ynone, Px, 0xd9, 0xfa },
{ AFTST, ynone, Px, 0xd9, 0xe4 },
{ AFXAM, ynone, Px, 0xd9, 0xe5 },
{ AFXTRACT, ynone, Px, 0xd9, 0xf4 },
{ AFYL2X, ynone, Px, 0xd9, 0xf1 },
{ AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
{ AEND },
0
};
// Inferno utils/8l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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 "l.h"
void
dodata(void)
{
int i;
Sym *s;
Prog *p;
long t, u;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
for(p = datap; p != P; p = p->link) {
s = p->from.sym;
if(p->as == ADYNT || p->as == AINIT)
s->value = dtype;
if(s->type == SBSS)
s->type = SDATA;
if(s->type != SDATA)
diag("initialize non-data (%d): %s\n%P",
s->type, s->name, p);
t = p->from.offset + p->width;
if(t > s->value)
diag("initialize bounds (%ld): %s\n%P",
s->value, s->name, p);
}
/* allocate small guys */
datsize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA)
if(s->type != SBSS)
continue;
t = s->value;
if(t == 0) {
diag("%s: no size", s->name);
t = 1;
}
t = rnd(t, 4);;
s->value = t;
if(t > MINSIZ)
continue;
s->value = datsize;
datsize += t;
s->type = SDATA1;
}
/* allocate the rest of the data */
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA) {
if(s->type == SDATA1)
s->type = SDATA;
continue;
}
t = s->value;
s->value = datsize;
datsize += t;
}
if(debug['j']) {
/*
* pad data with bss that fits up to next
* 8k boundary, then push data to 8k
*/
u = rnd(datsize, 8192);
u -= datsize;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
if(t > u)
continue;
u -= t;
s->value = datsize;
s->type = SDATA;
datsize += t;
}
datsize += u;
}
/* now the bss */
bsssize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
s->value = bsssize + datsize;
bsssize += t;
}
xdefine("edata", SBSS, datsize);
xdefine("end", SBSS, bsssize + datsize);
}
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != AJMP)
return p;
p = p->pcond;
}
return P;
}
void
follow(void)
{
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
firstp = prg();
lastp = firstp;
xfol(textp);
lastp->link = P;
firstp = firstp->link;
}
void
xfol(Prog *p)
{
Prog *q;
int i;
enum as a;
loop:
if(p == P)
return;
if(p->as == ATEXT)
curtext = p;
if(p->as == AJMP)
if((q = p->pcond) != P) {
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/* copy up to 4 instructions to avoid branch */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == lastp)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case APUSHL:
case APUSHFL:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPW:
case APOPFW:
goto brk;
}
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
lastp->link = q;
lastp = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(q->link);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
p->mark = 1;
lastp->link = p;
lastp = p;
a = p->as;
if(a == AJMP || a == ARET || a == AIRETL)
return;
if(p->pcond != P)
if(a != ACALL) {
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
xfol(p->link);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
return;
}
p = q;
goto loop;
}
p = p->link;
goto loop;
}
int
relinv(int a)
{
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
return a;
}
void
doinit(void)
{
Sym *s;
Prog *p;
int x;
for(p = datap; p != P; p = p->link) {
x = p->to.type;
if(x != D_EXTERN && x != D_STATIC)
continue;
s = p->to.sym;
if(s->type == 0 || s->type == SXREF)
diag("undefined %s initializer of %s",
s->name, p->from.sym->name);
p->to.offset += s->value;
p->to.type = D_CONST;
if(s->type == SDATA || s->type == SBSS)
p->to.offset += INITDAT;
}
}
void
patch(void)
{
long c;
Prog *p, *q;
Sym *s;
long vexit;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->as == ACALL || p->as == ARET) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
switch(s->type) {
default:
diag("undefined: %s in %s", s->name, TNAME);
s->type = STEXT;
s->value = vexit;
break; /* or fall through to set offset? */
case STEXT:
p->to.offset = s->value;
break;
case SUNDEF:
p->pcond = UP;
p->to.offset = 0;
break;
}
p->to.type = D_BRANCH;
}
}
if(p->to.type != D_BRANCH || p->pcond == UP)
continue;
c = p->to.offset;
for(q = firstp; q != P;) {
if(q->forwd != P)
if(c >= q->forwd->pc) {
q = q->forwd;
continue;
}
if(c == q->pc)
break;
q = q->link;
}
if(q == P) {
diag("branch out of range in %s\n%P", TNAME, p);
p->to.type = D_NONE;
}
p->pcond = q;
}
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
p->mark = 0; /* initialization for follow */
if(p->pcond != P && p->pcond != UP) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}
#define LOG 5
void
mkfwd(void)
{
Prog *p;
int i;
long dwn[LOG], cnt[LOG];
Prog *lst[LOG];
for(i=0; i<LOG; i++) {
if(i == 0)
cnt[i] = 1; else
cnt[i] = LOG * cnt[i-1];
dwn[i] = 1;
lst[i] = P;
}
i = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
i--;
if(i < 0)
i = LOG-1;
p->forwd = P;
dwn[i]--;
if(dwn[i] <= 0) {
dwn[i] = cnt[i];
if(lst[i] != P)
lst[i]->forwd = p;
lst[i] = p;
}
}
}
Prog*
brloop(Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as != AJMP)
break;
c++;
if(c >= 5000)
return P;
}
return q;
}
void
dostkoff(void)
{
Prog *p, *q;
long autoffset, deltasp;
int a, f, curframe, curbecome, maxbecome;
curframe = 0;
curbecome = 0;
maxbecome = 0;
curtext = 0;
for(p = firstp; p != P; p = p->link) {
/* find out how much arg space is used in this TEXT */
if(p->to.type == (D_INDIR+D_SP))
if(p->to.offset > curframe)
curframe = p->to.offset;
switch(p->as) {
case ATEXT:
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
curframe = 0;
curbecome = 0;
curtext = p;
break;
case ARET:
/* special form of RET is BECOME */
if(p->from.type == D_CONST)
if(p->from.offset > curbecome)
curbecome = p->from.offset;
break;
}
}
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
if(debug['b'])
print("max become = %d\n", maxbecome);
xdefine("ALEFbecome", STEXT, maxbecome);
curtext = 0;
for(p = firstp; p != P; p = p->link) {
switch(p->as) {
case ATEXT:
curtext = p;
break;
case ACALL:
if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
f = maxbecome - curtext->from.sym->frame;
if(f <= 0)
break;
/* calling a become or calling a variable */
if(p->to.sym == S || p->to.sym->become) {
curtext->to.offset += f;
if(debug['b']) {
curp = p;
print("%D calling %D increase %d\n",
&curtext->from, &p->to, f);
}
}
}
break;
}
}
autoffset = 0;
deltasp = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
curtext = p;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
if(autoffset) {
p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = autoffset;
}
deltasp = autoffset;
}
a = p->from.type;
if(a == D_AUTO)
p->from.offset += deltasp;
if(a == D_PARAM)
p->from.offset += deltasp + 4;
a = p->to.type;
if(a == D_AUTO)
p->to.offset += deltasp;
if(a == D_PARAM)
p->to.offset += deltasp + 4;
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
continue;
case ARET:
break;
}
if(autoffset != deltasp)
diag("unbalanced PUSH/POP");
if(p->from.type == D_CONST)
goto become;
if(autoffset) {
q = p;
p = appendp(p);
p->as = ARET;
q->as = AADJSP;
q->from.type = D_CONST;
q->from.offset = -autoffset;
}
continue;
become:
q = p;
p = appendp(p);
p->as = AJMP;
p->to = q->to;
p->pcond = q->pcond;
q->as = AADJSP;
q->from = zprg.from;
q->from.type = D_CONST;
q->from.offset = -autoffset;
q->to = zprg.to;
continue;
}
}
long
atolwhex(char *s)
{
long n;
int f;
n = 0;
f = 0;
while(*s == ' ' || *s == '\t')
s++;
if(*s == '-' || *s == '+') {
if(*s++ == '-')
f = 1;
while(*s == ' ' || *s == '\t')
s++;
}
if(s[0]=='0' && s[1]){
if(s[1]=='x' || s[1]=='X'){
s += 2;
for(;;){
if(*s >= '0' && *s <= '9')
n = n*16 + *s++ - '0';
else if(*s >= 'a' && *s <= 'f')
n = n*16 + *s++ - 'a' + 10;
else if(*s >= 'A' && *s <= 'F')
n = n*16 + *s++ - 'A' + 10;
else
break;
}
} else
while(*s >= '0' && *s <= '7')
n = n*8 + *s++ - '0';
} else
while(*s >= '0' && *s <= '9')
n = n*10 + *s++ - '0';
if(f)
n = -n;
return n;
}
void
undef(void)
{
int i;
Sym *s;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
void
import(void)
{
int i;
Sym *s;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
if(s->value != 0)
diag("value != 0 on SXREF");
undefsym(s);
Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
if(debug['S'])
s->sig = 0;
}
}
void
ckoff(Sym *s, long v)
{
if(v < 0 || v >= 1<<Roffset)
diag("relocation offset %ld for %s out of range", v, s->name);
}
static Prog*
newdata(Sym *s, int o, int w, int t)
{
Prog *p;
p = prg();
if(edatap == P)
datap = p;
else
edatap->link = p;
edatap = p;
p->as = ADATA;
p->width = w;
p->from.scale = w;
p->from.type = t;
p->from.sym = s;
p->from.offset = o;
p->to.type = D_CONST;
return p;
}
void
export(void)
{
int i, j, n, off, nb, sv, ne;
Sym *s, *et, *str, **esyms;
Prog *p;
char buf[NSNAME], *t;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
n++;
esyms = malloc(n*sizeof(Sym*));
ne = n;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
esyms[n++] = s;
for(i = 0; i < ne-1; i++)
for(j = i+1; j < ne; j++)
if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
s = esyms[i];
esyms[i] = esyms[j];
esyms[j] = s;
}
nb = 0;
off = 0;
et = lookup(EXPTAB, 0);
if(et->type != 0 && et->type != SXREF)
diag("%s already defined", EXPTAB);
et->type = SDATA;
str = lookup(".string", 0);
if(str->type == 0)
str->type = SDATA;
sv = str->value;
for(i = 0; i < ne; i++){
s = esyms[i];
if(debug['S'])
s->sig = 0;
/* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
/* signature */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.offset = s->sig;
/* address */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
p->to.sym = s;
/* string */
t = s->name;
n = strlen(t)+1;
for(;;){
buf[nb++] = *t;
sv++;
if(nb >= NSNAME){
p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
p->to.type = D_SCONST;
memmove(p->to.scon, buf, NSNAME);
nb = 0;
}
if(*t++ == 0)
break;
}
/* name */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.type = D_ADDR;
p->to.index = D_STATIC;
p->to.sym = str;
p->to.offset = sv-n;
}
if(nb > 0){
p = newdata(str, sv-nb, nb, D_STATIC);
p->to.type = D_SCONST;
memmove(p->to.scon, buf, nb);
}
for(i = 0; i < 3; i++){
newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
}
et->value = off;
if(sv == 0)
sv = 1;
str->value = sv;
exports = ne;
free(esyms);
}
// Inferno utils/8l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.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 "l.h"
void
span(void)
{
Prog *p, *q;
long v, c, idat;
int m, n, again;
xdefine("etext", STEXT, 0L);
idat = INITDAT;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
n = 0;
if(p->to.type == D_BRANCH)
if(p->pcond == P)
p->pcond = p;
if((q = p->pcond) != P)
if(q->back != 2)
n = 1;
p->back = n;
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
p->from.offset = v;
p->as = AADDL;
if(v < 0) {
p->as = ASUBL;
v = -v;
p->from.offset = v;
}
if(v == 0)
p->as = ANOP;
}
}
n = 0;
start:
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
Bflush(&bso);
c = INITTEXT;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->to.type == D_BRANCH)
if(p->back)
p->pc = c;
asmins(p);
p->pc = c;
m = andptr-and;
p->mark = m;
c += m;
}
loop:
n++;
if(debug['v'])
Bprint(&bso, "%5.2f span %d\n", cputime(), n);
Bflush(&bso);
if(n > 50) {
print("span must be looping\n");
errorexit();
}
again = 0;
c = INITTEXT;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->to.type == D_BRANCH) {
if(p->back)
p->pc = c;
asmins(p);
m = andptr-and;
if(m != p->mark) {
p->mark = m;
again++;
}
}
p->pc = c;
c += p->mark;
}
if(again) {
textsize = c;
goto loop;
}
if(INITRND) {
INITDAT = rnd(c, INITRND);
if(INITDAT != idat) {
idat = INITDAT;
goto start;
}
}
xdefine("etext", STEXT, c);
if(debug['v'])
Bprint(&bso, "etext = %lux\n", c);
Bflush(&bso);
for(p = textp; p != P; p = p->pcond)
p->from.sym->value = p->pc;
textsize = c - INITTEXT;
}
void
xdefine(char *p, int t, long v)
{
Sym *s;
s = lookup(p, 0);
if(s->type == 0 || s->type == SXREF) {
s->type = t;
s->value = v;
}
if(s->type == STEXT && s->value == 0)
s->value = v;
}
void
putsymb(char *s, int t, long v, int ver)
{
int i, f;
if(t == 'f')
s++;
lput(v);
if(ver)
t += 'a' - 'A';
cput(t+0x80); /* 0x80 is variable length */
if(t == 'Z' || t == 'z') {
cput(s[0]);
for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
cput(s[i]);
cput(s[i+1]);
}
cput(0);
cput(0);
i++;
}
else {
for(i=0; s[i]; i++)
cput(s[i]);
cput(0);
}
symsize += 4 + 1 + i + 1;
if(debug['n']) {
if(t == 'z' || t == 'Z') {
Bprint(&bso, "%c %.8lux ", t, v);
for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
Bprint(&bso, "/%x", f);
}
Bprint(&bso, "\n");
return;
}
if(ver)
Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
else
Bprint(&bso, "%c %.8lux %s\n", t, v, s);
}
}
void
asmsym(void)
{
Prog *p;
Auto *a;
Sym *s;
int h;
s = lookup("etext", 0);
if(s->type == STEXT)
putsymb(s->name, 'T', s->value, s->version);
for(h=0; h<NHASH; h++)
for(s=hash[h]; s!=S; s=s->link)
switch(s->type) {
case SCONST:
putsymb(s->name, 'D', s->value, s->version);
continue;
case SDATA:
putsymb(s->name, 'D', s->value+INITDAT, s->version);
continue;
case SBSS:
putsymb(s->name, 'B', s->value+INITDAT, s->version);
continue;
case SFILE:
putsymb(s->name, 'f', s->value, s->version);
continue;
}
for(p=textp; p!=P; p=p->pcond) {
s = p->from.sym;
if(s->type != STEXT)
continue;
/* filenames first */
for(a=p->to.autom; a; a=a->link)
if(a->type == D_FILE)
putsymb(a->asym->name, 'z', a->aoffset, 0);
else
if(a->type == D_FILE1)
putsymb(a->asym->name, 'Z', a->aoffset, 0);
putsymb(s->name, 'T', s->value, s->version);
/* frame, auto and param after */
putsymb(".frame", 'm', p->to.offset+4, 0);
for(a=p->to.autom; a; a=a->link)
if(a->type == D_AUTO)
putsymb(a->asym->name, 'a', -a->aoffset, 0);
else
if(a->type == D_PARAM)
putsymb(a->asym->name, 'p', a->aoffset, 0);
}
if(debug['v'] || debug['n'])
Bprint(&bso, "symsize = %lud\n", symsize);
Bflush(&bso);
}
void
asmlc(void)
{
long oldpc, oldlc;
Prog *p;
long v, s;
oldpc = INITTEXT;
oldlc = 0;
for(p = firstp; p != P; p = p->link) {
if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
if(p->as == ATEXT)
curtext = p;
if(debug['L'])
Bprint(&bso, "%6lux %P\n",
p->pc, p);
continue;
}
if(debug['L'])
Bprint(&bso, "\t\t%6ld", lcsize);
v = (p->pc - oldpc) / MINLC;
while(v) {
s = 127;
if(v < 127)
s = v;
cput(s+128); /* 129-255 +pc */
if(debug['L'])
Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
v -= s;
lcsize++;
}
s = p->line - oldlc;
oldlc = p->line;
oldpc = p->pc + MINLC;
if(s > 64 || s < -64) {
cput(0); /* 0 vv +lc */
cput(s>>24);
cput(s>>16);
cput(s>>8);
cput(s);
if(debug['L']) {
if(s > 0)
Bprint(&bso, " lc+%ld(%d,%ld)\n",
s, 0, s);
else
Bprint(&bso, " lc%ld(%d,%ld)\n",
s, 0, s);
Bprint(&bso, "%6lux %P\n",
p->pc, p);
}
lcsize += 5;
continue;
}
if(s > 0) {
cput(0+s); /* 1-64 +lc */
if(debug['L']) {
Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
Bprint(&bso, "%6lux %P\n",
p->pc, p);
}
} else {
cput(64-s); /* 65-128 -lc */
if(debug['L']) {
Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
Bprint(&bso, "%6lux %P\n",
p->pc, p);
}
}
lcsize++;
}
while(lcsize & 1) {
s = 129;
cput(s);
lcsize++;
}
if(debug['v'] || debug['L'])
Bprint(&bso, "lcsize = %ld\n", lcsize);
Bflush(&bso);
}
int
oclass(Adr *a)
{
long v;
if(a->type >= D_INDIR || a->index != D_NONE) {
if(a->index != D_NONE && a->scale == 0) {
if(a->type == D_ADDR) {
switch(a->index) {
case D_EXTERN:
case D_STATIC:
return Yi32;
case D_AUTO:
case D_PARAM:
return Yiauto;
}
return Yxxx;
}
return Ycol;
}
return Ym;
}
switch(a->type)
{
case D_AL:
return Yal;
case D_AX:
return Yax;
case D_CL:
case D_DL:
case D_BL:
case D_AH:
case D_CH:
case D_DH:
case D_BH:
return Yrb;
case D_CX:
return Ycx;
case D_DX:
case D_BX:
return Yrx;
case D_SP:
case D_BP:
case D_SI:
case D_DI:
return Yrl;
case D_F0+0:
return Yf0;
case D_F0+1:
case D_F0+2:
case D_F0+3:
case D_F0+4:
case D_F0+5:
case D_F0+6:
case D_F0+7:
return Yrf;
case D_NONE:
return Ynone;
case D_CS: return Ycs;
case D_SS: return Yss;
case D_DS: return Yds;
case D_ES: return Yes;
case D_FS: return Yfs;
case D_GS: return Ygs;
case D_GDTR: return Ygdtr;
case D_IDTR: return Yidtr;
case D_LDTR: return Yldtr;
case D_MSW: return Ymsw;
case D_TASK: return Ytask;
case D_CR+0: return Ycr0;
case D_CR+1: return Ycr1;
case D_CR+2: return Ycr2;
case D_CR+3: return Ycr3;
case D_CR+4: return Ycr4;
case D_CR+5: return Ycr5;
case D_CR+6: return Ycr6;
case D_CR+7: return Ycr7;
case D_DR+0: return Ydr0;
case D_DR+1: return Ydr1;
case D_DR+2: return Ydr2;
case D_DR+3: return Ydr3;
case D_DR+4: return Ydr4;
case D_DR+5: return Ydr5;
case D_DR+6: return Ydr6;
case D_DR+7: return Ydr7;
case D_TR+0: return Ytr0;
case D_TR+1: return Ytr1;
case D_TR+2: return Ytr2;
case D_TR+3: return Ytr3;
case D_TR+4: return Ytr4;
case D_TR+5: return Ytr5;
case D_TR+6: return Ytr6;
case D_TR+7: return Ytr7;
case D_EXTERN:
case D_STATIC:
case D_AUTO:
case D_PARAM:
return Ym;
case D_CONST:
case D_ADDR:
if(a->sym == S) {
v = a->offset;
if(v == 0)
return Yi0;
if(v == 1)
return Yi1;
if(v >= -128 && v <= 127)
return Yi8;
}
return Yi32;
case D_BRANCH:
return Ybr;
}
return Yxxx;
}
void
asmidx(Adr *a, int base)
{
int i;
switch(a->index) {
default:
goto bad;
case D_NONE:
i = 4 << 3;
goto bas;
case D_AX:
case D_CX:
case D_DX:
case D_BX:
case D_BP:
case D_SI:
case D_DI:
i = reg[a->index] << 3;
break;
}
switch(a->scale) {
default:
goto bad;
case 1:
break;
case 2:
i |= (1<<6);
break;
case 4:
i |= (2<<6);
break;
case 8:
i |= (3<<6);
break;
}
bas:
switch(base) {
default:
goto bad;
case D_NONE: /* must be mod=00 */
i |= 5;
break;
case D_AX:
case D_CX:
case D_DX:
case D_BX:
case D_SP:
case D_BP:
case D_SI:
case D_DI:
i |= reg[base];
break;
}
*andptr++ = i;
return;
bad:
diag("asmidx: bad address %D", a);
*andptr++ = 0;
return;
}
static void
put4(long v)
{
if(dlm && curp != P && reloca != nil){
dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
reloca = nil;
}
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
andptr[3] = v>>24;
andptr += 4;
}
long
vaddr(Adr *a)
{
int t;
long v;
Sym *s;
t = a->type;
v = a->offset;
if(t == D_ADDR)
t = a->index;
switch(t) {
case D_STATIC:
case D_EXTERN:
s = a->sym;
if(s != nil) {
if(dlm && curp != P)
reloca = a;
switch(s->type) {
case SUNDEF:
ckoff(s, v);
case STEXT:
case SCONST:
v += s->value;
break;
default:
v += INITDAT + s->value;
}
}
}
return v;
}
void
asmand(Adr *a, int r)
{
long v;
int t;
Adr aa;
v = a->offset;
t = a->type;
if(a->index != D_NONE) {
if(t >= D_INDIR) {
t -= D_INDIR;
if(t == D_NONE) {
*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
asmidx(a, t);
put4(v);
return;
}
if(v == 0 && t != D_BP) {
*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
asmidx(a, t);
return;
}
if(v >= -128 && v < 128) {
*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
asmidx(a, t);
*andptr++ = v;
return;
}
*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
asmidx(a, t);
put4(v);
return;
}
switch(t) {
default:
goto bad;
case D_STATIC:
case D_EXTERN:
aa.type = D_NONE+D_INDIR;
break;
case D_AUTO:
case D_PARAM:
aa.type = D_SP+D_INDIR;
break;
}
aa.offset = vaddr(a);
aa.index = a->index;
aa.scale = a->scale;
asmand(&aa, r);
return;
}
if(t >= D_AL && t <= D_F0+7) {
if(v)
goto bad;
*andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
return;
}
if(t >= D_INDIR) {
t -= D_INDIR;
if(t == D_NONE) {
*andptr++ = (0 << 6) | (5 << 0) | (r << 3);
put4(v);
return;
}
if(t == D_SP) {
if(v == 0) {
*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
asmidx(a, D_SP);
return;
}
if(v >= -128 && v < 128) {
*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
asmidx(a, D_SP);
*andptr++ = v;
return;
}
*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
asmidx(a, D_SP);
put4(v);
return;
}
if(t >= D_AX && t <= D_DI) {
if(v == 0 && t != D_BP) {
*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
if(v >= -128 && v < 128) {
andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
andptr[1] = v;
andptr += 2;
return;
}
*andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
put4(v);
return;
}
goto bad;
}
switch(a->type) {
default:
goto bad;
case D_STATIC:
case D_EXTERN:
aa.type = D_NONE+D_INDIR;
break;
case D_AUTO:
case D_PARAM:
aa.type = D_SP+D_INDIR;
break;
}
aa.index = D_NONE;
aa.scale = 1;
aa.offset = vaddr(a);
asmand(&aa, r);
return;
bad:
diag("asmand: bad address %D", a);
return;
}
#define E 0xff
uchar ymovtab[] =
{
/* push */
APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
/* pop */
APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
APOPL, Ynone, Yes, 0, 0x07,E,0,0,
APOPL, Ynone, Yss, 0, 0x17,E,0,0,
APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
/* mov seg */
AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
/* mov cr */
AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
/* mov dr */
AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
/* mov tr */
AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
/* lgdt, sgdt, lidt, sidt */
AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
/* lldt, sldt */
AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
/* lmsw, smsw */
AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
/* ltr, str */
AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
/* load full pointer */
AMOVL, Yml, Ycol, 5, 0,0,0,0,
AMOVW, Yml, Ycol, 5, Pe,0,0,0,
/* double shift */
ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
/* extra imul */
AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
0
};
int
isax(Adr *a)
{
switch(a->type) {
case D_AX:
case D_AL:
case D_AH:
case D_INDIR+D_AX:
return 1;
}
if(a->index == D_AX)
return 1;
return 0;
}
void
subreg(Prog *p, int from, int to)
{
if(debug['Q'])
print("\n%P s/%R/%R/\n", p, from, to);
if(p->from.type == from)
p->from.type = to;
if(p->to.type == from)
p->to.type = to;
if(p->from.index == from)
p->from.index = to;
if(p->to.index == from)
p->to.index = to;
from += D_INDIR;
if(p->from.type == from)
p->from.type = to+D_INDIR;
if(p->to.type == from)
p->to.type = to+D_INDIR;
if(debug['Q'])
print("%P\n", p);
}
void
doasm(Prog *p)
{
Optab *o;
Prog *q, pp;
uchar *t;
int z, op, ft, tt;
long v;
o = &optab[p->as];
ft = oclass(&p->from) * Ymax;
tt = oclass(&p->to) * Ymax;
t = o->ytab;
if(t == 0) {
diag("asmins: noproto %P", p);
return;
}
for(z=0; *t; z+=t[3],t+=4)
if(ycover[ft+t[0]])
if(ycover[tt+t[1]])
goto found;
goto domov;
found:
switch(o->prefix) {
case Pq: /* 16 bit escape and opcode escape */
*andptr++ = Pe;
*andptr++ = Pm;
break;
case Pm: /* opcode escape */
*andptr++ = Pm;
break;
case Pe: /* 16 bit escape */
*andptr++ = Pe;
break;
case Pb: /* botch */
break;
}
v = vaddr(&p->from);
op = o->op[z];
switch(t[2]) {
default:
diag("asmins: unknown z %d %P", t[2], p);
return;
case Zpseudo:
break;
case Zlit:
for(; op = o->op[z]; z++)
*andptr++ = op;
break;
case Zm_r:
*andptr++ = op;
asmand(&p->from, reg[p->to.type]);
break;
case Zaut_r:
*andptr++ = 0x8d; /* leal */
if(p->from.type != D_ADDR)
diag("asmins: Zaut sb type ADDR");
p->from.type = p->from.index;
p->from.index = D_NONE;
asmand(&p->from, reg[p->to.type]);
p->from.index = p->from.type;
p->from.type = D_ADDR;
break;
case Zm_o:
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
break;
case Zr_m:
*andptr++ = op;
asmand(&p->to, reg[p->from.type]);
break;
case Zo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
break;
case Zm_ibo:
v = vaddr(&p->to);
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
*andptr++ = v;
break;
case Zibo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
*andptr++ = v;
break;
case Z_ib:
v = vaddr(&p->to);
case Zib_:
*andptr++ = op;
*andptr++ = v;
break;
case Zib_rp:
*andptr++ = op + reg[p->to.type];
*andptr++ = v;
break;
case Zil_rp:
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
*andptr++ = v;
*andptr++ = v>>8;
}
else
put4(v);
break;
case Zib_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
*andptr++ = v;
break;
case Z_il:
v = vaddr(&p->to);
case Zil_:
*andptr++ = op;
if(o->prefix == Pe) {
*andptr++ = v;
*andptr++ = v>>8;
}
else
put4(v);
break;
case Zm_ilo:
v = vaddr(&p->to);
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
*andptr++ = v;
*andptr++ = v>>8;
}
else
put4(v);
break;
case Zilo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
if(o->prefix == Pe) {
*andptr++ = v;
*andptr++ = v>>8;
}
else
put4(v);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
if(o->prefix == Pe) {
*andptr++ = v;
*andptr++ = v>>8;
}
else
put4(v);
break;
case Z_rp:
*andptr++ = op + reg[p->to.type];
break;
case Zrp_:
*andptr++ = op + reg[p->from.type];
break;
case Zclr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
break;
case Zbr:
q = p->pcond;
if(q) {
v = q->pc - p->pc - 2;
if(v >= -128 && v <= 127) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 6-2;
*andptr++ = 0x0f;
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
}
break;
case Zcall:
q = p->pcond;
if(q) {
v = q->pc - p->pc - 5;
if(dlm && curp != P && p->to.sym->type == SUNDEF){
/* v = 0 - p->pc - 5; */
v = 0;
ckoff(p->to.sym, v);
v += p->to.sym->value;
dynreloc(p->to.sym, p->pc+1, 0);
}
*andptr++ = op;
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
break;
case Zjmp:
q = p->pcond;
if(q) {
v = q->pc - p->pc - 2;
if(v >= -128 && v <= 127) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 5-2;
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
}
break;
case Zloop:
q = p->pcond;
if(q) {
v = q->pc - p->pc - 2;
if(v < -128 && v > 127)
diag("loop too far: %P", p);
*andptr++ = op;
*andptr++ = v;
}
break;
case Zbyte:
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
if(op > 2) {
*andptr++ = v>>16;
*andptr++ = v>>24;
}
}
break;
case Zmov:
goto domov;
}
return;
domov:
for(t=ymovtab; *t; t+=8)
if(p->as == t[0])
if(ycover[ft+t[1]])
if(ycover[tt+t[2]])
goto mfound;
bad:
/*
* here, the assembly has failed.
* if its a byte instruction that has
* unaddressable registers, try to
* exchange registers and reissue the
* instruction with the operands renamed.
*/
pp = *p;
z = p->from.type;
if(z >= D_BP && z <= D_DI) {
if(isax(&p->to)) {
*andptr++ = 0x87; /* xchg lhs,bx */
asmand(&p->from, reg[D_BX]);
subreg(&pp, z, D_BX);
doasm(&pp);
*andptr++ = 0x87; /* xchg lhs,bx */
asmand(&p->from, reg[D_BX]);
} else {
*andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
subreg(&pp, z, D_AX);
doasm(&pp);
*andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
}
return;
}
z = p->to.type;
if(z >= D_BP && z <= D_DI) {
if(isax(&p->from)) {
*andptr++ = 0x87; /* xchg rhs,bx */
asmand(&p->to, reg[D_BX]);
subreg(&pp, z, D_BX);
doasm(&pp);
*andptr++ = 0x87; /* xchg rhs,bx */
asmand(&p->to, reg[D_BX]);
} else {
*andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
subreg(&pp, z, D_AX);
doasm(&pp);
*andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
}
return;
}
diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
return;
mfound:
switch(t[3]) {
default:
diag("asmins: unknown mov %d %P", t[3], p);
break;
case 0: /* lit */
for(z=4; t[z]!=E; z++)
*andptr++ = t[z];
break;
case 1: /* r,m */
*andptr++ = t[4];
asmand(&p->to, t[5]);
break;
case 2: /* m,r */
*andptr++ = t[4];
asmand(&p->from, t[5]);
break;
case 3: /* r,m - 2op */
*andptr++ = t[4];
*andptr++ = t[5];
asmand(&p->to, t[6]);
break;
case 4: /* m,r - 2op */
*andptr++ = t[4];
*andptr++ = t[5];
asmand(&p->from, t[6]);
break;
case 5: /* load full pointer, trash heap */
if(t[4])
*andptr++ = t[4];
switch(p->to.index) {
default:
goto bad;
case D_DS:
*andptr++ = 0xc5;
break;
case D_SS:
*andptr++ = 0x0f;
*andptr++ = 0xb2;
break;
case D_ES:
*andptr++ = 0xc4;
break;
case D_FS:
*andptr++ = 0x0f;
*andptr++ = 0xb4;
break;
case D_GS:
*andptr++ = 0x0f;
*andptr++ = 0xb5;
break;
}
asmand(&p->from, reg[p->to.type]);
break;
case 6: /* double shift */
z = p->from.type;
switch(z) {
default:
goto bad;
case D_CONST:
*andptr++ = 0x0f;
*andptr++ = t[4];
asmand(&p->to, reg[p->from.index]);
*andptr++ = p->from.offset;
break;
case D_CL:
case D_CX:
*andptr++ = 0x0f;
*andptr++ = t[5];
asmand(&p->to, reg[p->from.index]);
break;
}
break;
case 7: /* imul rm,r */
*andptr++ = t[4];
*andptr++ = t[5];
asmand(&p->from, reg[p->to.type]);
break;
}
}
void
asmins(Prog *p)
{
andptr = and;
doasm(p);
}
enum{
ABSD = 0,
ABSU = 1,
RELD = 2,
RELU = 3,
};
int modemap[4] = { 0, 1, -1, 2, };
typedef struct Reloc Reloc;
struct Reloc
{
int n;
int t;
uchar *m;
ulong *a;
};
Reloc rels;
static void
grow(Reloc *r)
{
int t;
uchar *m, *nm;
ulong *a, *na;
t = r->t;
r->t += 64;
m = r->m;
a = r->a;
r->m = nm = malloc(r->t*sizeof(uchar));
r->a = na = malloc(r->t*sizeof(ulong));
memmove(nm, m, t*sizeof(uchar));
memmove(na, a, t*sizeof(ulong));
free(m);
free(a);
}
void
dynreloc(Sym *s, ulong v, int abs)
{
int i, k, n;
uchar *m;
ulong *a;
Reloc *r;
if(s->type == SUNDEF)
k = abs ? ABSU : RELU;
else
k = abs ? ABSD : RELD;
/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
k = modemap[k];
r = &rels;
n = r->n;
if(n >= r->t)
grow(r);
m = r->m;
a = r->a;
for(i = n; i > 0; i--){
if(v < a[i-1]){ /* happens occasionally for data */
m[i] = m[i-1];
a[i] = a[i-1];
}
else
break;
}
m[i] = k;
a[i] = v;
r->n++;
}
static int
sput(char *s)
{
char *p;
p = s;
while(*s)
cput(*s++);
cput(0);
return s-p+1;
}
void
asmdyn()
{
int i, n, t, c;
Sym *s;
ulong la, ra, *a;
vlong off;
uchar *m;
Reloc *r;
cflush();
off = seek(cout, 0, 1);
lput(0);
t = 0;
lput(imports);
t += 4;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SUNDEF){
lput(s->sig);
t += 4;
t += sput(s->name);
}
la = 0;
r = &rels;
n = r->n;
m = r->m;
a = r->a;
lput(n);
t += 4;
for(i = 0; i < n; i++){
ra = *a-la;
if(*a < la)
diag("bad relocation order");
if(ra < 256)
c = 0;
else if(ra < 65536)
c = 1;
else
c = 2;
cput((c<<6)|*m++);
t++;
if(c == 0){
cput(ra);
t++;
}
else if(c == 1){
wputb(ra);
t += 2;
}
else{
lput(ra);
t += 4;
}
la = *a++;
}
cflush();
seek(cout, off, 0);
lput(t);
if(debug['v']){
Bprint(&bso, "import table entries = %d\n", imports);
Bprint(&bso, "export table entries = %d\n", exports);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment